jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java
changeset 28695 427254b89b9e
parent 25868 686eef1e7a79
child 39907 db51759e3695
equal deleted inserted replaced
28694:b99e1eee0669 28695:427254b89b9e
     1 /*
     1 /*
     2  * reserved comment block
     2  * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT REMOVE OR ALTER!
       
     4  */
     3  */
     5 /*
     4 /*
     6  * Copyright 1999-2004 The Apache Software Foundation.
     5  * Licensed to the Apache Software Foundation (ASF) under one or more
       
     6  * contributor license agreements.  See the NOTICE file distributed with
       
     7  * this work for additional information regarding copyright ownership.
       
     8  * The ASF licenses this file to You under the Apache License, Version 2.0
       
     9  * (the "License"); you may not use this file except in compliance with
       
    10  * the License.  You may obtain a copy of the License at
     7  *
    11  *
     8  * Licensed under the Apache License, Version 2.0 (the "License");
    12  *      http://www.apache.org/licenses/LICENSE-2.0
     9  * you may not use this file except in compliance with the License.
       
    10  * You may obtain a copy of the License at
       
    11  *
       
    12  *     http://www.apache.org/licenses/LICENSE-2.0
       
    13  *
    13  *
    14  * Unless required by applicable law or agreed to in writing, software
    14  * Unless required by applicable law or agreed to in writing, software
    15  * distributed under the License is distributed on an "AS IS" BASIS,
    15  * distributed under the License is distributed on an "AS IS" BASIS,
    16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    17  * See the License for the specific language governing permissions and
    17  * See the License for the specific language governing permissions and
    18  * limitations under the License.
    18  * limitations under the License.
    19  */
    19  */
    20 // $Id: XPathExpressionImpl.java,v 1.3 2005/09/27 09:40:43 sunithareddy Exp $
       
    21 
    20 
    22 package com.sun.org.apache.xpath.internal.jaxp;
    21 package com.sun.org.apache.xpath.internal.jaxp;
    23 
    22 
    24 import com.sun.org.apache.xpath.internal.*;
    23 import com.sun.org.apache.xalan.internal.utils.FeatureManager;
       
    24 import com.sun.org.apache.xpath.internal.objects.XObject;
       
    25 import javax.xml.namespace.QName;
    25 import javax.xml.transform.TransformerException;
    26 import javax.xml.transform.TransformerException;
    26 
    27 import javax.xml.xpath.XPathConstants;
    27 import com.sun.org.apache.xpath.internal.objects.XObject;
    28 import javax.xml.xpath.XPathEvaluationResult;
    28 import com.sun.org.apache.xml.internal.dtm.DTM;
    29 import javax.xml.xpath.XPathExpression;
    29 import com.sun.org.apache.xml.internal.utils.PrefixResolver;
       
    30 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
       
    31 import com.sun.org.apache.xalan.internal.res.XSLMessages;
       
    32 import com.sun.org.apache.xalan.internal.utils.FactoryImpl;
       
    33 import com.sun.org.apache.xalan.internal.utils.FeatureManager;
       
    34 
       
    35 import javax.xml.namespace.NamespaceContext;
       
    36 import javax.xml.namespace.QName;
       
    37 import javax.xml.xpath.XPathExpressionException;
    30 import javax.xml.xpath.XPathExpressionException;
    38 import javax.xml.xpath.XPathConstants;
       
    39 import javax.xml.xpath.XPathFunctionResolver;
    31 import javax.xml.xpath.XPathFunctionResolver;
    40 import javax.xml.xpath.XPathVariableResolver;
    32 import javax.xml.xpath.XPathVariableResolver;
    41 import javax.xml.xpath.XPathConstants;
    33 import org.w3c.dom.Document;
    42 
       
    43 import org.w3c.dom.Node;
    34 import org.w3c.dom.Node;
    44 import org.w3c.dom.Document;
       
    45 import org.w3c.dom.DOMImplementation;
       
    46 import org.w3c.dom.traversal.NodeIterator;
       
    47 import javax.xml.parsers.DocumentBuilderFactory;
       
    48 import javax.xml.parsers.DocumentBuilder;
       
    49 
       
    50 import org.xml.sax.InputSource;
    35 import org.xml.sax.InputSource;
    51 
    36 
    52 /**
    37 /**
    53  * The XPathExpression interface encapsulates a (compiled) XPath expression.
    38  * The XPathExpression interface encapsulates a (compiled) XPath expression.
    54  *
    39  *
    55  * @author  Ramesh Mandava
    40  * @author  Ramesh Mandava
    56  */
    41  */
    57 public class XPathExpressionImpl  implements javax.xml.xpath.XPathExpression{
    42 public class XPathExpressionImpl extends XPathImplUtil implements XPathExpression {
    58 
    43 
    59     private XPathFunctionResolver functionResolver;
       
    60     private XPathVariableResolver variableResolver;
       
    61     private JAXPPrefixResolver prefixResolver;
       
    62     private com.sun.org.apache.xpath.internal.XPath xpath;
    44     private com.sun.org.apache.xpath.internal.XPath xpath;
    63 
       
    64     // By default Extension Functions are allowed in XPath Expressions. If
       
    65     // Secure Processing Feature is set on XPathFactory then the invocation of
       
    66     // extensions function need to throw XPathFunctionException
       
    67     private boolean featureSecureProcessing = false;
       
    68 
       
    69     private boolean useServicesMechanism = true;
       
    70 
       
    71     private final FeatureManager featureManager;
       
    72 
    45 
    73     /** Protected constructor to prevent direct instantiation; use compile()
    46     /** Protected constructor to prevent direct instantiation; use compile()
    74      * from the context.
    47      * from the context.
    75      */
    48      */
    76     protected XPathExpressionImpl() {
    49     protected XPathExpressionImpl() {
    79     };
    52     };
    80 
    53 
    81     protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath,
    54     protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath,
    82             JAXPPrefixResolver prefixResolver,
    55             JAXPPrefixResolver prefixResolver,
    83             XPathFunctionResolver functionResolver,
    56             XPathFunctionResolver functionResolver,
    84             XPathVariableResolver variableResolver ) {
    57             XPathVariableResolver variableResolver) {
    85         this(xpath, prefixResolver, functionResolver, variableResolver,
    58         this(xpath, prefixResolver, functionResolver, variableResolver,
    86              false, true, new FeatureManager());
    59              false, true, new FeatureManager());
    87     };
    60     };
    88 
    61 
    89     protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath,
    62     protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath,
    90             JAXPPrefixResolver prefixResolver,XPathFunctionResolver functionResolver,
    63             JAXPPrefixResolver prefixResolver,XPathFunctionResolver functionResolver,
    91             XPathVariableResolver variableResolver, boolean featureSecureProcessing,
    64             XPathVariableResolver variableResolver, boolean featureSecureProcessing,
    92             boolean useServicesMechanism, FeatureManager featureManager ) {
    65             boolean useServiceMechanism, FeatureManager featureManager) {
    93         this.xpath = xpath;
    66         this.xpath = xpath;
    94         this.prefixResolver = prefixResolver;
    67         this.prefixResolver = prefixResolver;
    95         this.functionResolver = functionResolver;
    68         this.functionResolver = functionResolver;
    96         this.variableResolver = variableResolver;
    69         this.variableResolver = variableResolver;
    97         this.featureSecureProcessing = featureSecureProcessing;
    70         this.featureSecureProcessing = featureSecureProcessing;
    98         this.useServicesMechanism = useServicesMechanism;
    71         this.useServiceMechanism = useServiceMechanism;
    99         this.featureManager = featureManager;
    72         this.featureManager = featureManager;
   100     };
    73     };
   101 
    74 
   102     public void setXPath (com.sun.org.apache.xpath.internal.XPath xpath ) {
    75     public void setXPath (com.sun.org.apache.xpath.internal.XPath xpath) {
   103         this.xpath = xpath;
    76         this.xpath = xpath;
   104     }
    77     }
   105 
    78 
   106     public Object eval(Object item, QName returnType)
    79     public Object eval(Object item, QName returnType)
   107             throws javax.xml.transform.TransformerException {
    80             throws javax.xml.transform.TransformerException {
   108         XObject resultObject = eval ( item );
    81         XObject resultObject = eval(item, xpath);
   109         return getResultAsType( resultObject, returnType );
    82         return getResultAsType(resultObject, returnType);
   110     }
    83     }
   111 
    84 
   112     private XObject eval ( Object contextItem )
    85     @Override
   113             throws javax.xml.transform.TransformerException {
    86     public Object evaluate(Object item, QName returnType)
   114         com.sun.org.apache.xpath.internal.XPathContext xpathSupport = null;
    87         throws XPathExpressionException {
   115         if ( functionResolver != null ) {
    88         isSupported(returnType);
   116             JAXPExtensionsProvider jep = new JAXPExtensionsProvider(
    89         try {
   117                     functionResolver, featureSecureProcessing, featureManager );
    90             return eval(item, returnType);
   118             xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext( jep );
    91         } catch (java.lang.NullPointerException npe) {
   119         } else {
    92             // If VariableResolver returns null Or if we get
   120             xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext();
    93             // NullPointerException at this stage for some other reason
       
    94             // then we have to reurn XPathException
       
    95             throw new XPathExpressionException (npe);
       
    96         } catch (javax.xml.transform.TransformerException te) {
       
    97             Throwable nestedException = te.getException();
       
    98             if (nestedException instanceof javax.xml.xpath.XPathFunctionException) {
       
    99                 throw (javax.xml.xpath.XPathFunctionException)nestedException;
       
   100             } else {
       
   101                 // For any other exceptions we need to throw
       
   102                 // XPathExpressionException (as per spec)
       
   103                 throw new XPathExpressionException(te);
       
   104             }
   121         }
   105         }
   122 
       
   123         xpathSupport.setVarStack(new JAXPVariableStack(variableResolver));
       
   124         XObject xobj = null;
       
   125 
       
   126         Node contextNode = (Node)contextItem;
       
   127         // We always need to have a ContextNode with Xalan XPath implementation
       
   128         // To allow simple expression evaluation like 1+1 we are setting
       
   129         // dummy Document as Context Node
       
   130 
       
   131         if ( contextNode == null )
       
   132             xobj = xpath.execute(xpathSupport, DTM.NULL, prefixResolver);
       
   133         else
       
   134             xobj = xpath.execute(xpathSupport, contextNode, prefixResolver);
       
   135 
       
   136         return xobj;
       
   137     }
   106     }
   138 
   107 
   139 
   108 
   140     /**
   109     @Override
   141      * <p>Evaluate the compiled XPath expression in the specified context and
   110     public String evaluate(Object item)
   142      *  return the result as the specified type.</p>
       
   143      *
       
   144      * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec
       
   145      * for context item evaluation,
       
   146      * variable, function and QName resolution and return type conversion.</p>
       
   147      *
       
   148      * <p>If <code>returnType</code> is not one of the types defined
       
   149      * in {@link XPathConstants},
       
   150      * then an <code>IllegalArgumentException</code> is thrown.</p>
       
   151      *
       
   152      * <p>If a <code>null</code> value is provided for
       
   153      * <code>item</code>, an empty document will be used for the
       
   154      * context.
       
   155      * If <code>returnType</code> is <code>null</code>, then a
       
   156      * <code>NullPointerException</code> is thrown.</p>
       
   157      *
       
   158      * @param item The starting context (node or node list, for example).
       
   159      * @param returnType The desired return type.
       
   160      *
       
   161      * @return The <code>Object</code> that is the result of evaluating the
       
   162      * expression and converting the result to
       
   163      *   <code>returnType</code>.
       
   164      *
       
   165      * @throws XPathExpressionException If the expression cannot be evaluated.
       
   166      * @throws IllegalArgumentException If <code>returnType</code> is not one
       
   167      * of the types defined in {@link XPathConstants}.
       
   168      * @throws NullPointerException If  <code>returnType</code> is
       
   169      * <code>null</code>.
       
   170      */
       
   171     public Object evaluate(Object item, QName returnType)
       
   172         throws XPathExpressionException {
   111         throws XPathExpressionException {
   173         //Validating parameters to enforce constraints defined by JAXP spec
   112         return (String)this.evaluate(item, XPathConstants.STRING);
   174         if ( returnType == null ) {
       
   175            //Throwing NullPointerException as defined in spec
       
   176             String fmsg = XSLMessages.createXPATHMessage(
       
   177                     XPATHErrorResources.ER_ARG_CANNOT_BE_NULL,
       
   178                     new Object[] {"returnType"} );
       
   179             throw new NullPointerException( fmsg );
       
   180         }
       
   181         // Checking if requested returnType is supported. returnType need to be
       
   182         // defined in XPathConstants
       
   183         if ( !isSupported ( returnType ) ) {
       
   184             String fmsg = XSLMessages.createXPATHMessage(
       
   185                     XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE,
       
   186                     new Object[] { returnType.toString() } );
       
   187             throw new IllegalArgumentException ( fmsg );
       
   188         }
       
   189         try {
       
   190             return eval( item, returnType);
       
   191         } catch ( java.lang.NullPointerException npe ) {
       
   192             // If VariableResolver returns null Or if we get
       
   193             // NullPointerException at this stage for some other reason
       
   194             // then we have to reurn XPathException
       
   195             throw new XPathExpressionException ( npe );
       
   196         } catch ( javax.xml.transform.TransformerException te ) {
       
   197             Throwable nestedException = te.getException();
       
   198             if ( nestedException instanceof javax.xml.xpath.XPathFunctionException ) {
       
   199                 throw (javax.xml.xpath.XPathFunctionException)nestedException;
       
   200             } else {
       
   201                 // For any other exceptions we need to throw
       
   202                 // XPathExpressionException ( as per spec )
       
   203                 throw new XPathExpressionException( te);
       
   204             }
       
   205         }
       
   206 
       
   207     }
   113     }
   208 
   114 
   209     /**
   115     @Override
   210      * <p>Evaluate the compiled XPath expression in the specified context and
       
   211      * return the result as a <code>String</code>.</p>
       
   212      *
       
   213      * <p>This method calls {@link #evaluate(Object item, QName returnType)}
       
   214      * with a <code>returnType</code> of
       
   215      * {@link XPathConstants#STRING}.</p>
       
   216      *
       
   217      * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec
       
   218      *  for context item evaluation,
       
   219      * variable, function and QName resolution and return type conversion.</p>
       
   220      *
       
   221      * <p>If a <code>null</code> value is provided for
       
   222      * <code>item</code>, an empty document will be used for the
       
   223      * context.
       
   224      *
       
   225      * @param item The starting context (node or node list, for example).
       
   226      *
       
   227      * @return The <code>String</code> that is the result of evaluating the
       
   228      * expression and converting the result to a
       
   229      *   <code>String</code>.
       
   230      *
       
   231      * @throws XPathExpressionException If the expression cannot be evaluated.
       
   232      */
       
   233     public String evaluate(Object item)
       
   234         throws XPathExpressionException {
       
   235         return (String)this.evaluate( item, XPathConstants.STRING );
       
   236     }
       
   237 
       
   238 
       
   239 
       
   240     static DocumentBuilderFactory dbf = null;
       
   241     static DocumentBuilder db = null;
       
   242     static Document d = null;
       
   243 
       
   244     /**
       
   245      * <p>Evaluate the compiled XPath expression in the context of the
       
   246      * specified <code>InputSource</code> and return the result as the
       
   247      *  specified type.</p>
       
   248      *
       
   249      * <p>This method builds a data model for the {@link InputSource} and calls
       
   250      * {@link #evaluate(Object item, QName returnType)} on the resulting
       
   251      * document object.</p>
       
   252      *
       
   253      * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec
       
   254      *  for context item evaluation,
       
   255      * variable, function and QName resolution and return type conversion.</p>
       
   256      *
       
   257      * <p>If <code>returnType</code> is not one of the types defined in
       
   258      * {@link XPathConstants},
       
   259      * then an <code>IllegalArgumentException</code> is thrown.</p>
       
   260      *
       
   261      *<p>If <code>source</code> or <code>returnType</code> is <code>null</code>,
       
   262      * then a <code>NullPointerException</code> is thrown.</p>
       
   263      *
       
   264      * @param source The <code>InputSource</code> of the document to evaluate
       
   265      * over.
       
   266      * @param returnType The desired return type.
       
   267      *
       
   268      * @return The <code>Object</code> that is the result of evaluating the
       
   269      * expression and converting the result to
       
   270      *   <code>returnType</code>.
       
   271      *
       
   272      * @throws XPathExpressionException If the expression cannot be evaluated.
       
   273      * @throws IllegalArgumentException If <code>returnType</code> is not one
       
   274      * of the types defined in {@link XPathConstants}.
       
   275      * @throws NullPointerException If  <code>source</code> or
       
   276      * <code>returnType</code> is <code>null</code>.
       
   277      */
       
   278     public Object evaluate(InputSource source, QName returnType)
   116     public Object evaluate(InputSource source, QName returnType)
   279         throws XPathExpressionException {
   117         throws XPathExpressionException {
   280         if ( ( source == null ) || ( returnType == null ) ) {
   118         isSupported (returnType);
   281             String fmsg = XSLMessages.createXPATHMessage(
       
   282                     XPATHErrorResources.ER_SOURCE_RETURN_TYPE_CANNOT_BE_NULL,
       
   283                     null );
       
   284             throw new NullPointerException ( fmsg );
       
   285         }
       
   286         // Checking if requested returnType is supported. returnType need to be
       
   287         // defined in XPathConstants
       
   288         if ( !isSupported ( returnType ) ) {
       
   289             String fmsg = XSLMessages.createXPATHMessage(
       
   290                     XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE,
       
   291                     new Object[] { returnType.toString() } );
       
   292             throw new IllegalArgumentException ( fmsg );
       
   293         }
       
   294         try {
   119         try {
   295             if ( dbf == null ) {
   120             Document document = getDocument(source);
   296                 dbf = FactoryImpl.getDOMFactory(useServicesMechanism);
   121             return eval(document, returnType);
   297                 dbf.setNamespaceAware( true );
   122         } catch (TransformerException e) {
   298                 dbf.setValidating( false );
   123             throw new XPathExpressionException(e);
   299             }
       
   300             db = dbf.newDocumentBuilder();
       
   301             Document document = db.parse( source );
       
   302             return eval(  document, returnType );
       
   303         } catch ( Exception e ) {
       
   304             throw new XPathExpressionException ( e );
       
   305         }
   124         }
   306     }
   125     }
   307 
   126 
   308     /**
   127     @Override
   309      * <p>Evaluate the compiled XPath expression in the context of the specified <code>InputSource</code> and return the result as a
       
   310      * <code>String</code>.</p>
       
   311      *
       
   312      * <p>This method calls {@link #evaluate(InputSource source, QName returnType)} with a <code>returnType</code> of
       
   313      * {@link XPathConstants#STRING}.</p>
       
   314      *
       
   315      * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec
       
   316      * for context item evaluation,
       
   317      * variable, function and QName resolution and return type conversion.</p>
       
   318      *
       
   319      * <p>If <code>source</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p>
       
   320      *
       
   321      * @param source The <code>InputSource</code> of the document to evaluate over.
       
   322      *
       
   323      * @return The <code>String</code> that is the result of evaluating the expression and converting the result to a
       
   324      *   <code>String</code>.
       
   325      *
       
   326      * @throws XPathExpressionException If the expression cannot be evaluated.
       
   327      * @throws NullPointerException If  <code>source</code> is <code>null</code>.
       
   328      */
       
   329     public String evaluate(InputSource source)
   128     public String evaluate(InputSource source)
   330         throws XPathExpressionException {
   129         throws XPathExpressionException {
   331         return (String)this.evaluate( source, XPathConstants.STRING );
   130         return (String)this.evaluate(source, XPathConstants.STRING);
   332     }
   131     }
   333 
   132 
   334     private boolean isSupported( QName returnType ) {
   133     @Override
   335         // XPathConstants.STRING
   134     public <T>T evaluateExpression(Object item, Class<T> type)
   336         if ( ( returnType.equals( XPathConstants.STRING ) ) ||
   135         throws XPathExpressionException {
   337              ( returnType.equals( XPathConstants.NUMBER ) ) ||
   136         isSupportedClassType(type);
   338              ( returnType.equals( XPathConstants.BOOLEAN ) ) ||
       
   339              ( returnType.equals( XPathConstants.NODE ) ) ||
       
   340              ( returnType.equals( XPathConstants.NODESET ) )  ) {
       
   341 
   137 
   342             return true;
   138         try {
       
   139             XObject resultObject = eval(item, xpath);
       
   140             if (type.isAssignableFrom(XPathEvaluationResult.class)) {
       
   141                 return getXPathResult(resultObject, type);
       
   142             } else {
       
   143                 return XPathResultImpl.getValue(resultObject, type);
       
   144             }
       
   145 
       
   146         } catch (javax.xml.transform.TransformerException te) {
       
   147             throw new XPathExpressionException(te);
   343         }
   148         }
   344         return false;
       
   345      }
       
   346 
       
   347      private Object getResultAsType( XObject resultObject, QName returnType )
       
   348         throws javax.xml.transform.TransformerException {
       
   349         // XPathConstants.STRING
       
   350         if ( returnType.equals( XPathConstants.STRING ) ) {
       
   351             return resultObject.str();
       
   352         }
       
   353         // XPathConstants.NUMBER
       
   354         if ( returnType.equals( XPathConstants.NUMBER ) ) {
       
   355             return new Double ( resultObject.num());
       
   356         }
       
   357         // XPathConstants.BOOLEAN
       
   358         if ( returnType.equals( XPathConstants.BOOLEAN ) ) {
       
   359             return new Boolean( resultObject.bool());
       
   360         }
       
   361         // XPathConstants.NODESET ---ORdered, UNOrdered???
       
   362         if ( returnType.equals( XPathConstants.NODESET ) ) {
       
   363             return resultObject.nodelist();
       
   364         }
       
   365         // XPathConstants.NODE
       
   366         if ( returnType.equals( XPathConstants.NODE ) ) {
       
   367             NodeIterator ni = resultObject.nodeset();
       
   368             //Return the first node, or null
       
   369             return ni.nextNode();
       
   370         }
       
   371         // If isSupported check is already done then the execution path
       
   372         // shouldn't come here. Being defensive
       
   373         String fmsg = XSLMessages.createXPATHMessage(
       
   374                 XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE,
       
   375                 new Object[] { returnType.toString()});
       
   376         throw new IllegalArgumentException ( fmsg );
       
   377     }
   149     }
   378 
   150 
       
   151     @Override
       
   152     public XPathEvaluationResult<?> evaluateExpression(Object item)
       
   153         throws XPathExpressionException {
       
   154         return evaluateExpression(item, XPathEvaluationResult.class);
       
   155     }
       
   156 
       
   157     @Override
       
   158     public <T>T  evaluateExpression(InputSource source, Class<T> type)
       
   159             throws XPathExpressionException {
       
   160         Document document = getDocument(source);
       
   161         return evaluateExpression(document, type);
       
   162     }
       
   163 
       
   164     @Override
       
   165     public XPathEvaluationResult<?> evaluateExpression(InputSource source)
       
   166         throws XPathExpressionException {
       
   167         return evaluateExpression(source, XPathEvaluationResult.class);
       
   168     }
   379  }
   169  }