alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (ExsltDynamic.java)

This example Java source code file (ExsltDynamic.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

document, dom, exsltbase, invalid, nodelist, nodeset, nodesetdtm, object, parser, sax, saxnotsupportedexception, string, transformerexception, xml, xnodeset, xobject, xpath, xpathcontext

The ExsltDynamic.java Java example source code

/*
 * reserved comment block
 * DO NOT REMOVE OR ALTER!
 */
/*
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * $Id: ExsltDynamic.java,v 1.1.2.1 2005/08/01 02:08:51 jeffsuttor Exp $
 */
package com.sun.org.apache.xalan.internal.lib;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.TransformerException;

import com.sun.org.apache.xalan.internal.extensions.ExpressionContext;
import com.sun.org.apache.xalan.internal.res.XSLMessages;
import com.sun.org.apache.xalan.internal.res.XSLTErrorResources;
import com.sun.org.apache.xpath.internal.NodeSet;
import com.sun.org.apache.xpath.internal.NodeSetDTM;
import com.sun.org.apache.xpath.internal.XPath;
import com.sun.org.apache.xpath.internal.XPathContext;
import com.sun.org.apache.xpath.internal.objects.XBoolean;
import com.sun.org.apache.xpath.internal.objects.XNodeSet;
import com.sun.org.apache.xpath.internal.objects.XNumber;
import com.sun.org.apache.xpath.internal.objects.XObject;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

import org.xml.sax.SAXNotSupportedException;

/**
 * This class contains EXSLT dynamic extension functions.
 *
 * It is accessed by specifying a namespace URI as follows:
 * <pre>
 *    xmlns:dyn="http://exslt.org/dynamic"
 * </pre>
 * The documentation for each function has been copied from the relevant
 * EXSLT Implementer page.
 *
 * @see <a href="http://www.exslt.org/">EXSLT

 * @xsl.usage general
 */
public class ExsltDynamic extends ExsltBase
{

   public static final String EXSL_URI = "http://exslt.org/common";

  /**
   * The dyn:max function calculates the maximum value for the nodes passed as
   * the first argument, where the value of each node is calculated dynamically
   * using an XPath expression passed as a string as the second argument.
   * <p>
   * The expressions are evaluated relative to the nodes passed as the first argument.
   * In other words, the value for each node is calculated by evaluating the XPath
   * expression with all context information being the same as that for the call to
   * the dyn:max function itself, except for the following:
   * <p>
   * <ul>
   *  <li>the context node is the node whose value is being calculated.
   *  <li>the context position is the position of the node within the node set passed as
   *   the first argument to the dyn:max function, arranged in document order.</li>
   *  <li>the context size is the number of nodes passed as the first argument to the
   *   dyn:max function.</li>
   * </ul>
   * <p>
   * The dyn:max function returns the maximum of these values, calculated in exactly
   * the same way as for math:max.
   * <p>
   * If the expression string passed as the second argument is an invalid XPath
   * expression (including an empty string), this function returns NaN.
   * <p>
   * This function must take a second argument. To calculate the maximum of a set of
   * nodes based on their string values, you should use the math:max function.
   *
   * @param myContext The ExpressionContext passed by the extension processor
   * @param nl The node set
   * @param expr The expression string
   *
   * @return The maximum evaluation value
   */
  public static double max(ExpressionContext myContext, NodeList nl, String expr)
    throws SAXNotSupportedException
  {

    XPathContext xctxt = null;
    if (myContext instanceof XPathContext.XPathExpressionContext)
      xctxt = ((XPathContext.XPathExpressionContext) myContext).getXPathContext();
    else
      throw new SAXNotSupportedException(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_CONTEXT_PASSED, new Object[]{myContext }));

    if (expr == null || expr.length() == 0)
      return Double.NaN;

    NodeSetDTM contextNodes = new NodeSetDTM(nl, xctxt);
    xctxt.pushContextNodeList(contextNodes);

    double maxValue = - Double.MAX_VALUE;
    for (int i = 0; i < contextNodes.getLength(); i++)
    {
      int contextNode = contextNodes.item(i);
      xctxt.pushCurrentNode(contextNode);

      double result = 0;
      try
      {
        XPath dynamicXPath = new XPath(expr, xctxt.getSAXLocator(),
                                       xctxt.getNamespaceContext(),
                                       XPath.SELECT);
        result = dynamicXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext()).num();
      }
      catch (TransformerException e)
      {
        xctxt.popCurrentNode();
        xctxt.popContextNodeList();
        return Double.NaN;
      }

      xctxt.popCurrentNode();

      if (result > maxValue)
          maxValue = result;
    }

    xctxt.popContextNodeList();
    return maxValue;

  }

  /**
   * The dyn:min function calculates the minimum value for the nodes passed as the
   * first argument, where the value of each node is calculated dynamically using
   * an XPath expression passed as a string as the second argument.
   * <p>
   * The expressions are evaluated relative to the nodes passed as the first argument.
   * In other words, the value for each node is calculated by evaluating the XPath
   * expression with all context information being the same as that for the call to
   * the dyn:min function itself, except for the following:
   * <p>
   * <ul>
   *  <li>the context node is the node whose value is being calculated.
   *  <li>the context position is the position of the node within the node set passed
   *    as the first argument to the dyn:min function, arranged in document order.</li>
   *  <li>the context size is the number of nodes passed as the first argument to the
   *    dyn:min function.</li>
   * </ul>
   * <p>
   * The dyn:min function returns the minimum of these values, calculated in exactly
   * the same way as for math:min.
   * <p>
   * If the expression string passed as the second argument is an invalid XPath expression
   * (including an empty string), this function returns NaN.
   * <p>
   * This function must take a second argument. To calculate the minimum of a set of
   * nodes based on their string values, you should use the math:min function.
   *
   * @param myContext The ExpressionContext passed by the extension processor
   * @param nl The node set
   * @param expr The expression string
   *
   * @return The minimum evaluation value
   */
  public static double min(ExpressionContext myContext, NodeList nl, String expr)
    throws SAXNotSupportedException
  {

    XPathContext xctxt = null;
    if (myContext instanceof XPathContext.XPathExpressionContext)
      xctxt = ((XPathContext.XPathExpressionContext) myContext).getXPathContext();
    else
      throw new SAXNotSupportedException(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_CONTEXT_PASSED, new Object[]{myContext }));

    if (expr == null || expr.length() == 0)
      return Double.NaN;

    NodeSetDTM contextNodes = new NodeSetDTM(nl, xctxt);
    xctxt.pushContextNodeList(contextNodes);

    double minValue = Double.MAX_VALUE;
    for (int i = 0; i < nl.getLength(); i++)
    {
      int contextNode = contextNodes.item(i);
      xctxt.pushCurrentNode(contextNode);

      double result = 0;
      try
      {
        XPath dynamicXPath = new XPath(expr, xctxt.getSAXLocator(),
                                       xctxt.getNamespaceContext(),
                                       XPath.SELECT);
        result = dynamicXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext()).num();
      }
      catch (TransformerException e)
      {
        xctxt.popCurrentNode();
        xctxt.popContextNodeList();
        return Double.NaN;
      }

      xctxt.popCurrentNode();

      if (result < minValue)
          minValue = result;
    }

    xctxt.popContextNodeList();
    return minValue;

  }

  /**
   * The dyn:sum function calculates the sum for the nodes passed as the first argument,
   * where the value of each node is calculated dynamically using an XPath expression
   * passed as a string as the second argument.
   * <p>
   * The expressions are evaluated relative to the nodes passed as the first argument.
   * In other words, the value for each node is calculated by evaluating the XPath
   * expression with all context information being the same as that for the call to
   * the dyn:sum function itself, except for the following:
   * <p>
   * <ul>
   *  <li>the context node is the node whose value is being calculated.
   *  <li>the context position is the position of the node within the node set passed as
   *    the first argument to the dyn:sum function, arranged in document order.</li>
   *  <li>the context size is the number of nodes passed as the first argument to the
   *    dyn:sum function.</li>
   * </ul>
   * <p>
   * The dyn:sum function returns the sumimum of these values, calculated in exactly
   * the same way as for sum.
   * <p>
   * If the expression string passed as the second argument is an invalid XPath
   * expression (including an empty string), this function returns NaN.
   * <p>
   * This function must take a second argument. To calculate the sumimum of a set of
   * nodes based on their string values, you should use the sum function.
   *
   * @param myContext The ExpressionContext passed by the extension processor
   * @param nl The node set
   * @param expr The expression string
   *
   * @return The sum of the evaluation value on each node
   */
  public static double sum(ExpressionContext myContext, NodeList nl, String expr)
    throws SAXNotSupportedException
  {
    XPathContext xctxt = null;
    if (myContext instanceof XPathContext.XPathExpressionContext)
      xctxt = ((XPathContext.XPathExpressionContext) myContext).getXPathContext();
    else
      throw new SAXNotSupportedException(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_CONTEXT_PASSED, new Object[]{myContext }));

    if (expr == null || expr.length() == 0)
      return Double.NaN;

    NodeSetDTM contextNodes = new NodeSetDTM(nl, xctxt);
    xctxt.pushContextNodeList(contextNodes);

    double sum = 0;
    for (int i = 0; i < nl.getLength(); i++)
    {
      int contextNode = contextNodes.item(i);
      xctxt.pushCurrentNode(contextNode);

      double result = 0;
      try
      {
        XPath dynamicXPath = new XPath(expr, xctxt.getSAXLocator(),
                                       xctxt.getNamespaceContext(),
                                       XPath.SELECT);
        result = dynamicXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext()).num();
      }
      catch (TransformerException e)
      {
        xctxt.popCurrentNode();
        xctxt.popContextNodeList();
        return Double.NaN;
      }

      xctxt.popCurrentNode();

      sum = sum + result;

    }

    xctxt.popContextNodeList();
    return sum;
  }

  /**
   * The dyn:map function evaluates the expression passed as the second argument for
   * each of the nodes passed as the first argument, and returns a node set of those values.
   * <p>
   * The expressions are evaluated relative to the nodes passed as the first argument.
   * In other words, the value for each node is calculated by evaluating the XPath
   * expression with all context information being the same as that for the call to
   * the dyn:map function itself, except for the following:
   * <p>
   * <ul>
   *  <li>The context node is the node whose value is being calculated.
   *  <li>the context position is the position of the node within the node set passed
   *    as the first argument to the dyn:map function, arranged in document order.</li>
   *  <li>the context size is the number of nodes passed as the first argument to the
   *    dyn:map function.</li>
   * </ul>
   * <p>
   * If the expression string passed as the second argument is an invalid XPath
   * expression (including an empty string), this function returns an empty node set.
   * <p>
   * If the XPath expression evaluates as a node set, the dyn:map function returns
   * the union of the node sets returned by evaluating the expression for each of the
   * nodes in the first argument. Note that this may mean that the node set resulting
   * from the call to the dyn:map function contains a different number of nodes from
   * the number in the node set passed as the first argument to the function.
   * <p>
   * If the XPath expression evaluates as a number, the dyn:map function returns a
   * node set containing one exsl:number element (namespace http://exslt.org/common)
   * for each node in the node set passed as the first argument to the dyn:map function,
   * in document order. The string value of each exsl:number element is the same as
   * the result of converting the number resulting from evaluating the expression to
   * a string as with the number function, with the exception that Infinity results
   * in an exsl:number holding the highest number the implementation can store, and
   * -Infinity results in an exsl:number holding the lowest number the implementation
   * can store.
   * <p>
   * If the XPath expression evaluates as a boolean, the dyn:map function returns a
   * node set containing one exsl:boolean element (namespace http://exslt.org/common)
   * for each node in the node set passed as the first argument to the dyn:map function,
   * in document order. The string value of each exsl:boolean element is 'true' if the
   * expression evaluates as true for the node, and '' if the expression evaluates as
   * false.
   * <p>
   * Otherwise, the dyn:map function returns a node set containing one exsl:string
   * element (namespace http://exslt.org/common) for each node in the node set passed
   * as the first argument to the dyn:map function, in document order. The string
   * value of each exsl:string element is the same as the result of converting the
   * result of evaluating the expression for the relevant node to a string as with
   * the string function.
   *
   * @param myContext The ExpressionContext passed by the extension processor
   * @param nl The node set
   * @param expr The expression string
   *
   * @return The node set after evaluation
   */
  public static NodeList map(ExpressionContext myContext, NodeList nl, String expr)
    throws SAXNotSupportedException
  {
    XPathContext xctxt = null;
    Document lDoc = null;

    if (myContext instanceof XPathContext.XPathExpressionContext)
      xctxt = ((XPathContext.XPathExpressionContext) myContext).getXPathContext();
    else
      throw new SAXNotSupportedException(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_CONTEXT_PASSED, new Object[]{myContext }));

    if (expr == null || expr.length() == 0)
      return new NodeSet();

    NodeSetDTM contextNodes = new NodeSetDTM(nl, xctxt);
    xctxt.pushContextNodeList(contextNodes);

    NodeSet resultSet = new NodeSet();
    resultSet.setShouldCacheNodes(true);

    for (int i = 0; i < nl.getLength(); i++)
    {
      int contextNode = contextNodes.item(i);
      xctxt.pushCurrentNode(contextNode);

      XObject object = null;
      try
      {
        XPath dynamicXPath = new XPath(expr, xctxt.getSAXLocator(),
                                       xctxt.getNamespaceContext(),
                                       XPath.SELECT);
        object = dynamicXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext());

        if (object instanceof XNodeSet)
        {
          NodeList nodelist = null;
          nodelist = ((XNodeSet)object).nodelist();

          for (int k = 0; k < nodelist.getLength(); k++)
          {
            Node n = nodelist.item(k);
            if (!resultSet.contains(n))
              resultSet.addNode(n);
          }
        }
        else
        {
          if (lDoc == null)
          {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware(true);
            DocumentBuilder db = dbf.newDocumentBuilder();
            lDoc = db.newDocument();
          }

          Element element = null;
          if (object instanceof XNumber)
            element = lDoc.createElementNS(EXSL_URI, "exsl:number");
          else if (object instanceof XBoolean)
            element = lDoc.createElementNS(EXSL_URI, "exsl:boolean");
          else
            element = lDoc.createElementNS(EXSL_URI, "exsl:string");

          Text textNode = lDoc.createTextNode(object.str());
          element.appendChild(textNode);
          resultSet.addNode(element);
        }
      }
      catch (Exception e)
      {
        xctxt.popCurrentNode();
        xctxt.popContextNodeList();
        return new NodeSet();
      }

      xctxt.popCurrentNode();

    }

    xctxt.popContextNodeList();
    return resultSet;
  }

  /**
   * The dyn:evaluate function evaluates a string as an XPath expression and returns
   * the resulting value, which might be a boolean, number, string, node set, result
   * tree fragment or external object. The sole argument is the string to be evaluated.
   * <p>
   * If the expression string passed as the second argument is an invalid XPath
   * expression (including an empty string), this function returns an empty node set.
   * <p>
   * You should only use this function if the expression must be constructed dynamically,
   * otherwise it is much more efficient to use the expression literally.
   *
   * @param myContext The ExpressionContext passed by the extension processor
   * @param xpathExpr The XPath expression string
   *
   * @return The evaluation result
   */
  public static XObject evaluate(ExpressionContext myContext, String xpathExpr)
    throws SAXNotSupportedException
  {
    if (myContext instanceof XPathContext.XPathExpressionContext)
    {
      XPathContext xctxt = null;
      try
      {
        xctxt = ((XPathContext.XPathExpressionContext) myContext).getXPathContext();
        XPath dynamicXPath = new XPath(xpathExpr, xctxt.getSAXLocator(),
                                       xctxt.getNamespaceContext(),
                                       XPath.SELECT);

        return dynamicXPath.execute(xctxt, myContext.getContextNode(),
                                    xctxt.getNamespaceContext());
      }
      catch (TransformerException e)
      {
        return new XNodeSet(xctxt.getDTMManager());
      }
    }
    else
      throw new SAXNotSupportedException(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_CONTEXT_PASSED, new Object[]{myContext })); //"Invalid context passed to evaluate "
  }

  /**
   * The dyn:closure function creates a node set resulting from transitive closure of
   * evaluating the expression passed as the second argument on each of the nodes passed
   * as the first argument, then on the node set resulting from that and so on until no
   * more nodes are found. For example:
   * <pre>
   *  dyn:closure(., '*')
   * </pre>
   * returns all the descendant elements of the node (its element children, their
   * children, their children's children and so on).
   * <p>
   * The expression is thus evaluated several times, each with a different node set
   * acting as the context of the expression. The first time the expression is
   * evaluated, the context node set is the first argument passed to the dyn:closure
   * function. In other words, the node set for each node is calculated by evaluating
   * the XPath expression with all context information being the same as that for
   * the call to the dyn:closure function itself, except for the following:
   * <p>
   * <ul>
   *  <li>the context node is the node whose value is being calculated.
   *  <li>the context position is the position of the node within the node set passed
   *    as the first argument to the dyn:closure function, arranged in document order.</li>
   *  <li>the context size is the number of nodes passed as the first argument to the
   *    dyn:closure function.</li>
   *  <li>the current node is the node whose value is being calculated.
   * </ul>
   * <p>
   * The result for a particular iteration is the union of the node sets resulting
   * from evaluting the expression for each of the nodes in the source node set for
   * that iteration. This result is then used as the source node set for the next
   * iteration, and so on. The result of the function as a whole is the union of
   * the node sets generated by each iteration.
   * <p>
   * If the expression string passed as the second argument is an invalid XPath
   * expression (including an empty string) or an expression that does not return a
   * node set, this function returns an empty node set.
   *
   * @param myContext The ExpressionContext passed by the extension processor
   * @param nl The node set
   * @param expr The expression string
   *
   * @return The node set after evaluation
   */
  public static NodeList closure(ExpressionContext myContext, NodeList nl, String expr)
    throws SAXNotSupportedException
  {
    XPathContext xctxt = null;
    if (myContext instanceof XPathContext.XPathExpressionContext)
      xctxt = ((XPathContext.XPathExpressionContext) myContext).getXPathContext();
    else
      throw new SAXNotSupportedException(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_CONTEXT_PASSED, new Object[]{myContext }));

    if (expr == null || expr.length() == 0)
      return new NodeSet();

    NodeSet closureSet = new NodeSet();
    closureSet.setShouldCacheNodes(true);

    NodeList iterationList = nl;
    do
    {

      NodeSet iterationSet = new NodeSet();

      NodeSetDTM contextNodes = new NodeSetDTM(iterationList, xctxt);
      xctxt.pushContextNodeList(contextNodes);

      for (int i = 0; i < iterationList.getLength(); i++)
      {
        int contextNode = contextNodes.item(i);
        xctxt.pushCurrentNode(contextNode);

        XObject object = null;
        try
        {
          XPath dynamicXPath = new XPath(expr, xctxt.getSAXLocator(),
                                         xctxt.getNamespaceContext(),
                                         XPath.SELECT);
          object = dynamicXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext());

          if (object instanceof XNodeSet)
          {
            NodeList nodelist = null;
            nodelist = ((XNodeSet)object).nodelist();

            for (int k = 0; k < nodelist.getLength(); k++)
            {
              Node n = nodelist.item(k);
              if (!iterationSet.contains(n))
                iterationSet.addNode(n);
            }
          }
          else
          {
            xctxt.popCurrentNode();
            xctxt.popContextNodeList();
            return new NodeSet();
          }
        }
        catch (TransformerException e)
        {
          xctxt.popCurrentNode();
          xctxt.popContextNodeList();
          return new NodeSet();
        }

        xctxt.popCurrentNode();

      }

      xctxt.popContextNodeList();

      iterationList = iterationSet;

      for (int i = 0; i < iterationList.getLength(); i++)
      {
        Node n = iterationList.item(i);
        if (!closureSet.contains(n))
          closureSet.addNode(n);
      }

    } while(iterationList.getLength() > 0);

    return closureSet;

  }

}

Other Java examples (source code examples)

Here is a short list of links related to this Java ExsltDynamic.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.