jaxp/src/com/sun/org/apache/xalan/internal/lib/ExsltDynamic.java
author duke
Wed, 05 Jul 2017 19:04:46 +0200
changeset 18896 98b0babd0565
parent 12457 c348e06f0e82
permissions -rw-r--r--
Merge
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
6
7f561c08de6b Initial load
duke
parents:
diff changeset
     1
/*
7f561c08de6b Initial load
duke
parents:
diff changeset
     2
 * reserved comment block
7f561c08de6b Initial load
duke
parents:
diff changeset
     3
 * DO NOT REMOVE OR ALTER!
7f561c08de6b Initial load
duke
parents:
diff changeset
     4
 */
7f561c08de6b Initial load
duke
parents:
diff changeset
     5
/*
7f561c08de6b Initial load
duke
parents:
diff changeset
     6
 * Copyright 1999-2004 The Apache Software Foundation.
7f561c08de6b Initial load
duke
parents:
diff changeset
     7
 *
7f561c08de6b Initial load
duke
parents:
diff changeset
     8
 * Licensed under the Apache License, Version 2.0 (the "License");
7f561c08de6b Initial load
duke
parents:
diff changeset
     9
 * you may not use this file except in compliance with the License.
7f561c08de6b Initial load
duke
parents:
diff changeset
    10
 * You may obtain a copy of the License at
7f561c08de6b Initial load
duke
parents:
diff changeset
    11
 *
7f561c08de6b Initial load
duke
parents:
diff changeset
    12
 *     http://www.apache.org/licenses/LICENSE-2.0
7f561c08de6b Initial load
duke
parents:
diff changeset
    13
 *
7f561c08de6b Initial load
duke
parents:
diff changeset
    14
 * Unless required by applicable law or agreed to in writing, software
7f561c08de6b Initial load
duke
parents:
diff changeset
    15
 * distributed under the License is distributed on an "AS IS" BASIS,
7f561c08de6b Initial load
duke
parents:
diff changeset
    16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7f561c08de6b Initial load
duke
parents:
diff changeset
    17
 * See the License for the specific language governing permissions and
7f561c08de6b Initial load
duke
parents:
diff changeset
    18
 * limitations under the License.
7f561c08de6b Initial load
duke
parents:
diff changeset
    19
 */
7f561c08de6b Initial load
duke
parents:
diff changeset
    20
/*
7f561c08de6b Initial load
duke
parents:
diff changeset
    21
 * $Id: ExsltDynamic.java,v 1.1.2.1 2005/08/01 02:08:51 jeffsuttor Exp $
7f561c08de6b Initial load
duke
parents:
diff changeset
    22
 */
7f561c08de6b Initial load
duke
parents:
diff changeset
    23
package com.sun.org.apache.xalan.internal.lib;
7f561c08de6b Initial load
duke
parents:
diff changeset
    24
7f561c08de6b Initial load
duke
parents:
diff changeset
    25
import javax.xml.parsers.DocumentBuilder;
7f561c08de6b Initial load
duke
parents:
diff changeset
    26
import javax.xml.parsers.DocumentBuilderFactory;
7f561c08de6b Initial load
duke
parents:
diff changeset
    27
import javax.xml.transform.TransformerException;
7f561c08de6b Initial load
duke
parents:
diff changeset
    28
7f561c08de6b Initial load
duke
parents:
diff changeset
    29
import com.sun.org.apache.xalan.internal.extensions.ExpressionContext;
7f561c08de6b Initial load
duke
parents:
diff changeset
    30
import com.sun.org.apache.xalan.internal.res.XSLMessages;
7f561c08de6b Initial load
duke
parents:
diff changeset
    31
import com.sun.org.apache.xalan.internal.res.XSLTErrorResources;
7f561c08de6b Initial load
duke
parents:
diff changeset
    32
import com.sun.org.apache.xpath.internal.NodeSet;
7f561c08de6b Initial load
duke
parents:
diff changeset
    33
import com.sun.org.apache.xpath.internal.NodeSetDTM;
7f561c08de6b Initial load
duke
parents:
diff changeset
    34
import com.sun.org.apache.xpath.internal.XPath;
7f561c08de6b Initial load
duke
parents:
diff changeset
    35
import com.sun.org.apache.xpath.internal.XPathContext;
7f561c08de6b Initial load
duke
parents:
diff changeset
    36
import com.sun.org.apache.xpath.internal.objects.XBoolean;
7f561c08de6b Initial load
duke
parents:
diff changeset
    37
import com.sun.org.apache.xpath.internal.objects.XNodeSet;
7f561c08de6b Initial load
duke
parents:
diff changeset
    38
import com.sun.org.apache.xpath.internal.objects.XNumber;
7f561c08de6b Initial load
duke
parents:
diff changeset
    39
import com.sun.org.apache.xpath.internal.objects.XObject;
7f561c08de6b Initial load
duke
parents:
diff changeset
    40
7f561c08de6b Initial load
duke
parents:
diff changeset
    41
import org.w3c.dom.Document;
7f561c08de6b Initial load
duke
parents:
diff changeset
    42
import org.w3c.dom.Element;
7f561c08de6b Initial load
duke
parents:
diff changeset
    43
import org.w3c.dom.Node;
7f561c08de6b Initial load
duke
parents:
diff changeset
    44
import org.w3c.dom.NodeList;
7f561c08de6b Initial load
duke
parents:
diff changeset
    45
import org.w3c.dom.Text;
7f561c08de6b Initial load
duke
parents:
diff changeset
    46
7f561c08de6b Initial load
duke
parents:
diff changeset
    47
import org.xml.sax.SAXNotSupportedException;
7f561c08de6b Initial load
duke
parents:
diff changeset
    48
7f561c08de6b Initial load
duke
parents:
diff changeset
    49
/**
7f561c08de6b Initial load
duke
parents:
diff changeset
    50
 * This class contains EXSLT dynamic extension functions.
7f561c08de6b Initial load
duke
parents:
diff changeset
    51
 *
7f561c08de6b Initial load
duke
parents:
diff changeset
    52
 * It is accessed by specifying a namespace URI as follows:
7f561c08de6b Initial load
duke
parents:
diff changeset
    53
 * <pre>
7f561c08de6b Initial load
duke
parents:
diff changeset
    54
 *    xmlns:dyn="http://exslt.org/dynamic"
7f561c08de6b Initial load
duke
parents:
diff changeset
    55
 * </pre>
7f561c08de6b Initial load
duke
parents:
diff changeset
    56
 * The documentation for each function has been copied from the relevant
7f561c08de6b Initial load
duke
parents:
diff changeset
    57
 * EXSLT Implementer page.
7f561c08de6b Initial load
duke
parents:
diff changeset
    58
 *
7f561c08de6b Initial load
duke
parents:
diff changeset
    59
 * @see <a href="http://www.exslt.org/">EXSLT</a>
7f561c08de6b Initial load
duke
parents:
diff changeset
    60
7f561c08de6b Initial load
duke
parents:
diff changeset
    61
 * @xsl.usage general
7f561c08de6b Initial load
duke
parents:
diff changeset
    62
 */
7f561c08de6b Initial load
duke
parents:
diff changeset
    63
public class ExsltDynamic extends ExsltBase
7f561c08de6b Initial load
duke
parents:
diff changeset
    64
{
7f561c08de6b Initial load
duke
parents:
diff changeset
    65
7f561c08de6b Initial load
duke
parents:
diff changeset
    66
   public static final String EXSL_URI = "http://exslt.org/common";
7f561c08de6b Initial load
duke
parents:
diff changeset
    67
7f561c08de6b Initial load
duke
parents:
diff changeset
    68
  /**
7f561c08de6b Initial load
duke
parents:
diff changeset
    69
   * The dyn:max function calculates the maximum value for the nodes passed as
7f561c08de6b Initial load
duke
parents:
diff changeset
    70
   * the first argument, where the value of each node is calculated dynamically
7f561c08de6b Initial load
duke
parents:
diff changeset
    71
   * using an XPath expression passed as a string as the second argument.
7f561c08de6b Initial load
duke
parents:
diff changeset
    72
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
    73
   * The expressions are evaluated relative to the nodes passed as the first argument.
7f561c08de6b Initial load
duke
parents:
diff changeset
    74
   * In other words, the value for each node is calculated by evaluating the XPath
7f561c08de6b Initial load
duke
parents:
diff changeset
    75
   * expression with all context information being the same as that for the call to
7f561c08de6b Initial load
duke
parents:
diff changeset
    76
   * the dyn:max function itself, except for the following:
7f561c08de6b Initial load
duke
parents:
diff changeset
    77
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
    78
   * <ul>
7f561c08de6b Initial load
duke
parents:
diff changeset
    79
   *  <li>the context node is the node whose value is being calculated.</li>
7f561c08de6b Initial load
duke
parents:
diff changeset
    80
   *  <li>the context position is the position of the node within the node set passed as
7f561c08de6b Initial load
duke
parents:
diff changeset
    81
   *   the first argument to the dyn:max function, arranged in document order.</li>
7f561c08de6b Initial load
duke
parents:
diff changeset
    82
   *  <li>the context size is the number of nodes passed as the first argument to the
7f561c08de6b Initial load
duke
parents:
diff changeset
    83
   *   dyn:max function.</li>
7f561c08de6b Initial load
duke
parents:
diff changeset
    84
   * </ul>
7f561c08de6b Initial load
duke
parents:
diff changeset
    85
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
    86
   * The dyn:max function returns the maximum of these values, calculated in exactly
7f561c08de6b Initial load
duke
parents:
diff changeset
    87
   * the same way as for math:max.
7f561c08de6b Initial load
duke
parents:
diff changeset
    88
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
    89
   * If the expression string passed as the second argument is an invalid XPath
7f561c08de6b Initial load
duke
parents:
diff changeset
    90
   * expression (including an empty string), this function returns NaN.
7f561c08de6b Initial load
duke
parents:
diff changeset
    91
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
    92
   * This function must take a second argument. To calculate the maximum of a set of
7f561c08de6b Initial load
duke
parents:
diff changeset
    93
   * nodes based on their string values, you should use the math:max function.
7f561c08de6b Initial load
duke
parents:
diff changeset
    94
   *
7f561c08de6b Initial load
duke
parents:
diff changeset
    95
   * @param myContext The ExpressionContext passed by the extension processor
7f561c08de6b Initial load
duke
parents:
diff changeset
    96
   * @param nl The node set
7f561c08de6b Initial load
duke
parents:
diff changeset
    97
   * @param expr The expression string
7f561c08de6b Initial load
duke
parents:
diff changeset
    98
   *
7f561c08de6b Initial load
duke
parents:
diff changeset
    99
   * @return The maximum evaluation value
7f561c08de6b Initial load
duke
parents:
diff changeset
   100
   */
7f561c08de6b Initial load
duke
parents:
diff changeset
   101
  public static double max(ExpressionContext myContext, NodeList nl, String expr)
7f561c08de6b Initial load
duke
parents:
diff changeset
   102
    throws SAXNotSupportedException
7f561c08de6b Initial load
duke
parents:
diff changeset
   103
  {
7f561c08de6b Initial load
duke
parents:
diff changeset
   104
7f561c08de6b Initial load
duke
parents:
diff changeset
   105
    XPathContext xctxt = null;
7f561c08de6b Initial load
duke
parents:
diff changeset
   106
    if (myContext instanceof XPathContext.XPathExpressionContext)
7f561c08de6b Initial load
duke
parents:
diff changeset
   107
      xctxt = ((XPathContext.XPathExpressionContext) myContext).getXPathContext();
7f561c08de6b Initial load
duke
parents:
diff changeset
   108
    else
7f561c08de6b Initial load
duke
parents:
diff changeset
   109
      throw new SAXNotSupportedException(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_CONTEXT_PASSED, new Object[]{myContext }));
7f561c08de6b Initial load
duke
parents:
diff changeset
   110
7f561c08de6b Initial load
duke
parents:
diff changeset
   111
    if (expr == null || expr.length() == 0)
7f561c08de6b Initial load
duke
parents:
diff changeset
   112
      return Double.NaN;
7f561c08de6b Initial load
duke
parents:
diff changeset
   113
7f561c08de6b Initial load
duke
parents:
diff changeset
   114
    NodeSetDTM contextNodes = new NodeSetDTM(nl, xctxt);
7f561c08de6b Initial load
duke
parents:
diff changeset
   115
    xctxt.pushContextNodeList(contextNodes);
7f561c08de6b Initial load
duke
parents:
diff changeset
   116
7f561c08de6b Initial load
duke
parents:
diff changeset
   117
    double maxValue = - Double.MAX_VALUE;
7f561c08de6b Initial load
duke
parents:
diff changeset
   118
    for (int i = 0; i < contextNodes.getLength(); i++)
7f561c08de6b Initial load
duke
parents:
diff changeset
   119
    {
7f561c08de6b Initial load
duke
parents:
diff changeset
   120
      int contextNode = contextNodes.item(i);
7f561c08de6b Initial load
duke
parents:
diff changeset
   121
      xctxt.pushCurrentNode(contextNode);
7f561c08de6b Initial load
duke
parents:
diff changeset
   122
7f561c08de6b Initial load
duke
parents:
diff changeset
   123
      double result = 0;
7f561c08de6b Initial load
duke
parents:
diff changeset
   124
      try
7f561c08de6b Initial load
duke
parents:
diff changeset
   125
      {
7f561c08de6b Initial load
duke
parents:
diff changeset
   126
        XPath dynamicXPath = new XPath(expr, xctxt.getSAXLocator(),
7f561c08de6b Initial load
duke
parents:
diff changeset
   127
                                       xctxt.getNamespaceContext(),
7f561c08de6b Initial load
duke
parents:
diff changeset
   128
                                       XPath.SELECT);
7f561c08de6b Initial load
duke
parents:
diff changeset
   129
        result = dynamicXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext()).num();
7f561c08de6b Initial load
duke
parents:
diff changeset
   130
      }
7f561c08de6b Initial load
duke
parents:
diff changeset
   131
      catch (TransformerException e)
7f561c08de6b Initial load
duke
parents:
diff changeset
   132
      {
7f561c08de6b Initial load
duke
parents:
diff changeset
   133
        xctxt.popCurrentNode();
7f561c08de6b Initial load
duke
parents:
diff changeset
   134
        xctxt.popContextNodeList();
7f561c08de6b Initial load
duke
parents:
diff changeset
   135
        return Double.NaN;
7f561c08de6b Initial load
duke
parents:
diff changeset
   136
      }
7f561c08de6b Initial load
duke
parents:
diff changeset
   137
7f561c08de6b Initial load
duke
parents:
diff changeset
   138
      xctxt.popCurrentNode();
7f561c08de6b Initial load
duke
parents:
diff changeset
   139
7f561c08de6b Initial load
duke
parents:
diff changeset
   140
      if (result > maxValue)
7f561c08de6b Initial load
duke
parents:
diff changeset
   141
          maxValue = result;
7f561c08de6b Initial load
duke
parents:
diff changeset
   142
    }
7f561c08de6b Initial load
duke
parents:
diff changeset
   143
7f561c08de6b Initial load
duke
parents:
diff changeset
   144
    xctxt.popContextNodeList();
7f561c08de6b Initial load
duke
parents:
diff changeset
   145
    return maxValue;
7f561c08de6b Initial load
duke
parents:
diff changeset
   146
7f561c08de6b Initial load
duke
parents:
diff changeset
   147
  }
7f561c08de6b Initial load
duke
parents:
diff changeset
   148
7f561c08de6b Initial load
duke
parents:
diff changeset
   149
  /**
7f561c08de6b Initial load
duke
parents:
diff changeset
   150
   * The dyn:min function calculates the minimum value for the nodes passed as the
7f561c08de6b Initial load
duke
parents:
diff changeset
   151
   * first argument, where the value of each node is calculated dynamically using
7f561c08de6b Initial load
duke
parents:
diff changeset
   152
   * an XPath expression passed as a string as the second argument.
7f561c08de6b Initial load
duke
parents:
diff changeset
   153
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   154
   * The expressions are evaluated relative to the nodes passed as the first argument.
7f561c08de6b Initial load
duke
parents:
diff changeset
   155
   * In other words, the value for each node is calculated by evaluating the XPath
7f561c08de6b Initial load
duke
parents:
diff changeset
   156
   * expression with all context information being the same as that for the call to
7f561c08de6b Initial load
duke
parents:
diff changeset
   157
   * the dyn:min function itself, except for the following:
7f561c08de6b Initial load
duke
parents:
diff changeset
   158
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   159
   * <ul>
7f561c08de6b Initial load
duke
parents:
diff changeset
   160
   *  <li>the context node is the node whose value is being calculated.</li>
7f561c08de6b Initial load
duke
parents:
diff changeset
   161
   *  <li>the context position is the position of the node within the node set passed
7f561c08de6b Initial load
duke
parents:
diff changeset
   162
   *    as the first argument to the dyn:min function, arranged in document order.</li>
7f561c08de6b Initial load
duke
parents:
diff changeset
   163
   *  <li>the context size is the number of nodes passed as the first argument to the
7f561c08de6b Initial load
duke
parents:
diff changeset
   164
   *    dyn:min function.</li>
7f561c08de6b Initial load
duke
parents:
diff changeset
   165
   * </ul>
7f561c08de6b Initial load
duke
parents:
diff changeset
   166
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   167
   * The dyn:min function returns the minimum of these values, calculated in exactly
7f561c08de6b Initial load
duke
parents:
diff changeset
   168
   * the same way as for math:min.
7f561c08de6b Initial load
duke
parents:
diff changeset
   169
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   170
   * If the expression string passed as the second argument is an invalid XPath expression
7f561c08de6b Initial load
duke
parents:
diff changeset
   171
   * (including an empty string), this function returns NaN.
7f561c08de6b Initial load
duke
parents:
diff changeset
   172
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   173
   * This function must take a second argument. To calculate the minimum of a set of
7f561c08de6b Initial load
duke
parents:
diff changeset
   174
   * nodes based on their string values, you should use the math:min function.
7f561c08de6b Initial load
duke
parents:
diff changeset
   175
   *
7f561c08de6b Initial load
duke
parents:
diff changeset
   176
   * @param myContext The ExpressionContext passed by the extension processor
7f561c08de6b Initial load
duke
parents:
diff changeset
   177
   * @param nl The node set
7f561c08de6b Initial load
duke
parents:
diff changeset
   178
   * @param expr The expression string
7f561c08de6b Initial load
duke
parents:
diff changeset
   179
   *
7f561c08de6b Initial load
duke
parents:
diff changeset
   180
   * @return The minimum evaluation value
7f561c08de6b Initial load
duke
parents:
diff changeset
   181
   */
7f561c08de6b Initial load
duke
parents:
diff changeset
   182
  public static double min(ExpressionContext myContext, NodeList nl, String expr)
7f561c08de6b Initial load
duke
parents:
diff changeset
   183
    throws SAXNotSupportedException
7f561c08de6b Initial load
duke
parents:
diff changeset
   184
  {
7f561c08de6b Initial load
duke
parents:
diff changeset
   185
7f561c08de6b Initial load
duke
parents:
diff changeset
   186
    XPathContext xctxt = null;
7f561c08de6b Initial load
duke
parents:
diff changeset
   187
    if (myContext instanceof XPathContext.XPathExpressionContext)
7f561c08de6b Initial load
duke
parents:
diff changeset
   188
      xctxt = ((XPathContext.XPathExpressionContext) myContext).getXPathContext();
7f561c08de6b Initial load
duke
parents:
diff changeset
   189
    else
7f561c08de6b Initial load
duke
parents:
diff changeset
   190
      throw new SAXNotSupportedException(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_CONTEXT_PASSED, new Object[]{myContext }));
7f561c08de6b Initial load
duke
parents:
diff changeset
   191
7f561c08de6b Initial load
duke
parents:
diff changeset
   192
    if (expr == null || expr.length() == 0)
7f561c08de6b Initial load
duke
parents:
diff changeset
   193
      return Double.NaN;
7f561c08de6b Initial load
duke
parents:
diff changeset
   194
7f561c08de6b Initial load
duke
parents:
diff changeset
   195
    NodeSetDTM contextNodes = new NodeSetDTM(nl, xctxt);
7f561c08de6b Initial load
duke
parents:
diff changeset
   196
    xctxt.pushContextNodeList(contextNodes);
7f561c08de6b Initial load
duke
parents:
diff changeset
   197
7f561c08de6b Initial load
duke
parents:
diff changeset
   198
    double minValue = Double.MAX_VALUE;
7f561c08de6b Initial load
duke
parents:
diff changeset
   199
    for (int i = 0; i < nl.getLength(); i++)
7f561c08de6b Initial load
duke
parents:
diff changeset
   200
    {
7f561c08de6b Initial load
duke
parents:
diff changeset
   201
      int contextNode = contextNodes.item(i);
7f561c08de6b Initial load
duke
parents:
diff changeset
   202
      xctxt.pushCurrentNode(contextNode);
7f561c08de6b Initial load
duke
parents:
diff changeset
   203
7f561c08de6b Initial load
duke
parents:
diff changeset
   204
      double result = 0;
7f561c08de6b Initial load
duke
parents:
diff changeset
   205
      try
7f561c08de6b Initial load
duke
parents:
diff changeset
   206
      {
7f561c08de6b Initial load
duke
parents:
diff changeset
   207
        XPath dynamicXPath = new XPath(expr, xctxt.getSAXLocator(),
7f561c08de6b Initial load
duke
parents:
diff changeset
   208
                                       xctxt.getNamespaceContext(),
7f561c08de6b Initial load
duke
parents:
diff changeset
   209
                                       XPath.SELECT);
7f561c08de6b Initial load
duke
parents:
diff changeset
   210
        result = dynamicXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext()).num();
7f561c08de6b Initial load
duke
parents:
diff changeset
   211
      }
7f561c08de6b Initial load
duke
parents:
diff changeset
   212
      catch (TransformerException e)
7f561c08de6b Initial load
duke
parents:
diff changeset
   213
      {
7f561c08de6b Initial load
duke
parents:
diff changeset
   214
        xctxt.popCurrentNode();
7f561c08de6b Initial load
duke
parents:
diff changeset
   215
        xctxt.popContextNodeList();
7f561c08de6b Initial load
duke
parents:
diff changeset
   216
        return Double.NaN;
7f561c08de6b Initial load
duke
parents:
diff changeset
   217
      }
7f561c08de6b Initial load
duke
parents:
diff changeset
   218
7f561c08de6b Initial load
duke
parents:
diff changeset
   219
      xctxt.popCurrentNode();
7f561c08de6b Initial load
duke
parents:
diff changeset
   220
7f561c08de6b Initial load
duke
parents:
diff changeset
   221
      if (result < minValue)
7f561c08de6b Initial load
duke
parents:
diff changeset
   222
          minValue = result;
7f561c08de6b Initial load
duke
parents:
diff changeset
   223
    }
7f561c08de6b Initial load
duke
parents:
diff changeset
   224
7f561c08de6b Initial load
duke
parents:
diff changeset
   225
    xctxt.popContextNodeList();
7f561c08de6b Initial load
duke
parents:
diff changeset
   226
    return minValue;
7f561c08de6b Initial load
duke
parents:
diff changeset
   227
7f561c08de6b Initial load
duke
parents:
diff changeset
   228
  }
7f561c08de6b Initial load
duke
parents:
diff changeset
   229
7f561c08de6b Initial load
duke
parents:
diff changeset
   230
  /**
7f561c08de6b Initial load
duke
parents:
diff changeset
   231
   * The dyn:sum function calculates the sum for the nodes passed as the first argument,
7f561c08de6b Initial load
duke
parents:
diff changeset
   232
   * where the value of each node is calculated dynamically using an XPath expression
7f561c08de6b Initial load
duke
parents:
diff changeset
   233
   * passed as a string as the second argument.
7f561c08de6b Initial load
duke
parents:
diff changeset
   234
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   235
   * The expressions are evaluated relative to the nodes passed as the first argument.
7f561c08de6b Initial load
duke
parents:
diff changeset
   236
   * In other words, the value for each node is calculated by evaluating the XPath
7f561c08de6b Initial load
duke
parents:
diff changeset
   237
   * expression with all context information being the same as that for the call to
7f561c08de6b Initial load
duke
parents:
diff changeset
   238
   * the dyn:sum function itself, except for the following:
7f561c08de6b Initial load
duke
parents:
diff changeset
   239
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   240
   * <ul>
7f561c08de6b Initial load
duke
parents:
diff changeset
   241
   *  <li>the context node is the node whose value is being calculated.</li>
7f561c08de6b Initial load
duke
parents:
diff changeset
   242
   *  <li>the context position is the position of the node within the node set passed as
7f561c08de6b Initial load
duke
parents:
diff changeset
   243
   *    the first argument to the dyn:sum function, arranged in document order.</li>
7f561c08de6b Initial load
duke
parents:
diff changeset
   244
   *  <li>the context size is the number of nodes passed as the first argument to the
7f561c08de6b Initial load
duke
parents:
diff changeset
   245
   *    dyn:sum function.</li>
7f561c08de6b Initial load
duke
parents:
diff changeset
   246
   * </ul>
7f561c08de6b Initial load
duke
parents:
diff changeset
   247
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   248
   * The dyn:sum function returns the sumimum of these values, calculated in exactly
7f561c08de6b Initial load
duke
parents:
diff changeset
   249
   * the same way as for sum.
7f561c08de6b Initial load
duke
parents:
diff changeset
   250
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   251
   * If the expression string passed as the second argument is an invalid XPath
7f561c08de6b Initial load
duke
parents:
diff changeset
   252
   * expression (including an empty string), this function returns NaN.
7f561c08de6b Initial load
duke
parents:
diff changeset
   253
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   254
   * This function must take a second argument. To calculate the sumimum of a set of
7f561c08de6b Initial load
duke
parents:
diff changeset
   255
   * nodes based on their string values, you should use the sum function.
7f561c08de6b Initial load
duke
parents:
diff changeset
   256
   *
7f561c08de6b Initial load
duke
parents:
diff changeset
   257
   * @param myContext The ExpressionContext passed by the extension processor
7f561c08de6b Initial load
duke
parents:
diff changeset
   258
   * @param nl The node set
7f561c08de6b Initial load
duke
parents:
diff changeset
   259
   * @param expr The expression string
7f561c08de6b Initial load
duke
parents:
diff changeset
   260
   *
7f561c08de6b Initial load
duke
parents:
diff changeset
   261
   * @return The sum of the evaluation value on each node
7f561c08de6b Initial load
duke
parents:
diff changeset
   262
   */
7f561c08de6b Initial load
duke
parents:
diff changeset
   263
  public static double sum(ExpressionContext myContext, NodeList nl, String expr)
7f561c08de6b Initial load
duke
parents:
diff changeset
   264
    throws SAXNotSupportedException
7f561c08de6b Initial load
duke
parents:
diff changeset
   265
  {
7f561c08de6b Initial load
duke
parents:
diff changeset
   266
    XPathContext xctxt = null;
7f561c08de6b Initial load
duke
parents:
diff changeset
   267
    if (myContext instanceof XPathContext.XPathExpressionContext)
7f561c08de6b Initial load
duke
parents:
diff changeset
   268
      xctxt = ((XPathContext.XPathExpressionContext) myContext).getXPathContext();
7f561c08de6b Initial load
duke
parents:
diff changeset
   269
    else
7f561c08de6b Initial load
duke
parents:
diff changeset
   270
      throw new SAXNotSupportedException(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_CONTEXT_PASSED, new Object[]{myContext }));
7f561c08de6b Initial load
duke
parents:
diff changeset
   271
7f561c08de6b Initial load
duke
parents:
diff changeset
   272
    if (expr == null || expr.length() == 0)
7f561c08de6b Initial load
duke
parents:
diff changeset
   273
      return Double.NaN;
7f561c08de6b Initial load
duke
parents:
diff changeset
   274
7f561c08de6b Initial load
duke
parents:
diff changeset
   275
    NodeSetDTM contextNodes = new NodeSetDTM(nl, xctxt);
7f561c08de6b Initial load
duke
parents:
diff changeset
   276
    xctxt.pushContextNodeList(contextNodes);
7f561c08de6b Initial load
duke
parents:
diff changeset
   277
7f561c08de6b Initial load
duke
parents:
diff changeset
   278
    double sum = 0;
7f561c08de6b Initial load
duke
parents:
diff changeset
   279
    for (int i = 0; i < nl.getLength(); i++)
7f561c08de6b Initial load
duke
parents:
diff changeset
   280
    {
7f561c08de6b Initial load
duke
parents:
diff changeset
   281
      int contextNode = contextNodes.item(i);
7f561c08de6b Initial load
duke
parents:
diff changeset
   282
      xctxt.pushCurrentNode(contextNode);
7f561c08de6b Initial load
duke
parents:
diff changeset
   283
7f561c08de6b Initial load
duke
parents:
diff changeset
   284
      double result = 0;
7f561c08de6b Initial load
duke
parents:
diff changeset
   285
      try
7f561c08de6b Initial load
duke
parents:
diff changeset
   286
      {
7f561c08de6b Initial load
duke
parents:
diff changeset
   287
        XPath dynamicXPath = new XPath(expr, xctxt.getSAXLocator(),
7f561c08de6b Initial load
duke
parents:
diff changeset
   288
                                       xctxt.getNamespaceContext(),
7f561c08de6b Initial load
duke
parents:
diff changeset
   289
                                       XPath.SELECT);
7f561c08de6b Initial load
duke
parents:
diff changeset
   290
        result = dynamicXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext()).num();
7f561c08de6b Initial load
duke
parents:
diff changeset
   291
      }
7f561c08de6b Initial load
duke
parents:
diff changeset
   292
      catch (TransformerException e)
7f561c08de6b Initial load
duke
parents:
diff changeset
   293
      {
7f561c08de6b Initial load
duke
parents:
diff changeset
   294
        xctxt.popCurrentNode();
7f561c08de6b Initial load
duke
parents:
diff changeset
   295
        xctxt.popContextNodeList();
7f561c08de6b Initial load
duke
parents:
diff changeset
   296
        return Double.NaN;
7f561c08de6b Initial load
duke
parents:
diff changeset
   297
      }
7f561c08de6b Initial load
duke
parents:
diff changeset
   298
7f561c08de6b Initial load
duke
parents:
diff changeset
   299
      xctxt.popCurrentNode();
7f561c08de6b Initial load
duke
parents:
diff changeset
   300
7f561c08de6b Initial load
duke
parents:
diff changeset
   301
      sum = sum + result;
7f561c08de6b Initial load
duke
parents:
diff changeset
   302
7f561c08de6b Initial load
duke
parents:
diff changeset
   303
    }
7f561c08de6b Initial load
duke
parents:
diff changeset
   304
7f561c08de6b Initial load
duke
parents:
diff changeset
   305
    xctxt.popContextNodeList();
7f561c08de6b Initial load
duke
parents:
diff changeset
   306
    return sum;
7f561c08de6b Initial load
duke
parents:
diff changeset
   307
  }
7f561c08de6b Initial load
duke
parents:
diff changeset
   308
7f561c08de6b Initial load
duke
parents:
diff changeset
   309
  /**
7f561c08de6b Initial load
duke
parents:
diff changeset
   310
   * The dyn:map function evaluates the expression passed as the second argument for
7f561c08de6b Initial load
duke
parents:
diff changeset
   311
   * each of the nodes passed as the first argument, and returns a node set of those values.
7f561c08de6b Initial load
duke
parents:
diff changeset
   312
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   313
   * The expressions are evaluated relative to the nodes passed as the first argument.
7f561c08de6b Initial load
duke
parents:
diff changeset
   314
   * In other words, the value for each node is calculated by evaluating the XPath
7f561c08de6b Initial load
duke
parents:
diff changeset
   315
   * expression with all context information being the same as that for the call to
7f561c08de6b Initial load
duke
parents:
diff changeset
   316
   * the dyn:map function itself, except for the following:
7f561c08de6b Initial load
duke
parents:
diff changeset
   317
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   318
   * <ul>
7f561c08de6b Initial load
duke
parents:
diff changeset
   319
   *  <li>The context node is the node whose value is being calculated.</li>
7f561c08de6b Initial load
duke
parents:
diff changeset
   320
   *  <li>the context position is the position of the node within the node set passed
7f561c08de6b Initial load
duke
parents:
diff changeset
   321
   *    as the first argument to the dyn:map function, arranged in document order.</li>
7f561c08de6b Initial load
duke
parents:
diff changeset
   322
   *  <li>the context size is the number of nodes passed as the first argument to the
7f561c08de6b Initial load
duke
parents:
diff changeset
   323
   *    dyn:map function.</li>
7f561c08de6b Initial load
duke
parents:
diff changeset
   324
   * </ul>
7f561c08de6b Initial load
duke
parents:
diff changeset
   325
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   326
   * If the expression string passed as the second argument is an invalid XPath
7f561c08de6b Initial load
duke
parents:
diff changeset
   327
   * expression (including an empty string), this function returns an empty node set.
7f561c08de6b Initial load
duke
parents:
diff changeset
   328
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   329
   * If the XPath expression evaluates as a node set, the dyn:map function returns
7f561c08de6b Initial load
duke
parents:
diff changeset
   330
   * the union of the node sets returned by evaluating the expression for each of the
7f561c08de6b Initial load
duke
parents:
diff changeset
   331
   * nodes in the first argument. Note that this may mean that the node set resulting
7f561c08de6b Initial load
duke
parents:
diff changeset
   332
   * from the call to the dyn:map function contains a different number of nodes from
7f561c08de6b Initial load
duke
parents:
diff changeset
   333
   * the number in the node set passed as the first argument to the function.
7f561c08de6b Initial load
duke
parents:
diff changeset
   334
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   335
   * If the XPath expression evaluates as a number, the dyn:map function returns a
7f561c08de6b Initial load
duke
parents:
diff changeset
   336
   * node set containing one exsl:number element (namespace http://exslt.org/common)
7f561c08de6b Initial load
duke
parents:
diff changeset
   337
   * for each node in the node set passed as the first argument to the dyn:map function,
7f561c08de6b Initial load
duke
parents:
diff changeset
   338
   * in document order. The string value of each exsl:number element is the same as
7f561c08de6b Initial load
duke
parents:
diff changeset
   339
   * the result of converting the number resulting from evaluating the expression to
7f561c08de6b Initial load
duke
parents:
diff changeset
   340
   * a string as with the number function, with the exception that Infinity results
7f561c08de6b Initial load
duke
parents:
diff changeset
   341
   * in an exsl:number holding the highest number the implementation can store, and
7f561c08de6b Initial load
duke
parents:
diff changeset
   342
   * -Infinity results in an exsl:number holding the lowest number the implementation
7f561c08de6b Initial load
duke
parents:
diff changeset
   343
   * can store.
7f561c08de6b Initial load
duke
parents:
diff changeset
   344
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   345
   * If the XPath expression evaluates as a boolean, the dyn:map function returns a
7f561c08de6b Initial load
duke
parents:
diff changeset
   346
   * node set containing one exsl:boolean element (namespace http://exslt.org/common)
7f561c08de6b Initial load
duke
parents:
diff changeset
   347
   * for each node in the node set passed as the first argument to the dyn:map function,
7f561c08de6b Initial load
duke
parents:
diff changeset
   348
   * in document order. The string value of each exsl:boolean element is 'true' if the
7f561c08de6b Initial load
duke
parents:
diff changeset
   349
   * expression evaluates as true for the node, and '' if the expression evaluates as
7f561c08de6b Initial load
duke
parents:
diff changeset
   350
   * false.
7f561c08de6b Initial load
duke
parents:
diff changeset
   351
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   352
   * Otherwise, the dyn:map function returns a node set containing one exsl:string
7f561c08de6b Initial load
duke
parents:
diff changeset
   353
   * element (namespace http://exslt.org/common) for each node in the node set passed
7f561c08de6b Initial load
duke
parents:
diff changeset
   354
   * as the first argument to the dyn:map function, in document order. The string
7f561c08de6b Initial load
duke
parents:
diff changeset
   355
   * value of each exsl:string element is the same as the result of converting the
7f561c08de6b Initial load
duke
parents:
diff changeset
   356
   * result of evaluating the expression for the relevant node to a string as with
7f561c08de6b Initial load
duke
parents:
diff changeset
   357
   * the string function.
7f561c08de6b Initial load
duke
parents:
diff changeset
   358
   *
7f561c08de6b Initial load
duke
parents:
diff changeset
   359
   * @param myContext The ExpressionContext passed by the extension processor
7f561c08de6b Initial load
duke
parents:
diff changeset
   360
   * @param nl The node set
7f561c08de6b Initial load
duke
parents:
diff changeset
   361
   * @param expr The expression string
7f561c08de6b Initial load
duke
parents:
diff changeset
   362
   *
7f561c08de6b Initial load
duke
parents:
diff changeset
   363
   * @return The node set after evaluation
7f561c08de6b Initial load
duke
parents:
diff changeset
   364
   */
7f561c08de6b Initial load
duke
parents:
diff changeset
   365
  public static NodeList map(ExpressionContext myContext, NodeList nl, String expr)
7f561c08de6b Initial load
duke
parents:
diff changeset
   366
    throws SAXNotSupportedException
7f561c08de6b Initial load
duke
parents:
diff changeset
   367
  {
7f561c08de6b Initial load
duke
parents:
diff changeset
   368
    XPathContext xctxt = null;
7f561c08de6b Initial load
duke
parents:
diff changeset
   369
    Document lDoc = null;
7f561c08de6b Initial load
duke
parents:
diff changeset
   370
7f561c08de6b Initial load
duke
parents:
diff changeset
   371
    if (myContext instanceof XPathContext.XPathExpressionContext)
7f561c08de6b Initial load
duke
parents:
diff changeset
   372
      xctxt = ((XPathContext.XPathExpressionContext) myContext).getXPathContext();
7f561c08de6b Initial load
duke
parents:
diff changeset
   373
    else
7f561c08de6b Initial load
duke
parents:
diff changeset
   374
      throw new SAXNotSupportedException(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_CONTEXT_PASSED, new Object[]{myContext }));
7f561c08de6b Initial load
duke
parents:
diff changeset
   375
7f561c08de6b Initial load
duke
parents:
diff changeset
   376
    if (expr == null || expr.length() == 0)
7f561c08de6b Initial load
duke
parents:
diff changeset
   377
      return new NodeSet();
7f561c08de6b Initial load
duke
parents:
diff changeset
   378
7f561c08de6b Initial load
duke
parents:
diff changeset
   379
    NodeSetDTM contextNodes = new NodeSetDTM(nl, xctxt);
7f561c08de6b Initial load
duke
parents:
diff changeset
   380
    xctxt.pushContextNodeList(contextNodes);
7f561c08de6b Initial load
duke
parents:
diff changeset
   381
7f561c08de6b Initial load
duke
parents:
diff changeset
   382
    NodeSet resultSet = new NodeSet();
7f561c08de6b Initial load
duke
parents:
diff changeset
   383
    resultSet.setShouldCacheNodes(true);
7f561c08de6b Initial load
duke
parents:
diff changeset
   384
7f561c08de6b Initial load
duke
parents:
diff changeset
   385
    for (int i = 0; i < nl.getLength(); i++)
7f561c08de6b Initial load
duke
parents:
diff changeset
   386
    {
7f561c08de6b Initial load
duke
parents:
diff changeset
   387
      int contextNode = contextNodes.item(i);
7f561c08de6b Initial load
duke
parents:
diff changeset
   388
      xctxt.pushCurrentNode(contextNode);
7f561c08de6b Initial load
duke
parents:
diff changeset
   389
7f561c08de6b Initial load
duke
parents:
diff changeset
   390
      XObject object = null;
7f561c08de6b Initial load
duke
parents:
diff changeset
   391
      try
7f561c08de6b Initial load
duke
parents:
diff changeset
   392
      {
7f561c08de6b Initial load
duke
parents:
diff changeset
   393
        XPath dynamicXPath = new XPath(expr, xctxt.getSAXLocator(),
7f561c08de6b Initial load
duke
parents:
diff changeset
   394
                                       xctxt.getNamespaceContext(),
7f561c08de6b Initial load
duke
parents:
diff changeset
   395
                                       XPath.SELECT);
7f561c08de6b Initial load
duke
parents:
diff changeset
   396
        object = dynamicXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext());
7f561c08de6b Initial load
duke
parents:
diff changeset
   397
7f561c08de6b Initial load
duke
parents:
diff changeset
   398
        if (object instanceof XNodeSet)
7f561c08de6b Initial load
duke
parents:
diff changeset
   399
        {
7f561c08de6b Initial load
duke
parents:
diff changeset
   400
          NodeList nodelist = null;
7f561c08de6b Initial load
duke
parents:
diff changeset
   401
          nodelist = ((XNodeSet)object).nodelist();
7f561c08de6b Initial load
duke
parents:
diff changeset
   402
7f561c08de6b Initial load
duke
parents:
diff changeset
   403
          for (int k = 0; k < nodelist.getLength(); k++)
7f561c08de6b Initial load
duke
parents:
diff changeset
   404
          {
7f561c08de6b Initial load
duke
parents:
diff changeset
   405
            Node n = nodelist.item(k);
7f561c08de6b Initial load
duke
parents:
diff changeset
   406
            if (!resultSet.contains(n))
7f561c08de6b Initial load
duke
parents:
diff changeset
   407
              resultSet.addNode(n);
7f561c08de6b Initial load
duke
parents:
diff changeset
   408
          }
7f561c08de6b Initial load
duke
parents:
diff changeset
   409
        }
7f561c08de6b Initial load
duke
parents:
diff changeset
   410
        else
7f561c08de6b Initial load
duke
parents:
diff changeset
   411
        {
7f561c08de6b Initial load
duke
parents:
diff changeset
   412
          if (lDoc == null)
7f561c08de6b Initial load
duke
parents:
diff changeset
   413
          {
7f561c08de6b Initial load
duke
parents:
diff changeset
   414
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
7f561c08de6b Initial load
duke
parents:
diff changeset
   415
            dbf.setNamespaceAware(true);
7f561c08de6b Initial load
duke
parents:
diff changeset
   416
            DocumentBuilder db = dbf.newDocumentBuilder();
7f561c08de6b Initial load
duke
parents:
diff changeset
   417
            lDoc = db.newDocument();
7f561c08de6b Initial load
duke
parents:
diff changeset
   418
          }
7f561c08de6b Initial load
duke
parents:
diff changeset
   419
7f561c08de6b Initial load
duke
parents:
diff changeset
   420
          Element element = null;
7f561c08de6b Initial load
duke
parents:
diff changeset
   421
          if (object instanceof XNumber)
7f561c08de6b Initial load
duke
parents:
diff changeset
   422
            element = lDoc.createElementNS(EXSL_URI, "exsl:number");
7f561c08de6b Initial load
duke
parents:
diff changeset
   423
          else if (object instanceof XBoolean)
7f561c08de6b Initial load
duke
parents:
diff changeset
   424
            element = lDoc.createElementNS(EXSL_URI, "exsl:boolean");
7f561c08de6b Initial load
duke
parents:
diff changeset
   425
          else
7f561c08de6b Initial load
duke
parents:
diff changeset
   426
            element = lDoc.createElementNS(EXSL_URI, "exsl:string");
7f561c08de6b Initial load
duke
parents:
diff changeset
   427
7f561c08de6b Initial load
duke
parents:
diff changeset
   428
          Text textNode = lDoc.createTextNode(object.str());
7f561c08de6b Initial load
duke
parents:
diff changeset
   429
          element.appendChild(textNode);
7f561c08de6b Initial load
duke
parents:
diff changeset
   430
          resultSet.addNode(element);
7f561c08de6b Initial load
duke
parents:
diff changeset
   431
        }
7f561c08de6b Initial load
duke
parents:
diff changeset
   432
      }
7f561c08de6b Initial load
duke
parents:
diff changeset
   433
      catch (Exception e)
7f561c08de6b Initial load
duke
parents:
diff changeset
   434
      {
7f561c08de6b Initial load
duke
parents:
diff changeset
   435
        xctxt.popCurrentNode();
7f561c08de6b Initial load
duke
parents:
diff changeset
   436
        xctxt.popContextNodeList();
7f561c08de6b Initial load
duke
parents:
diff changeset
   437
        return new NodeSet();
7f561c08de6b Initial load
duke
parents:
diff changeset
   438
      }
7f561c08de6b Initial load
duke
parents:
diff changeset
   439
7f561c08de6b Initial load
duke
parents:
diff changeset
   440
      xctxt.popCurrentNode();
7f561c08de6b Initial load
duke
parents:
diff changeset
   441
7f561c08de6b Initial load
duke
parents:
diff changeset
   442
    }
7f561c08de6b Initial load
duke
parents:
diff changeset
   443
7f561c08de6b Initial load
duke
parents:
diff changeset
   444
    xctxt.popContextNodeList();
7f561c08de6b Initial load
duke
parents:
diff changeset
   445
    return resultSet;
7f561c08de6b Initial load
duke
parents:
diff changeset
   446
  }
7f561c08de6b Initial load
duke
parents:
diff changeset
   447
7f561c08de6b Initial load
duke
parents:
diff changeset
   448
  /**
7f561c08de6b Initial load
duke
parents:
diff changeset
   449
   * The dyn:evaluate function evaluates a string as an XPath expression and returns
7f561c08de6b Initial load
duke
parents:
diff changeset
   450
   * the resulting value, which might be a boolean, number, string, node set, result
7f561c08de6b Initial load
duke
parents:
diff changeset
   451
   * tree fragment or external object. The sole argument is the string to be evaluated.
7f561c08de6b Initial load
duke
parents:
diff changeset
   452
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   453
   * If the expression string passed as the second argument is an invalid XPath
7f561c08de6b Initial load
duke
parents:
diff changeset
   454
   * expression (including an empty string), this function returns an empty node set.
7f561c08de6b Initial load
duke
parents:
diff changeset
   455
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   456
   * You should only use this function if the expression must be constructed dynamically,
7f561c08de6b Initial load
duke
parents:
diff changeset
   457
   * otherwise it is much more efficient to use the expression literally.
7f561c08de6b Initial load
duke
parents:
diff changeset
   458
   *
7f561c08de6b Initial load
duke
parents:
diff changeset
   459
   * @param myContext The ExpressionContext passed by the extension processor
7f561c08de6b Initial load
duke
parents:
diff changeset
   460
   * @param xpathExpr The XPath expression string
7f561c08de6b Initial load
duke
parents:
diff changeset
   461
   *
7f561c08de6b Initial load
duke
parents:
diff changeset
   462
   * @return The evaluation result
7f561c08de6b Initial load
duke
parents:
diff changeset
   463
   */
7f561c08de6b Initial load
duke
parents:
diff changeset
   464
  public static XObject evaluate(ExpressionContext myContext, String xpathExpr)
7f561c08de6b Initial load
duke
parents:
diff changeset
   465
    throws SAXNotSupportedException
7f561c08de6b Initial load
duke
parents:
diff changeset
   466
  {
7f561c08de6b Initial load
duke
parents:
diff changeset
   467
    if (myContext instanceof XPathContext.XPathExpressionContext)
7f561c08de6b Initial load
duke
parents:
diff changeset
   468
    {
7f561c08de6b Initial load
duke
parents:
diff changeset
   469
      XPathContext xctxt = null;
7f561c08de6b Initial load
duke
parents:
diff changeset
   470
      try
7f561c08de6b Initial load
duke
parents:
diff changeset
   471
      {
7f561c08de6b Initial load
duke
parents:
diff changeset
   472
        xctxt = ((XPathContext.XPathExpressionContext) myContext).getXPathContext();
7f561c08de6b Initial load
duke
parents:
diff changeset
   473
        XPath dynamicXPath = new XPath(xpathExpr, xctxt.getSAXLocator(),
7f561c08de6b Initial load
duke
parents:
diff changeset
   474
                                       xctxt.getNamespaceContext(),
7f561c08de6b Initial load
duke
parents:
diff changeset
   475
                                       XPath.SELECT);
7f561c08de6b Initial load
duke
parents:
diff changeset
   476
7f561c08de6b Initial load
duke
parents:
diff changeset
   477
        return dynamicXPath.execute(xctxt, myContext.getContextNode(),
7f561c08de6b Initial load
duke
parents:
diff changeset
   478
                                    xctxt.getNamespaceContext());
7f561c08de6b Initial load
duke
parents:
diff changeset
   479
      }
7f561c08de6b Initial load
duke
parents:
diff changeset
   480
      catch (TransformerException e)
7f561c08de6b Initial load
duke
parents:
diff changeset
   481
      {
7f561c08de6b Initial load
duke
parents:
diff changeset
   482
        return new XNodeSet(xctxt.getDTMManager());
7f561c08de6b Initial load
duke
parents:
diff changeset
   483
      }
7f561c08de6b Initial load
duke
parents:
diff changeset
   484
    }
7f561c08de6b Initial load
duke
parents:
diff changeset
   485
    else
7f561c08de6b Initial load
duke
parents:
diff changeset
   486
      throw new SAXNotSupportedException(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_CONTEXT_PASSED, new Object[]{myContext })); //"Invalid context passed to evaluate "
7f561c08de6b Initial load
duke
parents:
diff changeset
   487
  }
7f561c08de6b Initial load
duke
parents:
diff changeset
   488
7f561c08de6b Initial load
duke
parents:
diff changeset
   489
  /**
7f561c08de6b Initial load
duke
parents:
diff changeset
   490
   * The dyn:closure function creates a node set resulting from transitive closure of
7f561c08de6b Initial load
duke
parents:
diff changeset
   491
   * evaluating the expression passed as the second argument on each of the nodes passed
7f561c08de6b Initial load
duke
parents:
diff changeset
   492
   * as the first argument, then on the node set resulting from that and so on until no
7f561c08de6b Initial load
duke
parents:
diff changeset
   493
   * more nodes are found. For example:
7f561c08de6b Initial load
duke
parents:
diff changeset
   494
   * <pre>
7f561c08de6b Initial load
duke
parents:
diff changeset
   495
   *  dyn:closure(., '*')
7f561c08de6b Initial load
duke
parents:
diff changeset
   496
   * </pre>
7f561c08de6b Initial load
duke
parents:
diff changeset
   497
   * returns all the descendant elements of the node (its element children, their
7f561c08de6b Initial load
duke
parents:
diff changeset
   498
   * children, their children's children and so on).
7f561c08de6b Initial load
duke
parents:
diff changeset
   499
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   500
   * The expression is thus evaluated several times, each with a different node set
7f561c08de6b Initial load
duke
parents:
diff changeset
   501
   * acting as the context of the expression. The first time the expression is
7f561c08de6b Initial load
duke
parents:
diff changeset
   502
   * evaluated, the context node set is the first argument passed to the dyn:closure
7f561c08de6b Initial load
duke
parents:
diff changeset
   503
   * function. In other words, the node set for each node is calculated by evaluating
7f561c08de6b Initial load
duke
parents:
diff changeset
   504
   * the XPath expression with all context information being the same as that for
7f561c08de6b Initial load
duke
parents:
diff changeset
   505
   * the call to the dyn:closure function itself, except for the following:
7f561c08de6b Initial load
duke
parents:
diff changeset
   506
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   507
   * <ul>
7f561c08de6b Initial load
duke
parents:
diff changeset
   508
   *  <li>the context node is the node whose value is being calculated.</li>
7f561c08de6b Initial load
duke
parents:
diff changeset
   509
   *  <li>the context position is the position of the node within the node set passed
7f561c08de6b Initial load
duke
parents:
diff changeset
   510
   *    as the first argument to the dyn:closure function, arranged in document order.</li>
7f561c08de6b Initial load
duke
parents:
diff changeset
   511
   *  <li>the context size is the number of nodes passed as the first argument to the
7f561c08de6b Initial load
duke
parents:
diff changeset
   512
   *    dyn:closure function.</li>
7f561c08de6b Initial load
duke
parents:
diff changeset
   513
   *  <li>the current node is the node whose value is being calculated.</li>
7f561c08de6b Initial load
duke
parents:
diff changeset
   514
   * </ul>
7f561c08de6b Initial load
duke
parents:
diff changeset
   515
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   516
   * The result for a particular iteration is the union of the node sets resulting
7f561c08de6b Initial load
duke
parents:
diff changeset
   517
   * from evaluting the expression for each of the nodes in the source node set for
7f561c08de6b Initial load
duke
parents:
diff changeset
   518
   * that iteration. This result is then used as the source node set for the next
7f561c08de6b Initial load
duke
parents:
diff changeset
   519
   * iteration, and so on. The result of the function as a whole is the union of
7f561c08de6b Initial load
duke
parents:
diff changeset
   520
   * the node sets generated by each iteration.
7f561c08de6b Initial load
duke
parents:
diff changeset
   521
   * <p>
7f561c08de6b Initial load
duke
parents:
diff changeset
   522
   * If the expression string passed as the second argument is an invalid XPath
7f561c08de6b Initial load
duke
parents:
diff changeset
   523
   * expression (including an empty string) or an expression that does not return a
7f561c08de6b Initial load
duke
parents:
diff changeset
   524
   * node set, this function returns an empty node set.
7f561c08de6b Initial load
duke
parents:
diff changeset
   525
   *
7f561c08de6b Initial load
duke
parents:
diff changeset
   526
   * @param myContext The ExpressionContext passed by the extension processor
7f561c08de6b Initial load
duke
parents:
diff changeset
   527
   * @param nl The node set
7f561c08de6b Initial load
duke
parents:
diff changeset
   528
   * @param expr The expression string
7f561c08de6b Initial load
duke
parents:
diff changeset
   529
   *
7f561c08de6b Initial load
duke
parents:
diff changeset
   530
   * @return The node set after evaluation
7f561c08de6b Initial load
duke
parents:
diff changeset
   531
   */
7f561c08de6b Initial load
duke
parents:
diff changeset
   532
  public static NodeList closure(ExpressionContext myContext, NodeList nl, String expr)
7f561c08de6b Initial load
duke
parents:
diff changeset
   533
    throws SAXNotSupportedException
7f561c08de6b Initial load
duke
parents:
diff changeset
   534
  {
7f561c08de6b Initial load
duke
parents:
diff changeset
   535
    XPathContext xctxt = null;
7f561c08de6b Initial load
duke
parents:
diff changeset
   536
    if (myContext instanceof XPathContext.XPathExpressionContext)
7f561c08de6b Initial load
duke
parents:
diff changeset
   537
      xctxt = ((XPathContext.XPathExpressionContext) myContext).getXPathContext();
7f561c08de6b Initial load
duke
parents:
diff changeset
   538
    else
7f561c08de6b Initial load
duke
parents:
diff changeset
   539
      throw new SAXNotSupportedException(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_CONTEXT_PASSED, new Object[]{myContext }));
7f561c08de6b Initial load
duke
parents:
diff changeset
   540
7f561c08de6b Initial load
duke
parents:
diff changeset
   541
    if (expr == null || expr.length() == 0)
7f561c08de6b Initial load
duke
parents:
diff changeset
   542
      return new NodeSet();
7f561c08de6b Initial load
duke
parents:
diff changeset
   543
7f561c08de6b Initial load
duke
parents:
diff changeset
   544
    NodeSet closureSet = new NodeSet();
7f561c08de6b Initial load
duke
parents:
diff changeset
   545
    closureSet.setShouldCacheNodes(true);
7f561c08de6b Initial load
duke
parents:
diff changeset
   546
7f561c08de6b Initial load
duke
parents:
diff changeset
   547
    NodeList iterationList = nl;
7f561c08de6b Initial load
duke
parents:
diff changeset
   548
    do
7f561c08de6b Initial load
duke
parents:
diff changeset
   549
    {
7f561c08de6b Initial load
duke
parents:
diff changeset
   550
7f561c08de6b Initial load
duke
parents:
diff changeset
   551
      NodeSet iterationSet = new NodeSet();
7f561c08de6b Initial load
duke
parents:
diff changeset
   552
7f561c08de6b Initial load
duke
parents:
diff changeset
   553
      NodeSetDTM contextNodes = new NodeSetDTM(iterationList, xctxt);
7f561c08de6b Initial load
duke
parents:
diff changeset
   554
      xctxt.pushContextNodeList(contextNodes);
7f561c08de6b Initial load
duke
parents:
diff changeset
   555
7f561c08de6b Initial load
duke
parents:
diff changeset
   556
      for (int i = 0; i < iterationList.getLength(); i++)
7f561c08de6b Initial load
duke
parents:
diff changeset
   557
      {
7f561c08de6b Initial load
duke
parents:
diff changeset
   558
        int contextNode = contextNodes.item(i);
7f561c08de6b Initial load
duke
parents:
diff changeset
   559
        xctxt.pushCurrentNode(contextNode);
7f561c08de6b Initial load
duke
parents:
diff changeset
   560
7f561c08de6b Initial load
duke
parents:
diff changeset
   561
        XObject object = null;
7f561c08de6b Initial load
duke
parents:
diff changeset
   562
        try
7f561c08de6b Initial load
duke
parents:
diff changeset
   563
        {
7f561c08de6b Initial load
duke
parents:
diff changeset
   564
          XPath dynamicXPath = new XPath(expr, xctxt.getSAXLocator(),
7f561c08de6b Initial load
duke
parents:
diff changeset
   565
                                         xctxt.getNamespaceContext(),
7f561c08de6b Initial load
duke
parents:
diff changeset
   566
                                         XPath.SELECT);
7f561c08de6b Initial load
duke
parents:
diff changeset
   567
          object = dynamicXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext());
7f561c08de6b Initial load
duke
parents:
diff changeset
   568
7f561c08de6b Initial load
duke
parents:
diff changeset
   569
          if (object instanceof XNodeSet)
7f561c08de6b Initial load
duke
parents:
diff changeset
   570
          {
7f561c08de6b Initial load
duke
parents:
diff changeset
   571
            NodeList nodelist = null;
7f561c08de6b Initial load
duke
parents:
diff changeset
   572
            nodelist = ((XNodeSet)object).nodelist();
7f561c08de6b Initial load
duke
parents:
diff changeset
   573
7f561c08de6b Initial load
duke
parents:
diff changeset
   574
            for (int k = 0; k < nodelist.getLength(); k++)
7f561c08de6b Initial load
duke
parents:
diff changeset
   575
            {
7f561c08de6b Initial load
duke
parents:
diff changeset
   576
              Node n = nodelist.item(k);
7f561c08de6b Initial load
duke
parents:
diff changeset
   577
              if (!iterationSet.contains(n))
7f561c08de6b Initial load
duke
parents:
diff changeset
   578
                iterationSet.addNode(n);
7f561c08de6b Initial load
duke
parents:
diff changeset
   579
            }
7f561c08de6b Initial load
duke
parents:
diff changeset
   580
          }
7f561c08de6b Initial load
duke
parents:
diff changeset
   581
          else
7f561c08de6b Initial load
duke
parents:
diff changeset
   582
          {
7f561c08de6b Initial load
duke
parents:
diff changeset
   583
            xctxt.popCurrentNode();
7f561c08de6b Initial load
duke
parents:
diff changeset
   584
            xctxt.popContextNodeList();
7f561c08de6b Initial load
duke
parents:
diff changeset
   585
            return new NodeSet();
7f561c08de6b Initial load
duke
parents:
diff changeset
   586
          }
7f561c08de6b Initial load
duke
parents:
diff changeset
   587
        }
7f561c08de6b Initial load
duke
parents:
diff changeset
   588
        catch (TransformerException e)
7f561c08de6b Initial load
duke
parents:
diff changeset
   589
        {
7f561c08de6b Initial load
duke
parents:
diff changeset
   590
          xctxt.popCurrentNode();
7f561c08de6b Initial load
duke
parents:
diff changeset
   591
          xctxt.popContextNodeList();
7f561c08de6b Initial load
duke
parents:
diff changeset
   592
          return new NodeSet();
7f561c08de6b Initial load
duke
parents:
diff changeset
   593
        }
7f561c08de6b Initial load
duke
parents:
diff changeset
   594
7f561c08de6b Initial load
duke
parents:
diff changeset
   595
        xctxt.popCurrentNode();
7f561c08de6b Initial load
duke
parents:
diff changeset
   596
7f561c08de6b Initial load
duke
parents:
diff changeset
   597
      }
7f561c08de6b Initial load
duke
parents:
diff changeset
   598
7f561c08de6b Initial load
duke
parents:
diff changeset
   599
      xctxt.popContextNodeList();
7f561c08de6b Initial load
duke
parents:
diff changeset
   600
7f561c08de6b Initial load
duke
parents:
diff changeset
   601
      iterationList = iterationSet;
7f561c08de6b Initial load
duke
parents:
diff changeset
   602
7f561c08de6b Initial load
duke
parents:
diff changeset
   603
      for (int i = 0; i < iterationList.getLength(); i++)
7f561c08de6b Initial load
duke
parents:
diff changeset
   604
      {
7f561c08de6b Initial load
duke
parents:
diff changeset
   605
        Node n = iterationList.item(i);
7f561c08de6b Initial load
duke
parents:
diff changeset
   606
        if (!closureSet.contains(n))
7f561c08de6b Initial load
duke
parents:
diff changeset
   607
          closureSet.addNode(n);
7f561c08de6b Initial load
duke
parents:
diff changeset
   608
      }
7f561c08de6b Initial load
duke
parents:
diff changeset
   609
7f561c08de6b Initial load
duke
parents:
diff changeset
   610
    } while(iterationList.getLength() > 0);
7f561c08de6b Initial load
duke
parents:
diff changeset
   611
7f561c08de6b Initial load
duke
parents:
diff changeset
   612
    return closureSet;
7f561c08de6b Initial load
duke
parents:
diff changeset
   613
7f561c08de6b Initial load
duke
parents:
diff changeset
   614
  }
7f561c08de6b Initial load
duke
parents:
diff changeset
   615
7f561c08de6b Initial load
duke
parents:
diff changeset
   616
}