/** * This function is called after everything else has been recomposed, and allows the template to * set remaining values that may be based on some other property that depends on recomposition. */ public void compose(StylesheetRoot sroot) throws TransformerException { // See if we can reduce an RTF to a select with a string expression. if (null == m_selectPattern && sroot.getOptimizer()) { XPath newSelect = rewriteChildToExpression(this); if (null != newSelect) m_selectPattern = newSelect; } StylesheetRoot.ComposeState cstate = sroot.getComposeState(); // This should be done before addVariableName, so we don't have visibility // to the variable now being defined. java.util.Vector vnames = cstate.getVariableNames(); if (null != m_selectPattern) m_selectPattern.fixupVariables(vnames, cstate.getGlobalsSize()); // Only add the variable if this is not a global. If it is a global, // it was already added by stylesheet root. if (!(m_parentNode instanceof Stylesheet) && m_qname != null) { m_index = cstate.addVariableName(m_qname) - cstate.getGlobalsSize(); } else if (m_parentNode instanceof Stylesheet) { // If this is a global, then we need to treat it as if it's a xsl:template, // and count the number of variables it contains. So we set the count to // zero here. cstate.resetStackFrameSize(); } // This has to be done after the addVariableName, so that the variable // pushed won't be immediately popped again in endCompose. super.compose(sroot); }
/** * Set the "select" attribute. * * @param xpath The XPath expression for the "select" attribute. */ public void setSelect(XPath xpath) { m_selectExpression = xpath.getExpression(); // The following line is part of the codes added to fix bug#16889 // Store xpath which will be needed when firing Selected Event m_xpath = xpath; }
/** * 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; }
/** * Evaluate XPath string to an XObject. XPath namespace prefixes are resolved from the * namespaceNode. The implementation of this is a little slow, since it creates a number of * objects each time it is called. This could be optimized to keep the same objects around, but * then thread-safety issues would arise. * * @param contextNode The node to start searching from. * @param xpathnode * @param str * @param prefixResolver Will be called if the parser encounters namespace prefixes, to resolve * the prefixes to URLs. * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never * be null. * @see org.apache.xpath.objects.XObject * @see org.apache.xpath.objects.XNull * @see org.apache.xpath.objects.XBoolean * @see org.apache.xpath.objects.XNumber * @see org.apache.xpath.objects.XString * @see org.apache.xpath.objects.XRTreeFrag * @throws TransformerException */ public XObject eval(Node contextNode, Node xpathnode, String str, PrefixResolver prefixResolver) throws TransformerException { // Since we don't have a XML Parser involved here, install some default support // for things like namespaces, etc. // (Changed from: XPathContext xpathSupport = new XPathContext(); // because XPathContext is weak in a number of areas... perhaps // XPathContext should be done away with.) // Create the XPath object. // String str = CachedXPathFuncHereAPI.getStrFromNode(xpathnode); // only check if string points to different object (for performance) if (str != xpathStr) { if (str.indexOf("here()") > 0) { _context.reset(); _dtmManager = _context.getDTMManager(); } try { xpath = createXPath(str, prefixResolver); } catch (TransformerException ex) { // Try to see if it is a problem with the classloader. Throwable th = ex.getCause(); if (th instanceof ClassNotFoundException) { if (th.getMessage().indexOf("FuncHere") > 0) { throw new RuntimeException(I18n.translate("endorsed.jdk1.4.0") /*,*/ + ex); } } throw ex; } xpathStr = str; } // Execute the XPath, and have it return the result if (this._funcHereContext == null) { this._funcHereContext = new FuncHereContext(xpathnode, this._dtmManager); } int ctxtNode = this._funcHereContext.getDTMHandleFromNode(contextNode); return xpath.execute(this._funcHereContext, ctxtNode, prefixResolver); }
/** * Evaluate XPath string to an XObject. XPath namespace prefixes are resolved from the * namespaceNode. The implementation of this is a little slow, since it creates a number of * objects each time it is called. This could be optimized to keep the same objects around, but * then thread-safety issues would arise. * * @param contextNode The node to start searching from. * @param xpathnode * @param str * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces. * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never * be null. * @see org.apache.xpath.objects.XObject * @see org.apache.xpath.objects.XNull * @see org.apache.xpath.objects.XBoolean * @see org.apache.xpath.objects.XNumber * @see org.apache.xpath.objects.XString * @see org.apache.xpath.objects.XRTreeFrag * @throws TransformerException */ public XObject eval(Node contextNode, Node xpathnode, String str, Node namespaceNode) throws TransformerException { // Create the XPath object. // String str = CachedXPathFuncHereAPI.getStrFromNode(xpathnode); // Since we don't have a XML Parser involved here, install some default support // for things like namespaces, etc. // (Changed from: XPathContext xpathSupport = new XPathContext(); // because XPathContext is weak in a number of areas... perhaps // XPathContext should be done away with.) if (this._funcHereContext == null) { this._funcHereContext = new FuncHereContext(xpathnode, this._dtmManager); } // Create an object to resolve namespace prefixes. // XPath namespaces are resolved from the input context node's document element // if it is a root node, or else the current context node (for lack of a better // resolution space, given the simplicity of this sample code). PrefixResolverDefault prefixResolver = new PrefixResolverDefault( (namespaceNode.getNodeType() == Node.DOCUMENT_NODE) ? ((Document) namespaceNode).getDocumentElement() : namespaceNode); // only check if string points to different object (for performance) if (str != xpathStr) { if (str.indexOf("here()") > 0) { _context.reset(); _dtmManager = _context.getDTMManager(); } xpath = createXPath(str, prefixResolver); xpathStr = str; } // Execute the XPath, and have it return the result // return xpath.execute(xpathSupport, contextNode, prefixResolver); int ctxtNode = this._funcHereContext.getDTMHandleFromNode(contextNode); return xpath.execute(this._funcHereContext, ctxtNode, prefixResolver); }
/** * 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(); } }
/** * Call the children visitors. * * @param visitor The visitor whose appropriate method will be called. */ protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs) { if (null != m_selectPattern) m_selectPattern.getExpression().callVisitors(m_selectPattern, visitor); super.callChildVisitors(visitor, callAttrs); }