/**
   * 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);
  }
Exemple #2
0
  /**
   * 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);
  }
Exemple #6
0
  /**
   * 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);
 }