You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by dl...@apache.org on 2002/03/22 15:54:58 UTC

cvs commit: xml-xalan/java/src/org/apache/xalan/lib ExsltCommon.java ExsltMath.java ExsltSets.java package.html

dleslie     02/03/22 06:54:58

  Modified:    java/src/org/apache/xalan/lib package.html
  Added:       java/src/org/apache/xalan/lib ExsltCommon.java
                        ExsltMath.java ExsltSets.java
  Log:
  Preliminary set of EXSLT extension implementations.
  
  Revision  Changes    Path
  1.5       +2 -2      xml-xalan/java/src/org/apache/xalan/lib/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/lib/package.html,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- package.html	2 Jan 2001 03:36:37 -0000	1.4
  +++ package.html	22 Mar 2002 14:54:58 -0000	1.5
  @@ -1,7 +1,7 @@
   <html>
  -  <title>Xalan Extensions.</title>
  +  <title>Xalan and EXSLT Extensions.</title>
     <body>
  -   <p>Extension elements and functions shipped with Xalan-Java</p>
  +   <p>Extension elements and functions shipped with Xalan-Java, including EXSLT functions.</p>
      <p>We are adding extensions to this package.<p>
     </body>
   </html>
  
  
  
  1.1                  xml-xalan/java/src/org/apache/xalan/lib/ExsltCommon.java
  
  Index: ExsltCommon.java
  ===================================================================
  package org.apache.xalan.lib;
  
  import org.w3c.dom.Node;
  import org.w3c.dom.Document;
  import org.w3c.dom.DocumentFragment;
  import org.w3c.dom.NodeList;
  import org.w3c.dom.Text;
  import org.w3c.dom.traversal.NodeIterator;
  
  import org.apache.xpath.NodeSet;
  import org.apache.xpath.objects.XObject;
  import org.apache.xpath.objects.XBoolean;
  import org.apache.xpath.objects.XNumber;
  import org.apache.xpath.objects.XRTreeFrag;
  
  import org.apache.xpath.XPath;
  import org.apache.xpath.XPathContext;
  import org.apache.xpath.DOMHelper;
  import org.apache.xml.dtm.DTMIterator;
  import org.apache.xml.dtm.ref.DTMNodeIterator;
  import org.apache.xml.utils.XMLString;
  
  import org.xml.sax.SAXNotSupportedException;
  
  import java.util.Hashtable;
  import java.util.StringTokenizer;
  
  import org.apache.xalan.extensions.ExpressionContext;
  import org.apache.xalan.res.XSLMessages;
  import org.apache.xalan.res.XSLTErrorResources;
  import org.apache.xalan.xslt.EnvironmentCheck;
  
  import javax.xml.parsers.*;
  
  /**
   * <meta name="usage" content="general"/>
   * This class contains EXSLT common extension functions.
   * It is accessed by specifying a namespace URI as follows:
   * <pre>
   *    xmlns:exslt="http://exslt.org/xalan/common"
   * </pre>
   * 
   * The documentation for each function has been copied from the relevant
   * EXSLT Implementer page.
   * 
   * @see <a href="http://www.exslt.org/">EXSLT</a>
   */
  public class ExsltCommon
  {
    /**
     * The exsl:object-type function returns a string giving the type of the object passed 
     * as the argument. The possible object types are: 'string', 'number', 'boolean', 
     * 'node-set', 'RTF', or 'external'. 
     * 
     * Most XSLT object types can be coerced to each other without error. However, there are 
     * certain coercions that raise errors, most importantly treating anything other than a 
     * node set as a node set. Authors of utilities such as named templates or user-defined 
     * extension functions may wish to give some flexibility in the parameter and argument values 
     * that are accepted by the utility; the exsl:object-type function enables them to do so.
     * 
     * The Xalan extensions MethodResolver converts 'object-type' to 'objectType'.
     * 
     * @param obj The object to be typed.
     * @return objectType 'string', 'number', 'boolean', 'node-set', 'RTF', or 'external'.
     * 
     * @see <a href="http://www.exslt.org/">EXSLT</a>
     */
    public static String objectType (Object obj)
    {
      if (obj instanceof String)
        return "string";
      else if (obj instanceof Boolean)
        return "boolean";
      else if (obj instanceof Number)
        return "number";
      else if (obj instanceof DTMNodeIterator)
      {
        DTMIterator dtmI = ((DTMNodeIterator)obj).getDTMIterator();
        // Need to verify that OneStepIteratorForward is consistently the DTM iterator 
        // for rtfs and only rtfs.
        if (dtmI.getClass().getName().equals("org.apache.xpath.axes.OneStepIteratorForward"))
          return "RTF";
        else
          return "node-set";
      }
      else
        return "external";
    }
      
    /**
     * The exsl:node-set function converts a result tree fragment (which is what you get 
     * when you use the content of xsl:variable rather than its select attribute to give 
     * a variable value) into a node set. This enables you to process the XML that you create 
     * within a variable, and therefore do multi-step processing. 
     * 
     * You can also use this function to turn a string into a text node, which is helpful 
     * if you want to pass a string to a function that only accepts a node set.
     * 
     * The Xalan extensions MethodResolver converts 'node-set' to 'nodeSet'.
     * 
     * @param myProcesser is passed in by the Xalan extension processor
     * @param rtf The result tree fragment to be converted to a node-set.
     * 
     * @returns node-set with the contents of the result tree fragment.
     * 
     * Note: Already implemented in the xalan namespace as nodeset.
     * 
     * @see <a href="http://www.exslt.org/">EXSLT</a>
     */
    public static NodeSet nodeSet(ExpressionContext myProcessor, Object rtf)
    {
      return Extensions.nodeset(myProcessor, rtf);
    }
  
    public static NodeSet intersection(NodeIterator ni1, NodeIterator ni2)
            throws javax.xml.transform.TransformerException
    {
      return Extensions.intersection(ni1, ni2);
    }
    
    public static NodeSet difference(NodeIterator ni1, NodeIterator ni2)
            throws javax.xml.transform.TransformerException
    {
      return Extensions.difference(ni1, ni2);
    }
    
    public static NodeSet distinct(ExpressionContext myContext, NodeIterator ni)
            throws javax.xml.transform.TransformerException
    {
      return Extensions.distinct(myContext, ni);
    }
    
    public static boolean hasSameNodes(NodeIterator ni1, NodeIterator ni2)
    {
      return Extensions.hasSameNodes(ni1, ni2);
    }
  
  }
  
  
  1.1                  xml-xalan/java/src/org/apache/xalan/lib/ExsltMath.java
  
  Index: ExsltMath.java
  ===================================================================
  package org.apache.xalan.lib;
  
  import org.w3c.dom.Node;
  import org.w3c.dom.Document;
  import org.w3c.dom.DocumentFragment;
  import org.w3c.dom.NodeList;
  import org.w3c.dom.Text;
  import org.w3c.dom.traversal.NodeIterator;
  
  import org.apache.xpath.NodeSet;
  import org.apache.xpath.objects.XObject;
  import org.apache.xpath.objects.XBoolean;
  import org.apache.xpath.objects.XNumber;
  import org.apache.xpath.objects.XRTreeFrag;
  
  import org.apache.xpath.XPath;
  import org.apache.xpath.XPathContext;
  import org.apache.xpath.DOMHelper;
  import org.apache.xml.dtm.DTMIterator;
  import org.apache.xml.dtm.ref.DTMNodeIterator;
  import org.apache.xml.utils.XMLString;
  
  import org.xml.sax.SAXNotSupportedException;
  
  import java.util.Hashtable;
  import java.util.StringTokenizer;
  
  import org.apache.xalan.extensions.ExpressionContext;
  import org.apache.xalan.res.XSLMessages;
  import org.apache.xalan.res.XSLTErrorResources;
  import org.apache.xalan.xslt.EnvironmentCheck;
  
  import javax.xml.parsers.*;
  
  /**
   * <meta name="usage" content="general"/>
   * This class contains EXSLT math extension functions.
   * It is accessed by specifying a namespace URI as follows:
   * <pre>
   *    xmlns:exslt="http://exslt.org/math"
   * </pre>
   * 
   * The documentation for each function has been copied from the relevant
   * EXSLT Implementer page.
   * 
   * @see <a href="http://www.exslt.org/">EXSLT</a>
  
   */
  public class ExsltMath
  {
    /**
     * The math:max function returns the maximum value of the nodes passed as the argument. 
     * The maximum value is defined as follows. The node set passed as an argument is sorted 
     * in descending order as it would be by xsl:sort with a data type of number. The maximum 
     * is the result of converting the string value of the first node in this sorted list to 
     * a number using the number function. 
     * 
     * If the node set is empty, or if the result of converting the string values of any of the 
     * nodes to a number is NaN, then NaN is returned.
     * 
     * @param expCon is passed in by the Xalan extension processor
     * @param ni The NodeIterator for the node-set to be evaluated.
     * 
     * @return String representation of the maximum value found, NaN if any node cannot be 
     * converted to a number.
     * 
     * @see <a href="http://www.exslt.org/">EXSLT</a>
     */
    public static String max (ExpressionContext expCon, NodeIterator ni)
    {
      NodeSet ns = new NodeSet(ni);
      Node maxNode = null;
      double m = Double.MIN_VALUE;
      for (int i = 0; i < ns.getLength(); i++)
      {
        Node n = ns.elementAt(i);
        double d = expCon.toNumber(n);
        if (Double.isNaN(d))
          return "NaN";
        else if (d > m)
        {
          m = d;
          maxNode = n;
        }
      }
      return expCon.toString(maxNode);      
    }
  
    /**
     * The math:min function returns the minimum value of the nodes passed as the argument. 
     * The minimum value is defined as follows. The node set passed as an argument is sorted 
     * in ascending order as it would be by xsl:sort with a data type of number. The minimum 
     * is the result of converting the string value of the first node in this sorted list to 
     * a number using the number function. 
     * 
     * If the node set is empty, or if the result of converting the string values of any of 
     * the nodes to a number is NaN, then NaN is returned.
     * 
     * @param expCon is passed in by the Xalan extension processor
     * @param ni The NodeIterator for the node-set to be evaluated.
     * 
     * @return String representation of the minimum value found, NaN if any node cannot be 
     * converted to a number.
     * 
     * @see <a href="http://www.exslt.org/">EXSLT</a>
     */
    public static String min (ExpressionContext expCon, NodeIterator ni)
    {
      NodeSet ns = new NodeSet(ni);
      Node minNode = null;
      double m = Double.MAX_VALUE;
      for (int i = 0; i < ns.getLength(); i++)
      {
        Node n = ns.elementAt(i);
        double d = expCon.toNumber(n);
        if (Double.isNaN(d))
          return "NaN";
        else if (d < m)
        {
          m = d;
          minNode = n;
        }
      }
      return expCon.toString(minNode);
    }
    
    /**
     * The math:highest function returns the nodes in the node set whose value is the maximum 
     * value for the node set. The maximum value for the node set is the same as the value as 
     * calculated by math:max. A node has this maximum value if the result of converting its 
     * string value to a number as if by the number function is equal to the maximum value, 
     * where the equality comparison is defined as a numerical comparison using the = operator.
     * 
     * If any of the nodes in the node set has a non-numeric value, the math:max function will 
     * return NaN. The definition numeric comparisons entails that NaN != NaN. Therefore if any 
     * of the nodes in the node set has a non-numeric value, math:highest will return an empty 
     * node set. 
     * 
     * @param expCon is passed in by the Xalan extension processor
     * @param ni The NodeIterator for the node-set to be evaluated.
     * 
     * @return node-set with nodes containing the minimum value found, an empty node-set
     * if any node cannot be converted to a number.
     */
    public static NodeSet highest (ExpressionContext expCon, NodeIterator ni)
      throws java.lang.CloneNotSupportedException
    {    
      NodeSet ns = new NodeSet(ni);
      NodeIterator niClone = ns.cloneWithReset();
      double high = new Double(max(expCon, niClone)).doubleValue();
      NodeSet highNodes = new NodeSet();
      highNodes.setShouldCacheNodes(true);
      
      if (Double.isNaN(high))
        return highNodes;  // empty Nodeset
      
       for (int i = 0; i < ns.getLength(); i++)
      {
        Node n = ns.elementAt(i);
        double d = expCon.toNumber(n); 
        if (d == high)
        highNodes.addElement(n);
      }
      return highNodes;
    }
    
    /**
     * The math:lowest function returns the nodes in the node set whose value is the minimum value 
     * for the node set. The minimum value for the node set is the same as the value as calculated 
     * by math:min. A node has this minimum value if the result of converting its string value to 
     * a number as if by the number function is equal to the minimum value, where the equality 
     * comparison is defined as a numerical comparison using the = operator.
     * 
     * If any of the nodes in the node set has a non-numeric value, the math:min function will return 
     * NaN. The definition numeric comparisons entails that NaN != NaN. Therefore if any of the nodes 
     * in the node set has a non-numeric value, math:lowest will return an empty node set.
     * 
     * @param expCon is passed in by the Xalan extension processor
     * @param ni The NodeIterator for the node-set to be evaluated.
     * 
     * @return node-set with nodes containing the maximum value found, an empty node-set
     * if any node cannot be converted to a number.
     * 
     */
    public static NodeSet lowest (ExpressionContext expCon, NodeIterator ni)
      throws java.lang.CloneNotSupportedException
    {
      NodeSet ns = new NodeSet(ni);
      NodeIterator niClone = ns.cloneWithReset();
      double low = new Double(min(expCon, niClone)).doubleValue();
  
      NodeSet lowNodes = new NodeSet();
      lowNodes.setShouldCacheNodes(true);
      
      if (Double.isNaN(low))
        return lowNodes;  // empty Nodeset
      
       for (int i = 0; i < ns.getLength(); i++)
      {
        Node n = ns.elementAt(i);
        double d = expCon.toNumber(n); 
        if (d == low)
        lowNodes.addElement(n);
      }
      return lowNodes;
    }  
  }
  
  
  1.1                  xml-xalan/java/src/org/apache/xalan/lib/ExsltSets.java
  
  Index: ExsltSets.java
  ===================================================================
  package org.apache.xalan.lib;
  
  import org.w3c.dom.Node;
  import org.w3c.dom.Document;
  import org.w3c.dom.DocumentFragment;
  import org.w3c.dom.NodeList;
  import org.w3c.dom.Text;
  import org.w3c.dom.traversal.NodeIterator;
  
  import org.apache.xpath.NodeSet;
  import org.apache.xpath.objects.XObject;
  import org.apache.xpath.objects.XBoolean;
  import org.apache.xpath.objects.XNumber;
  import org.apache.xpath.objects.XRTreeFrag;
  
  import org.apache.xpath.XPath;
  import org.apache.xpath.XPathContext;
  import org.apache.xpath.DOMHelper;
  import org.apache.xml.dtm.DTMIterator;
  import org.apache.xml.dtm.ref.DTMNodeIterator;
  import org.apache.xml.utils.XMLString;
  
  import org.xml.sax.SAXNotSupportedException;
  
  import java.util.Hashtable;
  import java.util.StringTokenizer;
  
  import org.apache.xalan.extensions.ExpressionContext;
  import org.apache.xalan.res.XSLMessages;
  import org.apache.xalan.res.XSLTErrorResources;
  import org.apache.xalan.xslt.EnvironmentCheck;
  
  import javax.xml.parsers.*;
  
  /**
   * <meta name="usage" content="general"/>
   * This class contains EXSLT set extension functions.
   * It is accessed by specifying a namespace URI as follows:
   * <pre>
   *    xmlns:exslt="http://exslt.org/xalan/sets"
   * </pre>
   * 
   * The documentation for each function has been copied from the relevant
   * EXSLT Implementer page. 
   * 
   * @see <a href="http://www.exslt.org/">EXSLT</a>
   */
  public class ExsltSets
  {   
    /**
     * The set:leading function returns the nodes in the node set passed as the first argument that
     * precede, in document order, the first node in the node set passed as the second argument. If
     * the first node in the second node set is not contained in the first node set, then an empty
     * node set is returned. If the second node set is empty, then the first node set is returned.
     * 
     * @param ni1 NodeIterator for first node-set.
     * @param ni2 NodeIterator for second node-set.
     * @return a node-set containing the nodes in ni1 that precede in document order the first
     * node in ni2; an empty node-set if the first node in ni2 is not in ni1; all of ni1 if n12
     * is empty.
     * 
     * @see <a href="http://www.exslt.org/">EXSLT</a>
     */
    public static NodeSet leading (NodeIterator ni1, NodeIterator ni2)
    {
      NodeSet ns1 = new NodeSet(ni1);
      NodeSet ns2 = new NodeSet(ni2);
      NodeSet leadNodes = new NodeSet();
      if (ns2.getLength() == 0)
        return ns1;
      Node endNode = ns2.elementAt(0);
      if (!ns1.contains(endNode))
        return leadNodes; // empty NodeSet
      for (int i = 0; i < ns1.getLength(); i++)
      {
        Node testNode = ns1.elementAt(i);
        if (DOMHelper.isNodeAfter(testNode, endNode) 
            && !(DOMHelper.isNodeTheSame(testNode, endNode)))
          leadNodes.addElement(testNode);
      }
      return leadNodes;
    }
    
    /**
     * The set:trailing function returns the nodes in the node set passed as the first argument that 
     * follow, in document order, the first node in the node set passed as the second argument. If 
     * the first node in the second node set is not contained in the first node set, then an empty 
     * node set is returned. If the second node set is empty, then the first node set is returned. 
     * 
     * @param ni1 NodeIterator for first node-set.
     * @param ni2 NodeIterator for second node-set.
     * @return a node-set containing the nodes in ni1 that precede in document order the first
     * node in ni2; an empty node-set if the first noe in ni2 is not in ni1; all of ni1 if ni2
     * is empty.
     * 
     * @see <a href="http://www.exslt.org/">EXSLT</a>
     */
    public static NodeSet trailing (NodeIterator ni1, NodeIterator ni2)
    {
      NodeSet ns1 = new NodeSet(ni1);
      NodeSet ns2 = new NodeSet(ni2);
      NodeSet trailNodes = new NodeSet();
      if (ns2.getLength() == 0)
        return ns1;
      Node startNode = ns2.elementAt(0);
      if (!ns1.contains(startNode))
        return trailNodes; // empty NodeSet
      for (int i = 0; i < ns1.getLength(); i++)
      {
        Node testNode = ns1.elementAt(i);
        if (DOMHelper.isNodeAfter(startNode, testNode) 
            && !(DOMHelper.isNodeTheSame(startNode, testNode)))
          trailNodes.addElement(testNode);          
      }
      return trailNodes;
    }
    
    /**
     * The set:intersection function returns a node set comprising the nodes that are within 
     * both the node sets passed as arguments to it.
     * 
     * @param ni1 NodeIterator for first node-set.
     * @param ni2 NodeIterator for second node-set.
     * @return a NodeSet containing the nodes in ni1 that are also
     * in ni2.
     * 
     * Note: Already implemented in the xalan namespace.
     * 
     * @see <a href="http://www.exslt.org/">EXSLT</a>
     */
    public static NodeSet intersection(NodeIterator ni1, NodeIterator ni2)
            throws javax.xml.transform.TransformerException
    {
      return Extensions.intersection(ni1, ni2);
    }
    
    /**
     * The set:difference function returns the difference between two node sets - those nodes that 
     * are in the node set passed as the first argument that are not in the node set passed as the 
     * second argument.
     * 
     * @param ni1 NodeIterator for first node-set.
     * @param ni2 NodeIterator for second node-set.
     * @return a NodeSet containing the nodes in ni1 that are not
     * in ni2.
     * 
     * Note: Already implemented in the xalan namespace.
     * 
     * @see <a href="http://www.exslt.org/">EXSLT</a>
     */
    public static NodeSet difference(NodeIterator ni1, NodeIterator ni2)
            throws javax.xml.transform.TransformerException
    {
      return Extensions.difference(ni1, ni2);
    }
    
    /**
     * The set:distinct function returns a subset of the nodes contained in the node-set NS passed 
     * as the first argument. Specifically, it selects a node N if there is no node in NS that has 
     * the same string value as N, and that precedes N in document order. 
     * 
     * @param myContext Passed in by Xalan extension processor.
     * @param ni NodeIterator for node-set.
     * @return a NodeSet with nodes from ni containing distinct string values.
     * In other words, if more than one node in ni contains the same string value,
     * only include the first such node found.
     * 
     * Note: Already implemented in the xalan namespace.
     * 
     * @see <a href="http://www.exslt.org/">EXSLT</a>
     */
    public static NodeSet distinct(ExpressionContext myContext, NodeIterator ni)
            throws javax.xml.transform.TransformerException
    {
      return Extensions.distinct(myContext, ni);
    }
    
    /**
     * The set:has-same-node function returns true if the node set passed as the first argument shares 
     * any nodes with the node set passed as the second argument. If there are no nodes that are in both
     * node sets, then it returns false. 
     * 
     * The Xalan extensions MethodResolver converts 'has-same-node' to 'hasSameNode'.
     * 
     * Note: Not to be confused with hasSameNodes in the Xalan namespace, which returns true if
     * the two node sets contain the exactly the same nodes (perhaps in a different order), 
     * otherwise false.
     * 
     * @see <a href="http://www.exslt.org/">EXSLT</a>
     */
    public static boolean hasSameNode(NodeIterator ni1, NodeIterator ni2)
    {
      
      NodeSet ns1 = new NodeSet(ni1);
      NodeSet ns2 = new NodeSet(ni2);
  
      for (int i = 0; i < ns1.getLength(); i++)
      {
        if (ns2.contains(ns1.elementAt(i)))
          return true;
      }
      return false;
    }
    
  }
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: xalan-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: xalan-cvs-help@xml.apache.org