XPathEvaluator.cpp (5792B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "mozilla/dom/XPathEvaluator.h" 7 8 #include <utility> 9 10 #include "XPathResult.h" 11 #include "mozilla/dom/BindingUtils.h" 12 #include "mozilla/dom/Document.h" 13 #include "mozilla/dom/XPathEvaluatorBinding.h" 14 #include "mozilla/dom/XPathExpression.h" 15 #include "mozilla/dom/XPathNSResolverBinding.h" 16 #include "nsAtom.h" 17 #include "nsCOMPtr.h" 18 #include "nsContentUtils.h" 19 #include "nsDOMString.h" 20 #include "nsError.h" 21 #include "nsNameSpaceManager.h" 22 #include "txExpr.h" 23 #include "txExprParser.h" 24 #include "txIXPathContext.h" 25 #include "txURIUtils.h" 26 27 namespace mozilla::dom { 28 29 // txIParseContext implementation 30 class XPathEvaluatorParseContext : public txIParseContext { 31 public: 32 XPathEvaluatorParseContext(XPathNSResolver* aResolver, bool aIsCaseSensitive) 33 : mResolver(aResolver), 34 mResolverNode(nullptr), 35 mLastError(NS_OK), 36 mIsCaseSensitive(aIsCaseSensitive) {} 37 XPathEvaluatorParseContext(nsINode* aResolver, bool aIsCaseSensitive) 38 : mResolver(nullptr), 39 mResolverNode(aResolver), 40 mLastError(NS_OK), 41 mIsCaseSensitive(aIsCaseSensitive) {} 42 43 nsresult getError() { return mLastError; } 44 45 int32_t resolveNamespacePrefix(nsAtom* aPrefix) override; 46 nsresult resolveFunctionCall(nsAtom* aName, int32_t aID, 47 FunctionCall** aFunction) override; 48 bool caseInsensitiveNameTests() override; 49 void SetErrorOffset(uint32_t aOffset) override; 50 51 private: 52 XPathNSResolver* mResolver; 53 nsINode* mResolverNode; 54 nsresult mLastError; 55 bool mIsCaseSensitive; 56 }; 57 58 XPathEvaluator::XPathEvaluator(Document* aDocument) : mDocument(aDocument) {} 59 60 XPathEvaluator::~XPathEvaluator() = default; 61 62 UniquePtr<XPathExpression> XPathEvaluator::CreateExpression( 63 const nsAString& aExpression, XPathNSResolver* aResolver, 64 ErrorResult& aRv) { 65 nsCOMPtr<Document> doc(mDocument); 66 XPathEvaluatorParseContext pContext(aResolver, 67 !(doc && doc->IsHTMLDocument())); 68 return CreateExpression(aExpression, &pContext, doc, aRv); 69 } 70 71 UniquePtr<XPathExpression> XPathEvaluator::CreateExpression( 72 const nsAString& aExpression, nsINode* aResolver, ErrorResult& aRv) { 73 nsCOMPtr<Document> doc(mDocument); 74 XPathEvaluatorParseContext pContext(aResolver, 75 !(doc && doc->IsHTMLDocument())); 76 return CreateExpression(aExpression, &pContext, doc, aRv); 77 } 78 79 UniquePtr<XPathExpression> XPathEvaluator::CreateExpression( 80 const nsAString& aExpression, txIParseContext* aContext, 81 Document* aDocument, ErrorResult& aRv) { 82 if (!mRecycler) { 83 mRecycler = new txResultRecycler; 84 } 85 86 UniquePtr<Expr> expression; 87 aRv = txExprParser::createExpr(PromiseFlatString(aExpression), aContext, 88 getter_Transfers(expression)); 89 if (aRv.Failed()) { 90 if (!aRv.ErrorCodeIs(NS_ERROR_DOM_NAMESPACE_ERR)) { 91 aRv.SuppressException(); 92 aRv.ThrowSyntaxError("The expression is not a legal expression"); 93 } 94 95 return nullptr; 96 } 97 98 return MakeUnique<XPathExpression>(std::move(expression), mRecycler, 99 aDocument); 100 } 101 102 bool XPathEvaluator::WrapObject(JSContext* aCx, 103 JS::Handle<JSObject*> aGivenProto, 104 JS::MutableHandle<JSObject*> aReflector) { 105 return dom::XPathEvaluator_Binding::Wrap(aCx, this, aGivenProto, aReflector); 106 } 107 108 /* static */ 109 UniquePtr<XPathEvaluator> XPathEvaluator::Constructor( 110 const GlobalObject& aGlobal) { 111 return MakeUnique<XPathEvaluator>(nullptr); 112 } 113 114 already_AddRefed<XPathResult> XPathEvaluator::Evaluate( 115 JSContext* aCx, const nsAString& aExpression, nsINode& aContextNode, 116 XPathNSResolver* aResolver, uint16_t aType, JS::Handle<JSObject*> aResult, 117 ErrorResult& rv) { 118 UniquePtr<XPathExpression> expression( 119 CreateExpression(aExpression, aResolver, rv)); 120 if (rv.Failed()) { 121 return nullptr; 122 } 123 return expression->Evaluate(aCx, aContextNode, aType, aResult, rv); 124 } 125 126 /* 127 * Implementation of txIParseContext private to XPathEvaluator, based on a 128 * XPathNSResolver 129 */ 130 131 int32_t XPathEvaluatorParseContext::resolveNamespacePrefix(nsAtom* aPrefix) { 132 if (!mResolver && !mResolverNode) { 133 return kNameSpaceID_Unknown; 134 } 135 136 nsAutoString prefix; 137 if (aPrefix) { 138 aPrefix->ToString(prefix); 139 } 140 141 nsAutoString ns; 142 if (mResolver) { 143 ErrorResult rv; 144 mResolver->LookupNamespaceURI(prefix, ns, rv); 145 if (rv.Failed()) { 146 rv.SuppressException(); 147 return kNameSpaceID_Unknown; 148 } 149 } else { 150 if (aPrefix == nsGkAtoms::xml) { 151 ns.AssignLiteral("http://www.w3.org/XML/1998/namespace"); 152 } else { 153 mResolverNode->LookupNamespaceURI(prefix, ns); 154 } 155 } 156 157 if (DOMStringIsNull(ns)) { 158 return kNameSpaceID_Unknown; 159 } 160 161 if (ns.IsEmpty()) { 162 return kNameSpaceID_None; 163 } 164 165 // get the namespaceID for the URI 166 int32_t id; 167 return NS_SUCCEEDED( 168 nsNameSpaceManager::GetInstance()->RegisterNameSpace(ns, id)) 169 ? id 170 : kNameSpaceID_Unknown; 171 } 172 173 nsresult XPathEvaluatorParseContext::resolveFunctionCall(nsAtom* aName, 174 int32_t aID, 175 FunctionCall** aFn) { 176 return NS_ERROR_XPATH_UNKNOWN_FUNCTION; 177 } 178 179 bool XPathEvaluatorParseContext::caseInsensitiveNameTests() { 180 return !mIsCaseSensitive; 181 } 182 183 void XPathEvaluatorParseContext::SetErrorOffset(uint32_t aOffset) {} 184 185 } // namespace mozilla::dom