/** * Execute a variable declaration and push it onto the variable stack. * * @see <a href="http://www.w3.org/TR/xslt#variables">variables in XSLT Specification</a> * @param transformer non-null reference to the the current transform-time state. * @throws javax.xml.transform.TransformerException */ public void execute(TransformerImpl transformer) throws TransformerException { if (transformer.getDebug()) transformer.getTraceManager().fireTraceEvent(this); int sourceNode = transformer.getXPathContext().getCurrentNode(); XObject var = getValue(transformer, sourceNode); // transformer.getXPathContext().getVarStack().pushVariable(m_qname, var); transformer.getXPathContext().getVarStack().setLocalVariable(m_index, var); if (transformer.getDebug()) transformer.getTraceManager().fireTraceEndEvent(this); }
/** * Get the XObject representation of the variable. * * @param transformer non-null reference to the the current transform-time state. * @param sourceNode non-null reference to the <a * href="http://www.w3.org/TR/xslt#dt-current-node">current source node</a>. * @return the XObject representation of the variable. * @throws javax.xml.transform.TransformerException */ public XObject getValue(TransformerImpl transformer, int sourceNode) throws TransformerException { XObject var; XPathContext xctxt = transformer.getXPathContext(); xctxt.pushCurrentNode(sourceNode); try { if (null != m_selectPattern) { var = m_selectPattern.execute(xctxt, sourceNode, this); var.allowDetachToRelease(false); if (transformer.getDebug()) transformer .getTraceManager() .fireSelectedEvent(sourceNode, this, "select", m_selectPattern, var); } else if (null == getFirstChildElem()) { var = XString.EMPTYSTRING; } else { // Use result tree fragment. // Global variables may be deferred (see XUnresolvedVariable) and hence // need to be assigned to a different set of DTMs than local variables // so they aren't popped off the stack on return from a template. int df; // Bugzilla 7118: A variable set via an RTF may create local // variables during that computation. To keep them from overwriting // variables at this level, push a new variable stack. ////// PROBLEM: This is provoking a variable-used-before-set ////// problem in parameters. Needs more study. try { ////////// xctxt.getVarStack().link(0); if (m_parentNode instanceof Stylesheet) // Global variable df = transformer.transformToGlobalRTF(this); else df = transformer.transformToRTF(this); } finally { ////////////// xctxt.getVarStack().unlink(); } var = new XRTreeFrag(df, xctxt, this); } } finally { xctxt.popCurrentNode(); } return var; }
/** * Perform a query if needed, and call transformNode for each child. * * @param transformer non-null reference to the the current transform-time state. * @throws TransformerException Thrown in a variety of circumstances. * @xsl.usage advanced */ public void transformSelectedNodes(TransformerImpl transformer) throws TransformerException { final XPathContext xctxt = transformer.getXPathContext(); final int sourceNode = xctxt.getCurrentNode(); DTMIterator sourceNodes = m_selectExpression.asIterator(xctxt, sourceNode); try { final Vector keys = (m_sortElems == null) ? null : transformer.processSortKeys(this, sourceNode); // Sort if we need to. if (null != keys) sourceNodes = sortNodes(xctxt, keys, sourceNodes); if (transformer.getDebug()) { // The original code, which is broken for bug#16889, // which fails to get the original select expression in the select event. /* transformer.getTraceManager().fireSelectedEvent( * sourceNode, * this, * "select", * new XPath(m_selectExpression), * new org.apache.xpath.objects.XNodeSet(sourceNodes)); */ // The following code fixes bug#16889 // Solution: Store away XPath in setSelect(Xath), and use it here. // Pass m_xath, which the current node is associated with, onto the TraceManager. Expression expr = m_xpath.getExpression(); org.apache.xpath.objects.XObject xObject = expr.execute(xctxt); int current = xctxt.getCurrentNode(); transformer.getTraceManager().fireSelectedEvent(current, this, "select", m_xpath, xObject); } xctxt.pushCurrentNode(DTM.NULL); IntStack currentNodes = xctxt.getCurrentNodeStack(); xctxt.pushCurrentExpressionNode(DTM.NULL); IntStack currentExpressionNodes = xctxt.getCurrentExpressionNodeStack(); xctxt.pushSAXLocatorNull(); xctxt.pushContextNodeList(sourceNodes); transformer.pushElemTemplateElement(null); // pushParams(transformer, xctxt); // Should be able to get this from the iterator but there must be a bug. DTM dtm = xctxt.getDTM(sourceNode); int docID = sourceNode & DTMManager.IDENT_DTM_DEFAULT; int child; while (DTM.NULL != (child = sourceNodes.nextNode())) { currentNodes.setTop(child); currentExpressionNodes.setTop(child); if ((child & DTMManager.IDENT_DTM_DEFAULT) != docID) { dtm = xctxt.getDTM(child); docID = child & DTMManager.IDENT_DTM_DEFAULT; } // final int exNodeType = dtm.getExpandedTypeID(child); final int nodeType = dtm.getNodeType(child); // Fire a trace event for the template. if (transformer.getDebug()) { transformer.getTraceManager().fireTraceEvent(this); } // And execute the child templates. // Loop through the children of the template, calling execute on // each of them. for (ElemTemplateElement t = this.m_firstChild; t != null; t = t.m_nextSibling) { xctxt.setSAXLocator(t); transformer.setCurrentElement(t); t.execute(transformer); } if (transformer.getDebug()) { // We need to make sure an old current element is not // on the stack. See TransformerImpl#getElementCallstack. transformer.setCurrentElement(null); transformer.getTraceManager().fireTraceEndEvent(this); } // KLUGE: Implement <?xalan:doc_cache_off?> // ASSUMPTION: This will be set only when the XPath was indeed // a call to the Document() function. Calling it in other // situations is likely to fry Xalan. // // %REVIEW% We need a MUCH cleaner solution -- one that will // handle cleaning up after document() and getDTM() in other // contexts. The whole SourceTreeManager mechanism should probably // be moved into DTMManager rather than being explicitly invoked in // FuncDocument and here. if (m_doc_cache_off) { if (DEBUG) System.out.println( "JJK***** CACHE RELEASE *****\n" + "\tdtm=" + dtm.getDocumentBaseURI()); // NOTE: This will work because this is _NOT_ a shared DTM, and thus has // only a single Document node. If it could ever be an RTF or other // shared DTM, this would require substantial rework. xctxt.getSourceTreeManager().removeDocumentFromCache(dtm.getDocument()); xctxt.release(dtm, false); } } } finally { if (transformer.getDebug()) transformer .getTraceManager() .fireSelectedEndEvent( sourceNode, this, "select", new XPath(m_selectExpression), new org.apache.xpath.objects.XNodeSet(sourceNodes)); xctxt.popSAXLocator(); xctxt.popContextNodeList(); transformer.popElemTemplateElement(); xctxt.popCurrentExpressionNode(); xctxt.popCurrentNode(); sourceNodes.detach(); } }
/** * Copy a Literal Result Element into the Result tree, copy the non-excluded namespace attributes, * copy the attributes not of the XSLT namespace, and execute the children of the LRE. * * @see <a href="http://www.w3.org/TR/xslt#literal-result-element">literal-result-element in XSLT * Specification</a> * @param transformer non-null reference to the the current transform-time state. * @throws TransformerException */ public void execute(TransformerImpl transformer) throws TransformerException { SerializationHandler rhandler = transformer.getSerializationHandler(); try { // JJK Bugzilla 3464, test namespace85 -- make sure LRE's // namespace is asserted even if default, since xsl:element // may have changed the context. rhandler.startPrefixMapping(getPrefix(), getNamespace()); // Add namespace declarations. executeNSDecls(transformer); rhandler.startElement(getNamespace(), getLocalName(), getRawName()); } catch (SAXException se) { throw new TransformerException(se); } /* * If we make it to here we have done a successful startElement() * we will do an endElement() call for balance, no matter what happens * in the middle. */ // tException remembers if we had an exception "in the middle" TransformerException tException = null; try { // Process any possible attributes from xsl:use-attribute-sets first super.execute(transformer); // xsl:version, excludeResultPrefixes??? // Process the list of avts next if (null != m_avts) { int nAttrs = m_avts.size(); for (int i = (nAttrs - 1); i >= 0; i--) { AVT avt = (AVT) m_avts.get(i); XPathContext xctxt = transformer.getXPathContext(); int sourceNode = xctxt.getCurrentNode(); String stringedValue = avt.evaluate(xctxt, sourceNode, this); if (null != stringedValue) { // Important Note: I'm not going to check for excluded namespace // prefixes here. It seems like it's too expensive, and I'm not // even sure this is right. But I could be wrong, so this needs // to be tested against other implementations. rhandler.addAttribute( avt.getURI(), avt.getName(), avt.getRawName(), "CDATA", stringedValue, false); } } // end for } // Now process all the elements in this subtree // TODO: Process m_extensionElementPrefixes && m_attributeSetsNames transformer.executeChildTemplates(this, true); } catch (TransformerException te) { // thrown in finally to prevent original exception consumed by subsequent exceptions tException = te; } catch (SAXException se) { tException = new TransformerException(se); } try { /* we need to do this endElement() to balance the * successful startElement() call even if * there was an exception in the middle. * Otherwise an exception in the middle could cause a system to hang. */ rhandler.endElement(getNamespace(), getLocalName(), getRawName()); } catch (SAXException se) { /* we did call endElement(). If thee was an exception * in the middle throw that one, otherwise if there * was an exception from endElement() throw that one. */ if (tException != null) throw tException; else throw new TransformerException(se); } /* If an exception was thrown in the middle but not with startElement() or * or endElement() then its time to let it percolate. */ if (tException != null) throw tException; unexecuteNSDecls(transformer); // JJK Bugzilla 3464, test namespace85 -- balance explicit start. try { rhandler.endPrefixMapping(getPrefix()); } catch (SAXException se) { throw new TransformerException(se); } }
/** * <meta name="usage" content="advanced"/> Perform a query if needed, and call transformNode for * each child. * * @param transformer non-null reference to the the current transform-time state. * @param template The owning template context. * @throws TransformerException Thrown in a variety of circumstances. */ public void transformSelectedNodes(TransformerImpl transformer) throws TransformerException { final XPathContext xctxt = transformer.getXPathContext(); final int sourceNode = xctxt.getCurrentNode(); DTMIterator sourceNodes = m_selectExpression.asIterator(xctxt, sourceNode); VariableStack vars = xctxt.getVarStack(); int nParams = getParamElemCount(); int thisframe = vars.getStackFrame(); StackGuard guard = transformer.getStackGuard(); boolean check = (guard.getRecursionLimit() > -1) ? true : false; try { final Vector keys = (m_sortElems == null) ? null : transformer.processSortKeys(this, sourceNode); // Sort if we need to. if (null != keys) sourceNodes = sortNodes(xctxt, keys, sourceNodes); if (TransformerImpl.S_DEBUG) { transformer .getTraceManager() .fireSelectedEvent( sourceNode, this, "select", new XPath(m_selectExpression), new org.apache.xpath.objects.XNodeSet(sourceNodes)); } final ResultTreeHandler rth = transformer.getResultTreeHandler(); ContentHandler chandler = rth.getContentHandler(); final StylesheetRoot sroot = transformer.getStylesheet(); final TemplateList tl = sroot.getTemplateListComposed(); final boolean quiet = transformer.getQuietConflictWarnings(); // Should be able to get this from the iterator but there must be a bug. DTM dtm = xctxt.getDTM(sourceNode); int argsFrame = -1; if (nParams > 0) { // This code will create a section on the stack that is all the // evaluated arguments. These will be copied into the real params // section of each called template. argsFrame = vars.link(nParams); vars.setStackFrame(thisframe); for (int i = 0; i < nParams; i++) { ElemWithParam ewp = m_paramElems[i]; XObject obj = ewp.getValue(transformer, sourceNode); vars.setLocalVariable(i, obj, argsFrame); } vars.setStackFrame(argsFrame); } xctxt.pushCurrentNode(DTM.NULL); IntStack currentNodes = xctxt.getCurrentNodeStack(); xctxt.pushCurrentExpressionNode(DTM.NULL); IntStack currentExpressionNodes = xctxt.getCurrentExpressionNodeStack(); xctxt.pushSAXLocatorNull(); xctxt.pushContextNodeList(sourceNodes); transformer.pushElemTemplateElement(null); // pushParams(transformer, xctxt); int child; while (DTM.NULL != (child = sourceNodes.nextNode())) { currentNodes.setTop(child); currentExpressionNodes.setTop(child); if (xctxt.getDTM(child) != dtm) { dtm = xctxt.getDTM(child); } final int exNodeType = dtm.getExpandedTypeID(child); final int nodeType = dtm.getNodeType(child); final QName mode = transformer.getMode(); ElemTemplate template = tl.getTemplateFast(xctxt, child, exNodeType, mode, -1, quiet, dtm); // If that didn't locate a node, fall back to a default template rule. // See http://www.w3.org/TR/xslt#built-in-rule. if (null == template) { switch (nodeType) { case DTM.DOCUMENT_FRAGMENT_NODE: case DTM.ELEMENT_NODE: template = sroot.getDefaultRule(); // %OPT% direct faster? break; case DTM.ATTRIBUTE_NODE: case DTM.CDATA_SECTION_NODE: case DTM.TEXT_NODE: // if(rth.m_elemIsPending || rth.m_docPending) // rth.flushPending(true); transformer.pushPairCurrentMatched(sroot.getDefaultTextRule(), child); transformer.setCurrentElement(sroot.getDefaultTextRule()); // dtm.dispatchCharactersEvents(child, chandler, false); dtm.dispatchCharactersEvents(child, rth, false); transformer.popCurrentMatched(); continue; case DTM.DOCUMENT_NODE: template = sroot.getDefaultRootRule(); break; default: // No default rules for processing instructions and the like. continue; } } else { transformer.setCurrentElement(template); } transformer.pushPairCurrentMatched(template, child); if (check) guard.checkForInfinateLoop(); int currentFrameBottom; // See comment with unlink, below if (template.m_frameSize > 0) { xctxt.pushRTFContext(); currentFrameBottom = vars.getStackFrame(); // See comment with unlink, below vars.link(template.m_frameSize); // You can't do the check for nParams here, otherwise the // xsl:params might not be nulled. if ( /* nParams > 0 && */ template.m_inArgsSize > 0) { int paramIndex = 0; for (ElemTemplateElement elem = template.getFirstChildElem(); null != elem; elem = elem.getNextSiblingElem()) { if (Constants.ELEMNAME_PARAMVARIABLE == elem.getXSLToken()) { ElemParam ep = (ElemParam) elem; int i; for (i = 0; i < nParams; i++) { ElemWithParam ewp = m_paramElems[i]; if (ewp.m_qnameID == ep.m_qnameID) { XObject obj = vars.getLocalVariable(i, argsFrame); vars.setLocalVariable(paramIndex, obj); break; } } if (i == nParams) vars.setLocalVariable(paramIndex, null); } else break; paramIndex++; } } } else currentFrameBottom = 0; // Fire a trace event for the template. if (TransformerImpl.S_DEBUG) transformer.getTraceManager().fireTraceEvent(template); // And execute the child templates. // Loop through the children of the template, calling execute on // each of them. for (ElemTemplateElement t = template.m_firstChild; t != null; t = t.m_nextSibling) { xctxt.setSAXLocator(t); try { transformer.pushElemTemplateElement(t); t.execute(transformer); } finally { transformer.popElemTemplateElement(); } } if (TransformerImpl.S_DEBUG) transformer.getTraceManager().fireTraceEndEvent(template); if (template.m_frameSize > 0) { // See Frank Weiss bug around 03/19/2002 (no Bugzilla report yet). // While unlink will restore to the proper place, the real position // may have been changed for xsl:with-param, so that variables // can be accessed. // of right now. // More: // When we entered this function, the current // frame buffer (cfb) index in the variable stack may // have been manually set. If we just call // unlink(), however, it will restore the cfb to the // previous link index from the link stack, rather than // the manually set cfb. So, // the only safe solution is to restore it back // to the same position it was on entry, since we're // really not working in a stack context here. (Bug4218) vars.unlink(currentFrameBottom); xctxt.popRTFContext(); } transformer.popCurrentMatched(); } // end while (DTM.NULL != (child = sourceNodes.nextNode())) } catch (SAXException se) { transformer.getErrorListener().fatalError(new TransformerException(se)); } finally { if (TransformerImpl.S_DEBUG) transformer .getTraceManager() .fireSelectedEndEvent( sourceNode, this, "select", new XPath(m_selectExpression), new org.apache.xpath.objects.XNodeSet(sourceNodes)); // Unlink to the original stack frame if (nParams > 0) vars.unlink(thisframe); xctxt.popSAXLocator(); xctxt.popContextNodeList(); transformer.popElemTemplateElement(); xctxt.popCurrentExpressionNode(); xctxt.popCurrentNode(); sourceNodes.detach(); } }
/** * Invoke a named template. * * @see <a href="http://www.w3.org/TR/xslt#named-templates">named-templates in XSLT * Specification</a> * @param transformer non-null reference to the the current transform-time state. * @throws TransformerException */ public void execute(TransformerImpl transformer) throws TransformerException { if (null != m_template) { XPathContext xctxt = transformer.getXPathContext(); VariableStack vars = xctxt.getVarStack(); int thisframe = vars.getStackFrame(); int nextFrame = vars.link(m_template.m_frameSize); // We have to clear the section of the stack frame that has params // so that the default param evaluation will work correctly. if (m_template.m_inArgsSize > 0) { vars.clearLocalSlots(0, m_template.m_inArgsSize); if (null != m_paramElems) { int currentNode = xctxt.getCurrentNode(); vars.setStackFrame(thisframe); int size = m_paramElems.length; for (int i = 0; i < size; i++) { ElemWithParam ewp = m_paramElems[i]; if (ewp.m_index >= 0) { XObject obj = ewp.getValue(transformer, currentNode); // Note here that the index for ElemWithParam must have been // statically made relative to the xsl:template being called, // NOT this xsl:template. vars.setLocalVariable(ewp.m_index, obj, nextFrame); } } vars.setStackFrame(nextFrame); } } SourceLocator savedLocator = xctxt.getSAXLocator(); try { xctxt.setSAXLocator(m_template); // template.executeChildTemplates(transformer, sourceNode, mode, true); transformer.pushElemTemplateElement(m_template); m_template.execute(transformer); } finally { transformer.popElemTemplateElement(); xctxt.setSAXLocator(savedLocator); // When we entered this function, the current // frame buffer (cfb) index in the variable stack may // have been manually set. If we just call // unlink(), however, it will restore the cfb to the // previous link index from the link stack, rather than // the manually set cfb. So, // the only safe solution is to restore it back // to the same position it was on entry, since we're // really not working in a stack context here. (Bug4218) vars.unlink(thisframe); } } else { transformer .getMsgMgr() .error( this, XSLTErrorResources.ER_TEMPLATE_NOT_FOUND, new Object[] { m_templateName }); // "Could not find template named: '"+templateName+"'"); } }