Bug 1874684 - Part 4: Prefer const references instead of copying Instant values....
[gecko.git] / dom / xslt / xslt / txInstructions.cpp
blobdf6e1ffeb0db05ee0d99055027b03d8669c9e579
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/. */
6 #include "txInstructions.h"
8 #include <utility>
10 #include "nsError.h"
11 #include "nsGkAtoms.h"
12 #include "nsIConsoleService.h"
13 #include "nsServiceManagerUtils.h"
14 #include "txExecutionState.h"
15 #include "txExpr.h"
16 #include "txNodeSetContext.h"
17 #include "txNodeSorter.h"
18 #include "txRtfHandler.h"
19 #include "txStringUtils.h"
20 #include "txStylesheet.h"
21 #include "txTextHandler.h"
22 #include "txXSLTNumber.h"
24 using mozilla::MakeUnique;
25 using mozilla::UniquePtr;
27 nsresult txApplyDefaultElementTemplate::execute(txExecutionState& aEs) {
28 txExecutionState::TemplateRule* rule = aEs.getCurrentTemplateRule();
29 txExpandedName mode(rule->mModeNsId, rule->mModeLocalName);
30 txStylesheet::ImportFrame* frame = 0;
31 txInstruction* templ;
32 nsresult rv =
33 aEs.mStylesheet->findTemplate(aEs.getEvalContext()->getContextNode(),
34 mode, &aEs, nullptr, &templ, &frame);
35 NS_ENSURE_SUCCESS(rv, rv);
37 aEs.pushTemplateRule(frame, mode, aEs.mTemplateParams);
39 return aEs.runTemplate(templ);
42 nsresult txApplyImportsEnd::execute(txExecutionState& aEs) {
43 aEs.popTemplateRule();
44 RefPtr<txParameterMap> paramMap = aEs.popParamMap();
46 return NS_OK;
49 nsresult txApplyImportsStart::execute(txExecutionState& aEs) {
50 txExecutionState::TemplateRule* rule = aEs.getCurrentTemplateRule();
51 // The frame is set to null when there is no current template rule, or
52 // when the current template rule is a default template. However this
53 // instruction isn't used in default templates.
54 if (!rule->mFrame) {
55 // XXX ErrorReport: apply-imports instantiated without a current rule
56 return NS_ERROR_XSLT_EXECUTION_FAILURE;
59 aEs.pushParamMap(rule->mParams);
61 txStylesheet::ImportFrame* frame = 0;
62 txExpandedName mode(rule->mModeNsId, rule->mModeLocalName);
63 txInstruction* templ;
64 nsresult rv =
65 aEs.mStylesheet->findTemplate(aEs.getEvalContext()->getContextNode(),
66 mode, &aEs, rule->mFrame, &templ, &frame);
67 NS_ENSURE_SUCCESS(rv, rv);
69 aEs.pushTemplateRule(frame, mode, rule->mParams);
71 rv = aEs.runTemplate(templ);
72 if (NS_FAILED(rv)) {
73 aEs.popTemplateRule();
76 return rv;
79 txApplyTemplates::txApplyTemplates(const txExpandedName& aMode)
80 : mMode(aMode) {}
82 nsresult txApplyTemplates::execute(txExecutionState& aEs) {
83 txStylesheet::ImportFrame* frame = 0;
84 txInstruction* templ;
85 nsresult rv =
86 aEs.mStylesheet->findTemplate(aEs.getEvalContext()->getContextNode(),
87 mMode, &aEs, nullptr, &templ, &frame);
88 NS_ENSURE_SUCCESS(rv, rv);
90 aEs.pushTemplateRule(frame, mMode, aEs.mTemplateParams);
92 return aEs.runTemplate(templ);
95 txAttribute::txAttribute(UniquePtr<Expr>&& aName, UniquePtr<Expr>&& aNamespace,
96 txNamespaceMap* aMappings)
97 : mName(std::move(aName)),
98 mNamespace(std::move(aNamespace)),
99 mMappings(aMappings) {}
101 nsresult txAttribute::execute(txExecutionState& aEs) {
102 UniquePtr<txTextHandler> handler(
103 static_cast<txTextHandler*>(aEs.popResultHandler()));
105 nsAutoString name;
106 nsresult rv = mName->evaluateToString(aEs.getEvalContext(), name);
107 NS_ENSURE_SUCCESS(rv, rv);
109 const char16_t* colon;
110 if (!XMLUtils::isValidQName(name, &colon) ||
111 TX_StringEqualsAtom(name, nsGkAtoms::xmlns)) {
112 return NS_OK;
115 RefPtr<nsAtom> prefix;
116 uint32_t lnameStart = 0;
117 if (colon) {
118 prefix = NS_Atomize(Substring(name.get(), colon));
119 lnameStart = colon - name.get() + 1;
122 int32_t nsId = kNameSpaceID_None;
123 if (mNamespace) {
124 nsAutoString nspace;
125 rv = mNamespace->evaluateToString(aEs.getEvalContext(), nspace);
126 NS_ENSURE_SUCCESS(rv, rv);
128 if (!nspace.IsEmpty()) {
129 nsId = txNamespaceManager::getNamespaceID(nspace);
131 } else if (colon) {
132 nsId = mMappings->lookupNamespace(prefix);
135 // add attribute if everything was ok
136 return nsId != kNameSpaceID_Unknown
137 ? aEs.mResultHandler->attribute(
138 prefix, Substring(name, lnameStart), nsId, handler->mValue)
139 : NS_OK;
142 txCallTemplate::txCallTemplate(const txExpandedName& aName) : mName(aName) {}
144 nsresult txCallTemplate::execute(txExecutionState& aEs) {
145 txInstruction* instr = aEs.mStylesheet->getNamedTemplate(mName);
146 NS_ENSURE_TRUE(instr, NS_ERROR_XSLT_EXECUTION_FAILURE);
148 nsresult rv = aEs.runTemplate(instr);
149 NS_ENSURE_SUCCESS(rv, rv);
151 return NS_OK;
154 txCheckParam::txCheckParam(const txExpandedName& aName)
155 : mName(aName), mBailTarget(nullptr) {}
157 nsresult txCheckParam::execute(txExecutionState& aEs) {
158 nsresult rv = NS_OK;
159 if (aEs.mTemplateParams) {
160 RefPtr<txAExprResult> exprRes;
161 aEs.mTemplateParams->getVariable(mName, getter_AddRefs(exprRes));
162 if (exprRes) {
163 rv = aEs.bindVariable(mName, exprRes);
164 NS_ENSURE_SUCCESS(rv, rv);
166 aEs.gotoInstruction(mBailTarget);
170 return NS_OK;
173 txConditionalGoto::txConditionalGoto(UniquePtr<Expr>&& aCondition,
174 txInstruction* aTarget)
175 : mCondition(std::move(aCondition)), mTarget(aTarget) {}
177 nsresult txConditionalGoto::execute(txExecutionState& aEs) {
178 bool exprRes;
179 nsresult rv = mCondition->evaluateToBool(aEs.getEvalContext(), exprRes);
180 NS_ENSURE_SUCCESS(rv, rv);
182 if (!exprRes) {
183 aEs.gotoInstruction(mTarget);
186 return NS_OK;
189 nsresult txComment::execute(txExecutionState& aEs) {
190 UniquePtr<txTextHandler> handler(
191 static_cast<txTextHandler*>(aEs.popResultHandler()));
192 uint32_t length = handler->mValue.Length();
193 int32_t pos = 0;
194 while ((pos = handler->mValue.FindChar('-', (uint32_t)pos)) != kNotFound) {
195 ++pos;
196 if ((uint32_t)pos == length || handler->mValue.CharAt(pos) == '-') {
197 handler->mValue.Insert(char16_t(' '), pos++);
198 ++length;
202 return aEs.mResultHandler->comment(handler->mValue);
205 nsresult txCopyBase::copyNode(const txXPathNode& aNode, txExecutionState& aEs) {
206 switch (txXPathNodeUtils::getNodeType(aNode)) {
207 case txXPathNodeType::ATTRIBUTE_NODE: {
208 nsAutoString nodeValue;
209 txXPathNodeUtils::appendNodeValue(aNode, nodeValue);
211 RefPtr<nsAtom> localName = txXPathNodeUtils::getLocalName(aNode);
212 return aEs.mResultHandler->attribute(
213 txXPathNodeUtils::getPrefix(aNode), localName, nullptr,
214 txXPathNodeUtils::getNamespaceID(aNode), nodeValue);
216 case txXPathNodeType::COMMENT_NODE: {
217 nsAutoString nodeValue;
218 txXPathNodeUtils::appendNodeValue(aNode, nodeValue);
219 return aEs.mResultHandler->comment(nodeValue);
221 case txXPathNodeType::DOCUMENT_NODE:
222 case txXPathNodeType::DOCUMENT_FRAGMENT_NODE: {
223 // Copy children
224 txXPathTreeWalker walker(aNode);
225 bool hasChild = walker.moveToFirstChild();
226 while (hasChild) {
227 copyNode(walker.getCurrentPosition(), aEs);
228 hasChild = walker.moveToNextSibling();
230 break;
232 case txXPathNodeType::ELEMENT_NODE: {
233 RefPtr<nsAtom> localName = txXPathNodeUtils::getLocalName(aNode);
234 nsresult rv = aEs.mResultHandler->startElement(
235 txXPathNodeUtils::getPrefix(aNode), localName, nullptr,
236 txXPathNodeUtils::getNamespaceID(aNode));
237 NS_ENSURE_SUCCESS(rv, rv);
239 // Copy attributes
240 txXPathTreeWalker walker(aNode);
241 if (walker.moveToFirstAttribute()) {
242 do {
243 nsAutoString nodeValue;
244 walker.appendNodeValue(nodeValue);
246 const txXPathNode& attr = walker.getCurrentPosition();
247 localName = txXPathNodeUtils::getLocalName(attr);
248 rv = aEs.mResultHandler->attribute(
249 txXPathNodeUtils::getPrefix(attr), localName, nullptr,
250 txXPathNodeUtils::getNamespaceID(attr), nodeValue);
251 NS_ENSURE_SUCCESS(rv, rv);
252 } while (walker.moveToNextAttribute());
253 walker.moveToParent();
256 // Copy children
257 bool hasChild = walker.moveToFirstChild();
258 while (hasChild) {
259 copyNode(walker.getCurrentPosition(), aEs);
260 hasChild = walker.moveToNextSibling();
263 return aEs.mResultHandler->endElement();
265 case txXPathNodeType::PROCESSING_INSTRUCTION_NODE: {
266 nsAutoString target, data;
267 txXPathNodeUtils::getNodeName(aNode, target);
268 txXPathNodeUtils::appendNodeValue(aNode, data);
269 return aEs.mResultHandler->processingInstruction(target, data);
271 case txXPathNodeType::TEXT_NODE:
272 case txXPathNodeType::CDATA_SECTION_NODE: {
273 nsAutoString nodeValue;
274 txXPathNodeUtils::appendNodeValue(aNode, nodeValue);
275 return aEs.mResultHandler->characters(nodeValue, false);
279 return NS_OK;
282 txCopy::txCopy() : mBailTarget(nullptr) {}
284 nsresult txCopy::execute(txExecutionState& aEs) {
285 nsresult rv = NS_OK;
286 const txXPathNode& node = aEs.getEvalContext()->getContextNode();
288 switch (txXPathNodeUtils::getNodeType(node)) {
289 case txXPathNodeType::DOCUMENT_NODE:
290 case txXPathNodeType::DOCUMENT_FRAGMENT_NODE: {
291 // "close" current element to ensure that no attributes are added
292 rv = aEs.mResultHandler->characters(u""_ns, false);
293 NS_ENSURE_SUCCESS(rv, rv);
295 aEs.pushBool(false);
297 break;
299 case txXPathNodeType::ELEMENT_NODE: {
300 RefPtr<nsAtom> localName = txXPathNodeUtils::getLocalName(node);
301 rv = aEs.mResultHandler->startElement(
302 txXPathNodeUtils::getPrefix(node), localName, nullptr,
303 txXPathNodeUtils::getNamespaceID(node));
304 NS_ENSURE_SUCCESS(rv, rv);
306 // XXX copy namespace nodes once we have them
308 aEs.pushBool(true);
310 break;
312 default: {
313 rv = copyNode(node, aEs);
314 NS_ENSURE_SUCCESS(rv, rv);
316 aEs.gotoInstruction(mBailTarget);
320 return NS_OK;
323 txCopyOf::txCopyOf(UniquePtr<Expr>&& aSelect) : mSelect(std::move(aSelect)) {}
325 nsresult txCopyOf::execute(txExecutionState& aEs) {
326 RefPtr<txAExprResult> exprRes;
327 nsresult rv =
328 mSelect->evaluate(aEs.getEvalContext(), getter_AddRefs(exprRes));
329 NS_ENSURE_SUCCESS(rv, rv);
331 switch (exprRes->getResultType()) {
332 case txAExprResult::NODESET: {
333 txNodeSet* nodes =
334 static_cast<txNodeSet*>(static_cast<txAExprResult*>(exprRes));
335 int32_t i;
336 for (i = 0; i < nodes->size(); ++i) {
337 rv = copyNode(nodes->get(i), aEs);
338 NS_ENSURE_SUCCESS(rv, rv);
340 break;
342 case txAExprResult::RESULT_TREE_FRAGMENT: {
343 txResultTreeFragment* rtf = static_cast<txResultTreeFragment*>(
344 static_cast<txAExprResult*>(exprRes));
345 return rtf->flushToHandler(aEs.mResultHandler);
347 default: {
348 nsAutoString value;
349 exprRes->stringValue(value);
350 if (!value.IsEmpty()) {
351 return aEs.mResultHandler->characters(value, false);
353 break;
357 return NS_OK;
360 nsresult txEndElement::execute(txExecutionState& aEs) {
361 // This will return false if startElement was not called. This happens
362 // when <xsl:element> produces a bad name, or when <xsl:copy> copies a
363 // document node.
364 if (aEs.popBool()) {
365 return aEs.mResultHandler->endElement();
368 return NS_OK;
371 nsresult txErrorInstruction::execute(txExecutionState& aEs) {
372 // XXX ErrorReport: unknown instruction executed
373 return NS_ERROR_XSLT_EXECUTION_FAILURE;
376 txGoTo::txGoTo(txInstruction* aTarget) : mTarget(aTarget) {}
378 nsresult txGoTo::execute(txExecutionState& aEs) {
379 aEs.gotoInstruction(mTarget);
381 return NS_OK;
384 txInsertAttrSet::txInsertAttrSet(const txExpandedName& aName) : mName(aName) {}
386 nsresult txInsertAttrSet::execute(txExecutionState& aEs) {
387 txInstruction* instr = aEs.mStylesheet->getAttributeSet(mName);
388 NS_ENSURE_TRUE(instr, NS_ERROR_XSLT_EXECUTION_FAILURE);
390 nsresult rv = aEs.runTemplate(instr);
391 NS_ENSURE_SUCCESS(rv, rv);
393 return NS_OK;
396 txLoopNodeSet::txLoopNodeSet(txInstruction* aTarget) : mTarget(aTarget) {}
398 nsresult txLoopNodeSet::execute(txExecutionState& aEs) {
399 aEs.popTemplateRule();
400 txNodeSetContext* context =
401 static_cast<txNodeSetContext*>(aEs.getEvalContext());
402 if (!context->hasNext()) {
403 delete aEs.popEvalContext();
405 return NS_OK;
408 context->next();
409 aEs.gotoInstruction(mTarget);
411 return NS_OK;
414 txLREAttribute::txLREAttribute(int32_t aNamespaceID, nsAtom* aLocalName,
415 nsAtom* aPrefix, UniquePtr<Expr>&& aValue)
416 : mNamespaceID(aNamespaceID),
417 mLocalName(aLocalName),
418 mPrefix(aPrefix),
419 mValue(std::move(aValue)) {
420 if (aNamespaceID == kNameSpaceID_None) {
421 mLowercaseLocalName = TX_ToLowerCaseAtom(aLocalName);
425 nsresult txLREAttribute::execute(txExecutionState& aEs) {
426 RefPtr<txAExprResult> exprRes;
427 nsresult rv = mValue->evaluate(aEs.getEvalContext(), getter_AddRefs(exprRes));
428 NS_ENSURE_SUCCESS(rv, rv);
430 const nsString* value = exprRes->stringValuePointer();
431 if (value) {
432 return aEs.mResultHandler->attribute(
433 mPrefix, mLocalName, mLowercaseLocalName, mNamespaceID, *value);
436 nsAutoString valueStr;
437 exprRes->stringValue(valueStr);
438 return aEs.mResultHandler->attribute(mPrefix, mLocalName, mLowercaseLocalName,
439 mNamespaceID, valueStr);
442 txMessage::txMessage(bool aTerminate) : mTerminate(aTerminate) {}
444 nsresult txMessage::execute(txExecutionState& aEs) {
445 UniquePtr<txTextHandler> handler(
446 static_cast<txTextHandler*>(aEs.popResultHandler()));
448 nsCOMPtr<nsIConsoleService> consoleSvc =
449 do_GetService("@mozilla.org/consoleservice;1");
450 if (consoleSvc) {
451 nsAutoString logString(u"xsl:message - "_ns);
452 logString.Append(handler->mValue);
453 consoleSvc->LogStringMessage(logString.get());
456 return mTerminate ? NS_ERROR_XSLT_ABORTED : NS_OK;
459 txNumber::txNumber(txXSLTNumber::LevelType aLevel,
460 UniquePtr<txPattern>&& aCount, UniquePtr<txPattern>&& aFrom,
461 UniquePtr<Expr>&& aValue, UniquePtr<Expr>&& aFormat,
462 UniquePtr<Expr>&& aGroupingSeparator,
463 UniquePtr<Expr>&& aGroupingSize)
464 : mLevel(aLevel),
465 mCount(std::move(aCount)),
466 mFrom(std::move(aFrom)),
467 mValue(std::move(aValue)),
468 mFormat(std::move(aFormat)),
469 mGroupingSeparator(std::move(aGroupingSeparator)),
470 mGroupingSize(std::move(aGroupingSize)) {}
472 nsresult txNumber::execute(txExecutionState& aEs) {
473 nsAutoString res;
474 nsresult rv = txXSLTNumber::createNumber(
475 mValue.get(), mCount.get(), mFrom.get(), mLevel, mGroupingSize.get(),
476 mGroupingSeparator.get(), mFormat.get(), aEs.getEvalContext(), res);
477 NS_ENSURE_SUCCESS(rv, rv);
479 return aEs.mResultHandler->characters(res, false);
482 nsresult txPopParams::execute(txExecutionState& aEs) {
483 RefPtr<txParameterMap> paramMap = aEs.popParamMap();
485 return NS_OK;
488 txProcessingInstruction::txProcessingInstruction(UniquePtr<Expr>&& aName)
489 : mName(std::move(aName)) {}
491 nsresult txProcessingInstruction::execute(txExecutionState& aEs) {
492 UniquePtr<txTextHandler> handler(
493 static_cast<txTextHandler*>(aEs.popResultHandler()));
494 XMLUtils::normalizePIValue(handler->mValue);
496 nsAutoString name;
497 nsresult rv = mName->evaluateToString(aEs.getEvalContext(), name);
498 NS_ENSURE_SUCCESS(rv, rv);
500 // Check name validity (must be valid NCName and a PITarget)
501 // XXX Need to check for NCName and PITarget
502 const char16_t* colon;
503 if (!XMLUtils::isValidQName(name, &colon)) {
504 // XXX ErrorReport: bad PI-target
505 return NS_ERROR_FAILURE;
508 return aEs.mResultHandler->processingInstruction(name, handler->mValue);
511 txPushNewContext::txPushNewContext(UniquePtr<Expr>&& aSelect)
512 : mSelect(std::move(aSelect)), mBailTarget(nullptr) {}
514 txPushNewContext::~txPushNewContext() = default;
516 nsresult txPushNewContext::execute(txExecutionState& aEs) {
517 RefPtr<txAExprResult> exprRes;
518 nsresult rv =
519 mSelect->evaluate(aEs.getEvalContext(), getter_AddRefs(exprRes));
520 NS_ENSURE_SUCCESS(rv, rv);
522 if (exprRes->getResultType() != txAExprResult::NODESET) {
523 // XXX ErrorReport: nodeset expected
524 return NS_ERROR_XSLT_NODESET_EXPECTED;
527 txNodeSet* nodes =
528 static_cast<txNodeSet*>(static_cast<txAExprResult*>(exprRes));
530 if (nodes->isEmpty()) {
531 aEs.gotoInstruction(mBailTarget);
533 return NS_OK;
536 txNodeSorter sorter;
537 uint32_t i, count = mSortKeys.Length();
538 for (i = 0; i < count; ++i) {
539 SortKey& sort = mSortKeys[i];
540 rv = sorter.addSortElement(sort.mSelectExpr.get(), sort.mLangExpr.get(),
541 sort.mDataTypeExpr.get(), sort.mOrderExpr.get(),
542 sort.mCaseOrderExpr.get(), aEs.getEvalContext());
543 NS_ENSURE_SUCCESS(rv, rv);
545 RefPtr<txNodeSet> sortedNodes;
546 rv = sorter.sortNodeSet(nodes, &aEs, getter_AddRefs(sortedNodes));
547 NS_ENSURE_SUCCESS(rv, rv);
549 auto context = MakeUnique<txNodeSetContext>(sortedNodes, &aEs);
550 context->next();
552 aEs.pushEvalContext(context.release());
554 return NS_OK;
557 void txPushNewContext::addSort(UniquePtr<Expr>&& aSelectExpr,
558 UniquePtr<Expr>&& aLangExpr,
559 UniquePtr<Expr>&& aDataTypeExpr,
560 UniquePtr<Expr>&& aOrderExpr,
561 UniquePtr<Expr>&& aCaseOrderExpr) {
562 SortKey* key = mSortKeys.AppendElement();
563 // workaround for not triggering the Copy Constructor
564 key->mSelectExpr = std::move(aSelectExpr);
565 key->mLangExpr = std::move(aLangExpr);
566 key->mDataTypeExpr = std::move(aDataTypeExpr);
567 key->mOrderExpr = std::move(aOrderExpr);
568 key->mCaseOrderExpr = std::move(aCaseOrderExpr);
571 nsresult txPushNullTemplateRule::execute(txExecutionState& aEs) {
572 aEs.pushTemplateRule(nullptr, txExpandedName(), nullptr);
573 return NS_OK;
576 nsresult txPushParams::execute(txExecutionState& aEs) {
577 aEs.pushParamMap(nullptr);
578 return NS_OK;
581 nsresult txPushRTFHandler::execute(txExecutionState& aEs) {
582 aEs.pushResultHandler(new txRtfHandler);
584 return NS_OK;
587 txPushStringHandler::txPushStringHandler(bool aOnlyText)
588 : mOnlyText(aOnlyText) {}
590 nsresult txPushStringHandler::execute(txExecutionState& aEs) {
591 aEs.pushResultHandler(new txTextHandler(mOnlyText));
593 return NS_OK;
596 txRemoveVariable::txRemoveVariable(const txExpandedName& aName)
597 : mName(aName) {}
599 nsresult txRemoveVariable::execute(txExecutionState& aEs) {
600 aEs.removeVariable(mName);
602 return NS_OK;
605 nsresult txReturn::execute(txExecutionState& aEs) {
606 NS_ASSERTION(!mNext, "instructions exist after txReturn");
607 aEs.returnFromTemplate();
609 return NS_OK;
612 txSetParam::txSetParam(const txExpandedName& aName, UniquePtr<Expr>&& aValue)
613 : mName(aName), mValue(std::move(aValue)) {}
615 nsresult txSetParam::execute(txExecutionState& aEs) {
616 nsresult rv = NS_OK;
617 if (!aEs.mTemplateParams) {
618 aEs.mTemplateParams = new txParameterMap;
621 RefPtr<txAExprResult> exprRes;
622 if (mValue) {
623 rv = mValue->evaluate(aEs.getEvalContext(), getter_AddRefs(exprRes));
624 NS_ENSURE_SUCCESS(rv, rv);
625 } else {
626 UniquePtr<txRtfHandler> rtfHandler(
627 static_cast<txRtfHandler*>(aEs.popResultHandler()));
628 rv = rtfHandler->getAsRTF(getter_AddRefs(exprRes));
629 NS_ENSURE_SUCCESS(rv, rv);
632 rv = aEs.mTemplateParams->bindVariable(mName, exprRes);
633 NS_ENSURE_SUCCESS(rv, rv);
635 return NS_OK;
638 txSetVariable::txSetVariable(const txExpandedName& aName,
639 UniquePtr<Expr>&& aValue)
640 : mName(aName), mValue(std::move(aValue)) {}
642 nsresult txSetVariable::execute(txExecutionState& aEs) {
643 nsresult rv = NS_OK;
644 RefPtr<txAExprResult> exprRes;
645 if (mValue) {
646 rv = mValue->evaluate(aEs.getEvalContext(), getter_AddRefs(exprRes));
647 NS_ENSURE_SUCCESS(rv, rv);
648 } else {
649 UniquePtr<txRtfHandler> rtfHandler(
650 static_cast<txRtfHandler*>(aEs.popResultHandler()));
651 rv = rtfHandler->getAsRTF(getter_AddRefs(exprRes));
652 NS_ENSURE_SUCCESS(rv, rv);
655 return aEs.bindVariable(mName, exprRes);
658 txStartElement::txStartElement(UniquePtr<Expr>&& aName,
659 UniquePtr<Expr>&& aNamespace,
660 txNamespaceMap* aMappings)
661 : mName(std::move(aName)),
662 mNamespace(std::move(aNamespace)),
663 mMappings(aMappings) {}
665 nsresult txStartElement::execute(txExecutionState& aEs) {
666 nsAutoString name;
667 nsresult rv = mName->evaluateToString(aEs.getEvalContext(), name);
668 NS_ENSURE_SUCCESS(rv, rv);
670 int32_t nsId = kNameSpaceID_None;
671 RefPtr<nsAtom> prefix;
672 uint32_t lnameStart = 0;
674 const char16_t* colon;
675 if (XMLUtils::isValidQName(name, &colon)) {
676 if (colon) {
677 prefix = NS_Atomize(Substring(name.get(), colon));
678 lnameStart = colon - name.get() + 1;
681 if (mNamespace) {
682 nsAutoString nspace;
683 rv = mNamespace->evaluateToString(aEs.getEvalContext(), nspace);
684 NS_ENSURE_SUCCESS(rv, rv);
686 if (!nspace.IsEmpty()) {
687 nsId = txNamespaceManager::getNamespaceID(nspace);
689 } else {
690 nsId = mMappings->lookupNamespace(prefix);
692 } else {
693 nsId = kNameSpaceID_Unknown;
696 bool success = true;
698 if (nsId != kNameSpaceID_Unknown) {
699 rv = aEs.mResultHandler->startElement(prefix, Substring(name, lnameStart),
700 nsId);
701 } else {
702 rv = NS_ERROR_XSLT_BAD_NODE_NAME;
705 if (rv == NS_ERROR_XSLT_BAD_NODE_NAME) {
706 success = false;
707 // we call characters with an empty string to "close" any element to
708 // make sure that no attributes are added
709 rv = aEs.mResultHandler->characters(u""_ns, false);
711 NS_ENSURE_SUCCESS(rv, rv);
713 aEs.pushBool(success);
715 return NS_OK;
718 txStartLREElement::txStartLREElement(int32_t aNamespaceID, nsAtom* aLocalName,
719 nsAtom* aPrefix)
720 : mNamespaceID(aNamespaceID), mLocalName(aLocalName), mPrefix(aPrefix) {
721 if (aNamespaceID == kNameSpaceID_None) {
722 mLowercaseLocalName = TX_ToLowerCaseAtom(aLocalName);
726 nsresult txStartLREElement::execute(txExecutionState& aEs) {
727 nsresult rv = aEs.mResultHandler->startElement(
728 mPrefix, mLocalName, mLowercaseLocalName, mNamespaceID);
729 NS_ENSURE_SUCCESS(rv, rv);
731 aEs.pushBool(true);
733 return NS_OK;
736 txText::txText(const nsAString& aStr, bool aDOE) : mStr(aStr), mDOE(aDOE) {}
738 nsresult txText::execute(txExecutionState& aEs) {
739 return aEs.mResultHandler->characters(mStr, mDOE);
742 txValueOf::txValueOf(UniquePtr<Expr>&& aExpr, bool aDOE)
743 : mExpr(std::move(aExpr)), mDOE(aDOE) {}
745 nsresult txValueOf::execute(txExecutionState& aEs) {
746 RefPtr<txAExprResult> exprRes;
747 nsresult rv = mExpr->evaluate(aEs.getEvalContext(), getter_AddRefs(exprRes));
748 NS_ENSURE_SUCCESS(rv, rv);
750 const nsString* value = exprRes->stringValuePointer();
751 if (value) {
752 if (!value->IsEmpty()) {
753 return aEs.mResultHandler->characters(*value, mDOE);
755 } else {
756 nsAutoString valueStr;
757 exprRes->stringValue(valueStr);
758 if (!valueStr.IsEmpty()) {
759 return aEs.mResultHandler->characters(valueStr, mDOE);
763 return NS_OK;