diff options
Diffstat (limited to 'dom/xslt/xslt/txInstructions.cpp')
-rw-r--r-- | dom/xslt/xslt/txInstructions.cpp | 764 |
1 files changed, 764 insertions, 0 deletions
diff --git a/dom/xslt/xslt/txInstructions.cpp b/dom/xslt/xslt/txInstructions.cpp new file mode 100644 index 0000000000..df6e1ffeb0 --- /dev/null +++ b/dom/xslt/xslt/txInstructions.cpp @@ -0,0 +1,764 @@ +/* -*- 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 "txInstructions.h" + +#include <utility> + +#include "nsError.h" +#include "nsGkAtoms.h" +#include "nsIConsoleService.h" +#include "nsServiceManagerUtils.h" +#include "txExecutionState.h" +#include "txExpr.h" +#include "txNodeSetContext.h" +#include "txNodeSorter.h" +#include "txRtfHandler.h" +#include "txStringUtils.h" +#include "txStylesheet.h" +#include "txTextHandler.h" +#include "txXSLTNumber.h" + +using mozilla::MakeUnique; +using mozilla::UniquePtr; + +nsresult txApplyDefaultElementTemplate::execute(txExecutionState& aEs) { + txExecutionState::TemplateRule* rule = aEs.getCurrentTemplateRule(); + txExpandedName mode(rule->mModeNsId, rule->mModeLocalName); + txStylesheet::ImportFrame* frame = 0; + txInstruction* templ; + nsresult rv = + aEs.mStylesheet->findTemplate(aEs.getEvalContext()->getContextNode(), + mode, &aEs, nullptr, &templ, &frame); + NS_ENSURE_SUCCESS(rv, rv); + + aEs.pushTemplateRule(frame, mode, aEs.mTemplateParams); + + return aEs.runTemplate(templ); +} + +nsresult txApplyImportsEnd::execute(txExecutionState& aEs) { + aEs.popTemplateRule(); + RefPtr<txParameterMap> paramMap = aEs.popParamMap(); + + return NS_OK; +} + +nsresult txApplyImportsStart::execute(txExecutionState& aEs) { + txExecutionState::TemplateRule* rule = aEs.getCurrentTemplateRule(); + // The frame is set to null when there is no current template rule, or + // when the current template rule is a default template. However this + // instruction isn't used in default templates. + if (!rule->mFrame) { + // XXX ErrorReport: apply-imports instantiated without a current rule + return NS_ERROR_XSLT_EXECUTION_FAILURE; + } + + aEs.pushParamMap(rule->mParams); + + txStylesheet::ImportFrame* frame = 0; + txExpandedName mode(rule->mModeNsId, rule->mModeLocalName); + txInstruction* templ; + nsresult rv = + aEs.mStylesheet->findTemplate(aEs.getEvalContext()->getContextNode(), + mode, &aEs, rule->mFrame, &templ, &frame); + NS_ENSURE_SUCCESS(rv, rv); + + aEs.pushTemplateRule(frame, mode, rule->mParams); + + rv = aEs.runTemplate(templ); + if (NS_FAILED(rv)) { + aEs.popTemplateRule(); + } + + return rv; +} + +txApplyTemplates::txApplyTemplates(const txExpandedName& aMode) + : mMode(aMode) {} + +nsresult txApplyTemplates::execute(txExecutionState& aEs) { + txStylesheet::ImportFrame* frame = 0; + txInstruction* templ; + nsresult rv = + aEs.mStylesheet->findTemplate(aEs.getEvalContext()->getContextNode(), + mMode, &aEs, nullptr, &templ, &frame); + NS_ENSURE_SUCCESS(rv, rv); + + aEs.pushTemplateRule(frame, mMode, aEs.mTemplateParams); + + return aEs.runTemplate(templ); +} + +txAttribute::txAttribute(UniquePtr<Expr>&& aName, UniquePtr<Expr>&& aNamespace, + txNamespaceMap* aMappings) + : mName(std::move(aName)), + mNamespace(std::move(aNamespace)), + mMappings(aMappings) {} + +nsresult txAttribute::execute(txExecutionState& aEs) { + UniquePtr<txTextHandler> handler( + static_cast<txTextHandler*>(aEs.popResultHandler())); + + nsAutoString name; + nsresult rv = mName->evaluateToString(aEs.getEvalContext(), name); + NS_ENSURE_SUCCESS(rv, rv); + + const char16_t* colon; + if (!XMLUtils::isValidQName(name, &colon) || + TX_StringEqualsAtom(name, nsGkAtoms::xmlns)) { + return NS_OK; + } + + RefPtr<nsAtom> prefix; + uint32_t lnameStart = 0; + if (colon) { + prefix = NS_Atomize(Substring(name.get(), colon)); + lnameStart = colon - name.get() + 1; + } + + int32_t nsId = kNameSpaceID_None; + if (mNamespace) { + nsAutoString nspace; + rv = mNamespace->evaluateToString(aEs.getEvalContext(), nspace); + NS_ENSURE_SUCCESS(rv, rv); + + if (!nspace.IsEmpty()) { + nsId = txNamespaceManager::getNamespaceID(nspace); + } + } else if (colon) { + nsId = mMappings->lookupNamespace(prefix); + } + + // add attribute if everything was ok + return nsId != kNameSpaceID_Unknown + ? aEs.mResultHandler->attribute( + prefix, Substring(name, lnameStart), nsId, handler->mValue) + : NS_OK; +} + +txCallTemplate::txCallTemplate(const txExpandedName& aName) : mName(aName) {} + +nsresult txCallTemplate::execute(txExecutionState& aEs) { + txInstruction* instr = aEs.mStylesheet->getNamedTemplate(mName); + NS_ENSURE_TRUE(instr, NS_ERROR_XSLT_EXECUTION_FAILURE); + + nsresult rv = aEs.runTemplate(instr); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +txCheckParam::txCheckParam(const txExpandedName& aName) + : mName(aName), mBailTarget(nullptr) {} + +nsresult txCheckParam::execute(txExecutionState& aEs) { + nsresult rv = NS_OK; + if (aEs.mTemplateParams) { + RefPtr<txAExprResult> exprRes; + aEs.mTemplateParams->getVariable(mName, getter_AddRefs(exprRes)); + if (exprRes) { + rv = aEs.bindVariable(mName, exprRes); + NS_ENSURE_SUCCESS(rv, rv); + + aEs.gotoInstruction(mBailTarget); + } + } + + return NS_OK; +} + +txConditionalGoto::txConditionalGoto(UniquePtr<Expr>&& aCondition, + txInstruction* aTarget) + : mCondition(std::move(aCondition)), mTarget(aTarget) {} + +nsresult txConditionalGoto::execute(txExecutionState& aEs) { + bool exprRes; + nsresult rv = mCondition->evaluateToBool(aEs.getEvalContext(), exprRes); + NS_ENSURE_SUCCESS(rv, rv); + + if (!exprRes) { + aEs.gotoInstruction(mTarget); + } + + return NS_OK; +} + +nsresult txComment::execute(txExecutionState& aEs) { + UniquePtr<txTextHandler> handler( + static_cast<txTextHandler*>(aEs.popResultHandler())); + uint32_t length = handler->mValue.Length(); + int32_t pos = 0; + while ((pos = handler->mValue.FindChar('-', (uint32_t)pos)) != kNotFound) { + ++pos; + if ((uint32_t)pos == length || handler->mValue.CharAt(pos) == '-') { + handler->mValue.Insert(char16_t(' '), pos++); + ++length; + } + } + + return aEs.mResultHandler->comment(handler->mValue); +} + +nsresult txCopyBase::copyNode(const txXPathNode& aNode, txExecutionState& aEs) { + switch (txXPathNodeUtils::getNodeType(aNode)) { + case txXPathNodeType::ATTRIBUTE_NODE: { + nsAutoString nodeValue; + txXPathNodeUtils::appendNodeValue(aNode, nodeValue); + + RefPtr<nsAtom> localName = txXPathNodeUtils::getLocalName(aNode); + return aEs.mResultHandler->attribute( + txXPathNodeUtils::getPrefix(aNode), localName, nullptr, + txXPathNodeUtils::getNamespaceID(aNode), nodeValue); + } + case txXPathNodeType::COMMENT_NODE: { + nsAutoString nodeValue; + txXPathNodeUtils::appendNodeValue(aNode, nodeValue); + return aEs.mResultHandler->comment(nodeValue); + } + case txXPathNodeType::DOCUMENT_NODE: + case txXPathNodeType::DOCUMENT_FRAGMENT_NODE: { + // Copy children + txXPathTreeWalker walker(aNode); + bool hasChild = walker.moveToFirstChild(); + while (hasChild) { + copyNode(walker.getCurrentPosition(), aEs); + hasChild = walker.moveToNextSibling(); + } + break; + } + case txXPathNodeType::ELEMENT_NODE: { + RefPtr<nsAtom> localName = txXPathNodeUtils::getLocalName(aNode); + nsresult rv = aEs.mResultHandler->startElement( + txXPathNodeUtils::getPrefix(aNode), localName, nullptr, + txXPathNodeUtils::getNamespaceID(aNode)); + NS_ENSURE_SUCCESS(rv, rv); + + // Copy attributes + txXPathTreeWalker walker(aNode); + if (walker.moveToFirstAttribute()) { + do { + nsAutoString nodeValue; + walker.appendNodeValue(nodeValue); + + const txXPathNode& attr = walker.getCurrentPosition(); + localName = txXPathNodeUtils::getLocalName(attr); + rv = aEs.mResultHandler->attribute( + txXPathNodeUtils::getPrefix(attr), localName, nullptr, + txXPathNodeUtils::getNamespaceID(attr), nodeValue); + NS_ENSURE_SUCCESS(rv, rv); + } while (walker.moveToNextAttribute()); + walker.moveToParent(); + } + + // Copy children + bool hasChild = walker.moveToFirstChild(); + while (hasChild) { + copyNode(walker.getCurrentPosition(), aEs); + hasChild = walker.moveToNextSibling(); + } + + return aEs.mResultHandler->endElement(); + } + case txXPathNodeType::PROCESSING_INSTRUCTION_NODE: { + nsAutoString target, data; + txXPathNodeUtils::getNodeName(aNode, target); + txXPathNodeUtils::appendNodeValue(aNode, data); + return aEs.mResultHandler->processingInstruction(target, data); + } + case txXPathNodeType::TEXT_NODE: + case txXPathNodeType::CDATA_SECTION_NODE: { + nsAutoString nodeValue; + txXPathNodeUtils::appendNodeValue(aNode, nodeValue); + return aEs.mResultHandler->characters(nodeValue, false); + } + } + + return NS_OK; +} + +txCopy::txCopy() : mBailTarget(nullptr) {} + +nsresult txCopy::execute(txExecutionState& aEs) { + nsresult rv = NS_OK; + const txXPathNode& node = aEs.getEvalContext()->getContextNode(); + + switch (txXPathNodeUtils::getNodeType(node)) { + case txXPathNodeType::DOCUMENT_NODE: + case txXPathNodeType::DOCUMENT_FRAGMENT_NODE: { + // "close" current element to ensure that no attributes are added + rv = aEs.mResultHandler->characters(u""_ns, false); + NS_ENSURE_SUCCESS(rv, rv); + + aEs.pushBool(false); + + break; + } + case txXPathNodeType::ELEMENT_NODE: { + RefPtr<nsAtom> localName = txXPathNodeUtils::getLocalName(node); + rv = aEs.mResultHandler->startElement( + txXPathNodeUtils::getPrefix(node), localName, nullptr, + txXPathNodeUtils::getNamespaceID(node)); + NS_ENSURE_SUCCESS(rv, rv); + + // XXX copy namespace nodes once we have them + + aEs.pushBool(true); + + break; + } + default: { + rv = copyNode(node, aEs); + NS_ENSURE_SUCCESS(rv, rv); + + aEs.gotoInstruction(mBailTarget); + } + } + + return NS_OK; +} + +txCopyOf::txCopyOf(UniquePtr<Expr>&& aSelect) : mSelect(std::move(aSelect)) {} + +nsresult txCopyOf::execute(txExecutionState& aEs) { + RefPtr<txAExprResult> exprRes; + nsresult rv = + mSelect->evaluate(aEs.getEvalContext(), getter_AddRefs(exprRes)); + NS_ENSURE_SUCCESS(rv, rv); + + switch (exprRes->getResultType()) { + case txAExprResult::NODESET: { + txNodeSet* nodes = + static_cast<txNodeSet*>(static_cast<txAExprResult*>(exprRes)); + int32_t i; + for (i = 0; i < nodes->size(); ++i) { + rv = copyNode(nodes->get(i), aEs); + NS_ENSURE_SUCCESS(rv, rv); + } + break; + } + case txAExprResult::RESULT_TREE_FRAGMENT: { + txResultTreeFragment* rtf = static_cast<txResultTreeFragment*>( + static_cast<txAExprResult*>(exprRes)); + return rtf->flushToHandler(aEs.mResultHandler); + } + default: { + nsAutoString value; + exprRes->stringValue(value); + if (!value.IsEmpty()) { + return aEs.mResultHandler->characters(value, false); + } + break; + } + } + + return NS_OK; +} + +nsresult txEndElement::execute(txExecutionState& aEs) { + // This will return false if startElement was not called. This happens + // when <xsl:element> produces a bad name, or when <xsl:copy> copies a + // document node. + if (aEs.popBool()) { + return aEs.mResultHandler->endElement(); + } + + return NS_OK; +} + +nsresult txErrorInstruction::execute(txExecutionState& aEs) { + // XXX ErrorReport: unknown instruction executed + return NS_ERROR_XSLT_EXECUTION_FAILURE; +} + +txGoTo::txGoTo(txInstruction* aTarget) : mTarget(aTarget) {} + +nsresult txGoTo::execute(txExecutionState& aEs) { + aEs.gotoInstruction(mTarget); + + return NS_OK; +} + +txInsertAttrSet::txInsertAttrSet(const txExpandedName& aName) : mName(aName) {} + +nsresult txInsertAttrSet::execute(txExecutionState& aEs) { + txInstruction* instr = aEs.mStylesheet->getAttributeSet(mName); + NS_ENSURE_TRUE(instr, NS_ERROR_XSLT_EXECUTION_FAILURE); + + nsresult rv = aEs.runTemplate(instr); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +txLoopNodeSet::txLoopNodeSet(txInstruction* aTarget) : mTarget(aTarget) {} + +nsresult txLoopNodeSet::execute(txExecutionState& aEs) { + aEs.popTemplateRule(); + txNodeSetContext* context = + static_cast<txNodeSetContext*>(aEs.getEvalContext()); + if (!context->hasNext()) { + delete aEs.popEvalContext(); + + return NS_OK; + } + + context->next(); + aEs.gotoInstruction(mTarget); + + return NS_OK; +} + +txLREAttribute::txLREAttribute(int32_t aNamespaceID, nsAtom* aLocalName, + nsAtom* aPrefix, UniquePtr<Expr>&& aValue) + : mNamespaceID(aNamespaceID), + mLocalName(aLocalName), + mPrefix(aPrefix), + mValue(std::move(aValue)) { + if (aNamespaceID == kNameSpaceID_None) { + mLowercaseLocalName = TX_ToLowerCaseAtom(aLocalName); + } +} + +nsresult txLREAttribute::execute(txExecutionState& aEs) { + RefPtr<txAExprResult> exprRes; + nsresult rv = mValue->evaluate(aEs.getEvalContext(), getter_AddRefs(exprRes)); + NS_ENSURE_SUCCESS(rv, rv); + + const nsString* value = exprRes->stringValuePointer(); + if (value) { + return aEs.mResultHandler->attribute( + mPrefix, mLocalName, mLowercaseLocalName, mNamespaceID, *value); + } + + nsAutoString valueStr; + exprRes->stringValue(valueStr); + return aEs.mResultHandler->attribute(mPrefix, mLocalName, mLowercaseLocalName, + mNamespaceID, valueStr); +} + +txMessage::txMessage(bool aTerminate) : mTerminate(aTerminate) {} + +nsresult txMessage::execute(txExecutionState& aEs) { + UniquePtr<txTextHandler> handler( + static_cast<txTextHandler*>(aEs.popResultHandler())); + + nsCOMPtr<nsIConsoleService> consoleSvc = + do_GetService("@mozilla.org/consoleservice;1"); + if (consoleSvc) { + nsAutoString logString(u"xsl:message - "_ns); + logString.Append(handler->mValue); + consoleSvc->LogStringMessage(logString.get()); + } + + return mTerminate ? NS_ERROR_XSLT_ABORTED : NS_OK; +} + +txNumber::txNumber(txXSLTNumber::LevelType aLevel, + UniquePtr<txPattern>&& aCount, UniquePtr<txPattern>&& aFrom, + UniquePtr<Expr>&& aValue, UniquePtr<Expr>&& aFormat, + UniquePtr<Expr>&& aGroupingSeparator, + UniquePtr<Expr>&& aGroupingSize) + : mLevel(aLevel), + mCount(std::move(aCount)), + mFrom(std::move(aFrom)), + mValue(std::move(aValue)), + mFormat(std::move(aFormat)), + mGroupingSeparator(std::move(aGroupingSeparator)), + mGroupingSize(std::move(aGroupingSize)) {} + +nsresult txNumber::execute(txExecutionState& aEs) { + nsAutoString res; + nsresult rv = txXSLTNumber::createNumber( + mValue.get(), mCount.get(), mFrom.get(), mLevel, mGroupingSize.get(), + mGroupingSeparator.get(), mFormat.get(), aEs.getEvalContext(), res); + NS_ENSURE_SUCCESS(rv, rv); + + return aEs.mResultHandler->characters(res, false); +} + +nsresult txPopParams::execute(txExecutionState& aEs) { + RefPtr<txParameterMap> paramMap = aEs.popParamMap(); + + return NS_OK; +} + +txProcessingInstruction::txProcessingInstruction(UniquePtr<Expr>&& aName) + : mName(std::move(aName)) {} + +nsresult txProcessingInstruction::execute(txExecutionState& aEs) { + UniquePtr<txTextHandler> handler( + static_cast<txTextHandler*>(aEs.popResultHandler())); + XMLUtils::normalizePIValue(handler->mValue); + + nsAutoString name; + nsresult rv = mName->evaluateToString(aEs.getEvalContext(), name); + NS_ENSURE_SUCCESS(rv, rv); + + // Check name validity (must be valid NCName and a PITarget) + // XXX Need to check for NCName and PITarget + const char16_t* colon; + if (!XMLUtils::isValidQName(name, &colon)) { + // XXX ErrorReport: bad PI-target + return NS_ERROR_FAILURE; + } + + return aEs.mResultHandler->processingInstruction(name, handler->mValue); +} + +txPushNewContext::txPushNewContext(UniquePtr<Expr>&& aSelect) + : mSelect(std::move(aSelect)), mBailTarget(nullptr) {} + +txPushNewContext::~txPushNewContext() = default; + +nsresult txPushNewContext::execute(txExecutionState& aEs) { + RefPtr<txAExprResult> exprRes; + nsresult rv = + mSelect->evaluate(aEs.getEvalContext(), getter_AddRefs(exprRes)); + NS_ENSURE_SUCCESS(rv, rv); + + if (exprRes->getResultType() != txAExprResult::NODESET) { + // XXX ErrorReport: nodeset expected + return NS_ERROR_XSLT_NODESET_EXPECTED; + } + + txNodeSet* nodes = + static_cast<txNodeSet*>(static_cast<txAExprResult*>(exprRes)); + + if (nodes->isEmpty()) { + aEs.gotoInstruction(mBailTarget); + + return NS_OK; + } + + txNodeSorter sorter; + uint32_t i, count = mSortKeys.Length(); + for (i = 0; i < count; ++i) { + SortKey& sort = mSortKeys[i]; + rv = sorter.addSortElement(sort.mSelectExpr.get(), sort.mLangExpr.get(), + sort.mDataTypeExpr.get(), sort.mOrderExpr.get(), + sort.mCaseOrderExpr.get(), aEs.getEvalContext()); + NS_ENSURE_SUCCESS(rv, rv); + } + RefPtr<txNodeSet> sortedNodes; + rv = sorter.sortNodeSet(nodes, &aEs, getter_AddRefs(sortedNodes)); + NS_ENSURE_SUCCESS(rv, rv); + + auto context = MakeUnique<txNodeSetContext>(sortedNodes, &aEs); + context->next(); + + aEs.pushEvalContext(context.release()); + + return NS_OK; +} + +void txPushNewContext::addSort(UniquePtr<Expr>&& aSelectExpr, + UniquePtr<Expr>&& aLangExpr, + UniquePtr<Expr>&& aDataTypeExpr, + UniquePtr<Expr>&& aOrderExpr, + UniquePtr<Expr>&& aCaseOrderExpr) { + SortKey* key = mSortKeys.AppendElement(); + // workaround for not triggering the Copy Constructor + key->mSelectExpr = std::move(aSelectExpr); + key->mLangExpr = std::move(aLangExpr); + key->mDataTypeExpr = std::move(aDataTypeExpr); + key->mOrderExpr = std::move(aOrderExpr); + key->mCaseOrderExpr = std::move(aCaseOrderExpr); +} + +nsresult txPushNullTemplateRule::execute(txExecutionState& aEs) { + aEs.pushTemplateRule(nullptr, txExpandedName(), nullptr); + return NS_OK; +} + +nsresult txPushParams::execute(txExecutionState& aEs) { + aEs.pushParamMap(nullptr); + return NS_OK; +} + +nsresult txPushRTFHandler::execute(txExecutionState& aEs) { + aEs.pushResultHandler(new txRtfHandler); + + return NS_OK; +} + +txPushStringHandler::txPushStringHandler(bool aOnlyText) + : mOnlyText(aOnlyText) {} + +nsresult txPushStringHandler::execute(txExecutionState& aEs) { + aEs.pushResultHandler(new txTextHandler(mOnlyText)); + + return NS_OK; +} + +txRemoveVariable::txRemoveVariable(const txExpandedName& aName) + : mName(aName) {} + +nsresult txRemoveVariable::execute(txExecutionState& aEs) { + aEs.removeVariable(mName); + + return NS_OK; +} + +nsresult txReturn::execute(txExecutionState& aEs) { + NS_ASSERTION(!mNext, "instructions exist after txReturn"); + aEs.returnFromTemplate(); + + return NS_OK; +} + +txSetParam::txSetParam(const txExpandedName& aName, UniquePtr<Expr>&& aValue) + : mName(aName), mValue(std::move(aValue)) {} + +nsresult txSetParam::execute(txExecutionState& aEs) { + nsresult rv = NS_OK; + if (!aEs.mTemplateParams) { + aEs.mTemplateParams = new txParameterMap; + } + + RefPtr<txAExprResult> exprRes; + if (mValue) { + rv = mValue->evaluate(aEs.getEvalContext(), getter_AddRefs(exprRes)); + NS_ENSURE_SUCCESS(rv, rv); + } else { + UniquePtr<txRtfHandler> rtfHandler( + static_cast<txRtfHandler*>(aEs.popResultHandler())); + rv = rtfHandler->getAsRTF(getter_AddRefs(exprRes)); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = aEs.mTemplateParams->bindVariable(mName, exprRes); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +txSetVariable::txSetVariable(const txExpandedName& aName, + UniquePtr<Expr>&& aValue) + : mName(aName), mValue(std::move(aValue)) {} + +nsresult txSetVariable::execute(txExecutionState& aEs) { + nsresult rv = NS_OK; + RefPtr<txAExprResult> exprRes; + if (mValue) { + rv = mValue->evaluate(aEs.getEvalContext(), getter_AddRefs(exprRes)); + NS_ENSURE_SUCCESS(rv, rv); + } else { + UniquePtr<txRtfHandler> rtfHandler( + static_cast<txRtfHandler*>(aEs.popResultHandler())); + rv = rtfHandler->getAsRTF(getter_AddRefs(exprRes)); + NS_ENSURE_SUCCESS(rv, rv); + } + + return aEs.bindVariable(mName, exprRes); +} + +txStartElement::txStartElement(UniquePtr<Expr>&& aName, + UniquePtr<Expr>&& aNamespace, + txNamespaceMap* aMappings) + : mName(std::move(aName)), + mNamespace(std::move(aNamespace)), + mMappings(aMappings) {} + +nsresult txStartElement::execute(txExecutionState& aEs) { + nsAutoString name; + nsresult rv = mName->evaluateToString(aEs.getEvalContext(), name); + NS_ENSURE_SUCCESS(rv, rv); + + int32_t nsId = kNameSpaceID_None; + RefPtr<nsAtom> prefix; + uint32_t lnameStart = 0; + + const char16_t* colon; + if (XMLUtils::isValidQName(name, &colon)) { + if (colon) { + prefix = NS_Atomize(Substring(name.get(), colon)); + lnameStart = colon - name.get() + 1; + } + + if (mNamespace) { + nsAutoString nspace; + rv = mNamespace->evaluateToString(aEs.getEvalContext(), nspace); + NS_ENSURE_SUCCESS(rv, rv); + + if (!nspace.IsEmpty()) { + nsId = txNamespaceManager::getNamespaceID(nspace); + } + } else { + nsId = mMappings->lookupNamespace(prefix); + } + } else { + nsId = kNameSpaceID_Unknown; + } + + bool success = true; + + if (nsId != kNameSpaceID_Unknown) { + rv = aEs.mResultHandler->startElement(prefix, Substring(name, lnameStart), + nsId); + } else { + rv = NS_ERROR_XSLT_BAD_NODE_NAME; + } + + if (rv == NS_ERROR_XSLT_BAD_NODE_NAME) { + success = false; + // we call characters with an empty string to "close" any element to + // make sure that no attributes are added + rv = aEs.mResultHandler->characters(u""_ns, false); + } + NS_ENSURE_SUCCESS(rv, rv); + + aEs.pushBool(success); + + return NS_OK; +} + +txStartLREElement::txStartLREElement(int32_t aNamespaceID, nsAtom* aLocalName, + nsAtom* aPrefix) + : mNamespaceID(aNamespaceID), mLocalName(aLocalName), mPrefix(aPrefix) { + if (aNamespaceID == kNameSpaceID_None) { + mLowercaseLocalName = TX_ToLowerCaseAtom(aLocalName); + } +} + +nsresult txStartLREElement::execute(txExecutionState& aEs) { + nsresult rv = aEs.mResultHandler->startElement( + mPrefix, mLocalName, mLowercaseLocalName, mNamespaceID); + NS_ENSURE_SUCCESS(rv, rv); + + aEs.pushBool(true); + + return NS_OK; +} + +txText::txText(const nsAString& aStr, bool aDOE) : mStr(aStr), mDOE(aDOE) {} + +nsresult txText::execute(txExecutionState& aEs) { + return aEs.mResultHandler->characters(mStr, mDOE); +} + +txValueOf::txValueOf(UniquePtr<Expr>&& aExpr, bool aDOE) + : mExpr(std::move(aExpr)), mDOE(aDOE) {} + +nsresult txValueOf::execute(txExecutionState& aEs) { + RefPtr<txAExprResult> exprRes; + nsresult rv = mExpr->evaluate(aEs.getEvalContext(), getter_AddRefs(exprRes)); + NS_ENSURE_SUCCESS(rv, rv); + + const nsString* value = exprRes->stringValuePointer(); + if (value) { + if (!value->IsEmpty()) { + return aEs.mResultHandler->characters(*value, mDOE); + } + } else { + nsAutoString valueStr; + exprRes->stringValue(valueStr); + if (!valueStr.IsEmpty()) { + return aEs.mResultHandler->characters(valueStr, mDOE); + } + } + + return NS_OK; +} |