diff options
Diffstat (limited to 'dom/xslt/xpath/XPathEvaluator.cpp')
-rw-r--r-- | dom/xslt/xpath/XPathEvaluator.cpp | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/dom/xslt/xpath/XPathEvaluator.cpp b/dom/xslt/xpath/XPathEvaluator.cpp new file mode 100644 index 0000000000..269ea98ff6 --- /dev/null +++ b/dom/xslt/xpath/XPathEvaluator.cpp @@ -0,0 +1,187 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/XPathEvaluator.h" + +#include <utility> + +#include "XPathResult.h" +#include "mozilla/UniquePtrExtensions.h" +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/Document.h" +#include "mozilla/dom/XPathEvaluatorBinding.h" +#include "mozilla/dom/XPathExpression.h" +#include "mozilla/dom/XPathNSResolverBinding.h" +#include "nsAtom.h" +#include "nsCOMPtr.h" +#include "nsContentCID.h" +#include "nsContentUtils.h" +#include "nsDOMString.h" +#include "nsError.h" +#include "nsNameSpaceManager.h" +#include "txExpr.h" +#include "txExprParser.h" +#include "txIXPathContext.h" +#include "txURIUtils.h" + +namespace mozilla::dom { + +// txIParseContext implementation +class XPathEvaluatorParseContext : public txIParseContext { + public: + XPathEvaluatorParseContext(XPathNSResolver* aResolver, bool aIsCaseSensitive) + : mResolver(aResolver), + mResolverNode(nullptr), + mLastError(NS_OK), + mIsCaseSensitive(aIsCaseSensitive) {} + XPathEvaluatorParseContext(nsINode* aResolver, bool aIsCaseSensitive) + : mResolver(nullptr), + mResolverNode(aResolver), + mLastError(NS_OK), + mIsCaseSensitive(aIsCaseSensitive) {} + + nsresult getError() { return mLastError; } + + nsresult resolveNamespacePrefix(nsAtom* aPrefix, int32_t& aID) override; + nsresult resolveFunctionCall(nsAtom* aName, int32_t aID, + FunctionCall** aFunction) override; + bool caseInsensitiveNameTests() override; + void SetErrorOffset(uint32_t aOffset) override; + + private: + XPathNSResolver* mResolver; + nsINode* mResolverNode; + nsresult mLastError; + bool mIsCaseSensitive; +}; + +XPathEvaluator::XPathEvaluator(Document* aDocument) : mDocument(aDocument) {} + +XPathEvaluator::~XPathEvaluator() = default; + +UniquePtr<XPathExpression> XPathEvaluator::CreateExpression( + const nsAString& aExpression, XPathNSResolver* aResolver, + ErrorResult& aRv) { + nsCOMPtr<Document> doc(mDocument); + XPathEvaluatorParseContext pContext(aResolver, + !(doc && doc->IsHTMLDocument())); + return CreateExpression(aExpression, &pContext, doc, aRv); +} + +UniquePtr<XPathExpression> XPathEvaluator::CreateExpression( + const nsAString& aExpression, nsINode* aResolver, ErrorResult& aRv) { + nsCOMPtr<Document> doc(mDocument); + XPathEvaluatorParseContext pContext(aResolver, + !(doc && doc->IsHTMLDocument())); + return CreateExpression(aExpression, &pContext, doc, aRv); +} + +UniquePtr<XPathExpression> XPathEvaluator::CreateExpression( + const nsAString& aExpression, txIParseContext* aContext, + Document* aDocument, ErrorResult& aRv) { + if (!mRecycler) { + mRecycler = new txResultRecycler; + } + + UniquePtr<Expr> expression; + aRv = txExprParser::createExpr(PromiseFlatString(aExpression), aContext, + getter_Transfers(expression)); + if (aRv.Failed()) { + if (!aRv.ErrorCodeIs(NS_ERROR_DOM_NAMESPACE_ERR)) { + aRv.SuppressException(); + aRv.ThrowSyntaxError("The expression is not a legal expression"); + } + + return nullptr; + } + + return MakeUnique<XPathExpression>(std::move(expression), mRecycler, + aDocument); +} + +bool XPathEvaluator::WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto, + JS::MutableHandle<JSObject*> aReflector) { + return dom::XPathEvaluator_Binding::Wrap(aCx, this, aGivenProto, aReflector); +} + +/* static */ +UniquePtr<XPathEvaluator> XPathEvaluator::Constructor( + const GlobalObject& aGlobal) { + return MakeUnique<XPathEvaluator>(nullptr); +} + +already_AddRefed<XPathResult> XPathEvaluator::Evaluate( + JSContext* aCx, const nsAString& aExpression, nsINode& aContextNode, + XPathNSResolver* aResolver, uint16_t aType, JS::Handle<JSObject*> aResult, + ErrorResult& rv) { + UniquePtr<XPathExpression> expression( + CreateExpression(aExpression, aResolver, rv)); + if (rv.Failed()) { + return nullptr; + } + return expression->Evaluate(aCx, aContextNode, aType, aResult, rv); +} + +/* + * Implementation of txIParseContext private to XPathEvaluator, based on a + * XPathNSResolver + */ + +nsresult XPathEvaluatorParseContext::resolveNamespacePrefix(nsAtom* aPrefix, + int32_t& aID) { + aID = kNameSpaceID_Unknown; + + if (!mResolver && !mResolverNode) { + return NS_ERROR_DOM_NAMESPACE_ERR; + } + + nsAutoString prefix; + if (aPrefix) { + aPrefix->ToString(prefix); + } + + nsAutoString ns; + if (mResolver) { + ErrorResult rv; + mResolver->LookupNamespaceURI(prefix, ns, rv); + if (rv.Failed()) { + return rv.StealNSResult(); + } + } else { + if (aPrefix == nsGkAtoms::xml) { + ns.AssignLiteral("http://www.w3.org/XML/1998/namespace"); + } else { + mResolverNode->LookupNamespaceURI(prefix, ns); + } + } + + if (DOMStringIsNull(ns)) { + return NS_ERROR_DOM_NAMESPACE_ERR; + } + + if (ns.IsEmpty()) { + aID = kNameSpaceID_None; + + return NS_OK; + } + + // get the namespaceID for the URI + return nsNameSpaceManager::GetInstance()->RegisterNameSpace(ns, aID); +} + +nsresult XPathEvaluatorParseContext::resolveFunctionCall(nsAtom* aName, + int32_t aID, + FunctionCall** aFn) { + return NS_ERROR_XPATH_UNKNOWN_FUNCTION; +} + +bool XPathEvaluatorParseContext::caseInsensitiveNameTests() { + return !mIsCaseSensitive; +} + +void XPathEvaluatorParseContext::SetErrorOffset(uint32_t aOffset) {} + +} // namespace mozilla::dom |