All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.org.apache.xalan.internal.lib.ExsltDynamic Maven / Gradle / Ivy

The newest version!
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 *
 *
 * This file incorporates work covered by the following copyright and
 * permission notice:
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.9 2010-11-01 04:34:11 joehw 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:
 * 
 *    xmlns:dyn="http://exslt.org/dynamic"
 * 
* The documentation for each function has been copied from the relevant * EXSLT Implementer page. * * @see 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. *

* 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: *

*

    *
  • the context node is the node whose value is being calculated.
  • *
  • 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.
  • *
  • the context size is the number of nodes passed as the first argument to the * dyn:max function.
  • *
*

* The dyn:max function returns the maximum of these values, calculated in exactly * the same way as for math:max. *

* If the expression string passed as the second argument is an invalid XPath * expression (including an empty string), this function returns NaN. *

* 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. *

* 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: *

*

    *
  • the context node is the node whose value is being calculated.
  • *
  • 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.
  • *
  • the context size is the number of nodes passed as the first argument to the * dyn:min function.
  • *
*

* The dyn:min function returns the minimum of these values, calculated in exactly * the same way as for math:min. *

* If the expression string passed as the second argument is an invalid XPath expression * (including an empty string), this function returns NaN. *

* 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. *

* 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: *

*

    *
  • the context node is the node whose value is being calculated.
  • *
  • 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.
  • *
  • the context size is the number of nodes passed as the first argument to the * dyn:sum function.
  • *
*

* The dyn:sum function returns the sumimum of these values, calculated in exactly * the same way as for sum. *

* If the expression string passed as the second argument is an invalid XPath * expression (including an empty string), this function returns NaN. *

* 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. *

* 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: *

*

    *
  • The context node is the node whose value is being calculated.
  • *
  • 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.
  • *
  • the context size is the number of nodes passed as the first argument to the * dyn:map function.
  • *
*

* 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. *

* 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. *

* 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. *

* 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. *

* 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. *

* 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. *

* 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: *

   *  dyn:closure(., '*')
   * 
* returns all the descendant elements of the node (its element children, their * children, their children's children and so on). *

* 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: *

*

    *
  • the context node is the node whose value is being calculated.
  • *
  • 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.
  • *
  • the context size is the number of nodes passed as the first argument to the * dyn:closure function.
  • *
  • the current node is the node whose value is being calculated.
  • *
*

* 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. *

* 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; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy