--- old/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java Wed Jan 21 21:16:29 2015 +++ new/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java Wed Jan 21 21:16:29 2015 @@ -1,16 +1,16 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. */ /* - * Copyright 1999-2004 The Apache Software Foundation. + * 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 * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. @@ -17,36 +17,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// $Id: XPathExpressionImpl.java,v 1.3 2005/09/27 09:40:43 sunithareddy Exp $ package com.sun.org.apache.xpath.internal.jaxp; -import com.sun.org.apache.xpath.internal.*; -import javax.xml.transform.TransformerException; - -import com.sun.org.apache.xpath.internal.objects.XObject; -import com.sun.org.apache.xml.internal.dtm.DTM; -import com.sun.org.apache.xml.internal.utils.PrefixResolver; -import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; -import com.sun.org.apache.xalan.internal.res.XSLMessages; -import com.sun.org.apache.xalan.internal.utils.FactoryImpl; import com.sun.org.apache.xalan.internal.utils.FeatureManager; - -import javax.xml.namespace.NamespaceContext; +import com.sun.org.apache.xpath.internal.objects.XObject; import javax.xml.namespace.QName; -import javax.xml.xpath.XPathExpressionException; +import javax.xml.transform.TransformerException; import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathEvaluationResult; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFunctionResolver; import javax.xml.xpath.XPathVariableResolver; -import javax.xml.xpath.XPathConstants; - -import org.w3c.dom.Node; import org.w3c.dom.Document; -import org.w3c.dom.DOMImplementation; -import org.w3c.dom.traversal.NodeIterator; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.DocumentBuilder; - +import org.w3c.dom.Node; import org.xml.sax.InputSource; /** @@ -54,22 +39,10 @@ * * @author Ramesh Mandava */ -public class XPathExpressionImpl implements javax.xml.xpath.XPathExpression{ +public class XPathExpressionImpl extends XPathImplUtil implements XPathExpression { - private XPathFunctionResolver functionResolver; - private XPathVariableResolver variableResolver; - private JAXPPrefixResolver prefixResolver; private com.sun.org.apache.xpath.internal.XPath xpath; - // By default Extension Functions are allowed in XPath Expressions. If - // Secure Processing Feature is set on XPathFactory then the invocation of - // extensions function need to throw XPathFunctionException - private boolean featureSecureProcessing = false; - - private boolean useServicesMechanism = true; - - private final FeatureManager featureManager; - /** Protected constructor to prevent direct instantiation; use compile() * from the context. */ @@ -81,7 +54,7 @@ protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, JAXPPrefixResolver prefixResolver, XPathFunctionResolver functionResolver, - XPathVariableResolver variableResolver ) { + XPathVariableResolver variableResolver) { this(xpath, prefixResolver, functionResolver, variableResolver, false, true, new FeatureManager()); }; @@ -89,291 +62,108 @@ protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, JAXPPrefixResolver prefixResolver,XPathFunctionResolver functionResolver, XPathVariableResolver variableResolver, boolean featureSecureProcessing, - boolean useServicesMechanism, FeatureManager featureManager ) { + boolean useServiceMechanism, FeatureManager featureManager) { this.xpath = xpath; this.prefixResolver = prefixResolver; this.functionResolver = functionResolver; this.variableResolver = variableResolver; this.featureSecureProcessing = featureSecureProcessing; - this.useServicesMechanism = useServicesMechanism; + this.useServiceMechanism = useServiceMechanism; this.featureManager = featureManager; }; - public void setXPath (com.sun.org.apache.xpath.internal.XPath xpath ) { + public void setXPath (com.sun.org.apache.xpath.internal.XPath xpath) { this.xpath = xpath; } public Object eval(Object item, QName returnType) throws javax.xml.transform.TransformerException { - XObject resultObject = eval ( item ); - return getResultAsType( resultObject, returnType ); + XObject resultObject = eval(item, xpath); + return getResultAsType(resultObject, returnType); } - private XObject eval ( Object contextItem ) - throws javax.xml.transform.TransformerException { - com.sun.org.apache.xpath.internal.XPathContext xpathSupport = null; - if ( functionResolver != null ) { - JAXPExtensionsProvider jep = new JAXPExtensionsProvider( - functionResolver, featureSecureProcessing, featureManager ); - xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext( jep ); - } else { - xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext(); - } - - xpathSupport.setVarStack(new JAXPVariableStack(variableResolver)); - XObject xobj = null; - - Node contextNode = (Node)contextItem; - // We always need to have a ContextNode with Xalan XPath implementation - // To allow simple expression evaluation like 1+1 we are setting - // dummy Document as Context Node - - if ( contextNode == null ) - xobj = xpath.execute(xpathSupport, DTM.NULL, prefixResolver); - else - xobj = xpath.execute(xpathSupport, contextNode, prefixResolver); - - return xobj; - } - - - /** - *

Evaluate the compiled XPath expression in the specified context and - * return the result as the specified type.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If returnType is not one of the types defined - * in {@link XPathConstants}, - * then an IllegalArgumentException is thrown.

- * - *

If a null value is provided for - * item, an empty document will be used for the - * context. - * If returnType is null, then a - * NullPointerException is thrown.

- * - * @param item The starting context (node or node list, for example). - * @param returnType The desired return type. - * - * @return The Object that is the result of evaluating the - * expression and converting the result to - * returnType. - * - * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one - * of the types defined in {@link XPathConstants}. - * @throws NullPointerException If returnType is - * null. - */ + @Override public Object evaluate(Object item, QName returnType) throws XPathExpressionException { - //Validating parameters to enforce constraints defined by JAXP spec - if ( returnType == null ) { - //Throwing NullPointerException as defined in spec - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"returnType"} ); - throw new NullPointerException( fmsg ); - } - // Checking if requested returnType is supported. returnType need to be - // defined in XPathConstants - if ( !isSupported ( returnType ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString() } ); - throw new IllegalArgumentException ( fmsg ); - } + isSupported(returnType); try { - return eval( item, returnType); - } catch ( java.lang.NullPointerException npe ) { + return eval(item, returnType); + } catch (java.lang.NullPointerException npe) { // If VariableResolver returns null Or if we get // NullPointerException at this stage for some other reason // then we have to reurn XPathException - throw new XPathExpressionException ( npe ); - } catch ( javax.xml.transform.TransformerException te ) { + throw new XPathExpressionException (npe); + } catch (javax.xml.transform.TransformerException te) { Throwable nestedException = te.getException(); - if ( nestedException instanceof javax.xml.xpath.XPathFunctionException ) { + if (nestedException instanceof javax.xml.xpath.XPathFunctionException) { throw (javax.xml.xpath.XPathFunctionException)nestedException; } else { // For any other exceptions we need to throw - // XPathExpressionException ( as per spec ) - throw new XPathExpressionException( te); + // XPathExpressionException (as per spec) + throw new XPathExpressionException(te); } } - } - /** - *

Evaluate the compiled XPath expression in the specified context and - * return the result as a String.

- * - *

This method calls {@link #evaluate(Object item, QName returnType)} - * with a returnType of - * {@link XPathConstants#STRING}.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If a null value is provided for - * item, an empty document will be used for the - * context. - * - * @param item The starting context (node or node list, for example). - * - * @return The String that is the result of evaluating the - * expression and converting the result to a - * String. - * - * @throws XPathExpressionException If the expression cannot be evaluated. - */ + + @Override public String evaluate(Object item) throws XPathExpressionException { - return (String)this.evaluate( item, XPathConstants.STRING ); + return (String)this.evaluate(item, XPathConstants.STRING); } - - - static DocumentBuilderFactory dbf = null; - static DocumentBuilder db = null; - static Document d = null; - - /** - *

Evaluate the compiled XPath expression in the context of the - * specified InputSource and return the result as the - * specified type.

- * - *

This method builds a data model for the {@link InputSource} and calls - * {@link #evaluate(Object item, QName returnType)} on the resulting - * document object.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If returnType is not one of the types defined in - * {@link XPathConstants}, - * then an IllegalArgumentException is thrown.

- * - *

If source or returnType is null, - * then a NullPointerException is thrown.

- * - * @param source The InputSource of the document to evaluate - * over. - * @param returnType The desired return type. - * - * @return The Object that is the result of evaluating the - * expression and converting the result to - * returnType. - * - * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one - * of the types defined in {@link XPathConstants}. - * @throws NullPointerException If source or - * returnType is null. - */ + @Override public Object evaluate(InputSource source, QName returnType) throws XPathExpressionException { - if ( ( source == null ) || ( returnType == null ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_SOURCE_RETURN_TYPE_CANNOT_BE_NULL, - null ); - throw new NullPointerException ( fmsg ); - } - // Checking if requested returnType is supported. returnType need to be - // defined in XPathConstants - if ( !isSupported ( returnType ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString() } ); - throw new IllegalArgumentException ( fmsg ); - } + isSupported (returnType); try { - if ( dbf == null ) { - dbf = FactoryImpl.getDOMFactory(useServicesMechanism); - dbf.setNamespaceAware( true ); - dbf.setValidating( false ); - } - db = dbf.newDocumentBuilder(); - Document document = db.parse( source ); - return eval( document, returnType ); - } catch ( Exception e ) { - throw new XPathExpressionException ( e ); + Document document = getDocument(source); + return eval(document, returnType); + } catch (TransformerException e) { + throw new XPathExpressionException(e); } } - /** - *

Evaluate the compiled XPath expression in the context of the specified InputSource and return the result as a - * String.

- * - *

This method calls {@link #evaluate(InputSource source, QName returnType)} with a returnType of - * {@link XPathConstants#STRING}.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If source is null, then a NullPointerException is thrown.

- * - * @param source The InputSource of the document to evaluate over. - * - * @return The String that is the result of evaluating the expression and converting the result to a - * String. - * - * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws NullPointerException If source is null. - */ + @Override public String evaluate(InputSource source) throws XPathExpressionException { - return (String)this.evaluate( source, XPathConstants.STRING ); + return (String)this.evaluate(source, XPathConstants.STRING); } - private boolean isSupported( QName returnType ) { - // XPathConstants.STRING - if ( ( returnType.equals( XPathConstants.STRING ) ) || - ( returnType.equals( XPathConstants.NUMBER ) ) || - ( returnType.equals( XPathConstants.BOOLEAN ) ) || - ( returnType.equals( XPathConstants.NODE ) ) || - ( returnType.equals( XPathConstants.NODESET ) ) ) { + @Override + public T evaluateExpression(Object item, Class type) + throws XPathExpressionException { + isSupportedClassType(type); - return true; - } - return false; - } + try { + XObject resultObject = eval(item, xpath); + if (type.isAssignableFrom(XPathEvaluationResult.class)) { + return getXPathResult(resultObject, type); + } else { + return XPathResultImpl.getValue(resultObject, type); + } - private Object getResultAsType( XObject resultObject, QName returnType ) - throws javax.xml.transform.TransformerException { - // XPathConstants.STRING - if ( returnType.equals( XPathConstants.STRING ) ) { - return resultObject.str(); + } catch (javax.xml.transform.TransformerException te) { + throw new XPathExpressionException(te); } - // XPathConstants.NUMBER - if ( returnType.equals( XPathConstants.NUMBER ) ) { - return new Double ( resultObject.num()); - } - // XPathConstants.BOOLEAN - if ( returnType.equals( XPathConstants.BOOLEAN ) ) { - return new Boolean( resultObject.bool()); - } - // XPathConstants.NODESET ---ORdered, UNOrdered??? - if ( returnType.equals( XPathConstants.NODESET ) ) { - return resultObject.nodelist(); - } - // XPathConstants.NODE - if ( returnType.equals( XPathConstants.NODE ) ) { - NodeIterator ni = resultObject.nodeset(); - //Return the first node, or null - return ni.nextNode(); - } - // If isSupported check is already done then the execution path - // shouldn't come here. Being defensive - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString()}); - throw new IllegalArgumentException ( fmsg ); } + @Override + public XPathEvaluationResult evaluateExpression(Object item) + throws XPathExpressionException { + return evaluateExpression(item, XPathEvaluationResult.class); + } + + @Override + public T evaluateExpression(InputSource source, Class type) + throws XPathExpressionException { + Document document = getDocument(source); + return evaluateExpression(document, type); + } + + @Override + public XPathEvaluationResult evaluateExpression(InputSource source) + throws XPathExpressionException { + return evaluateExpression(source, XPathEvaluationResult.class); + } } --- old/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java Wed Jan 21 21:16:30 2015 +++ new/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java Wed Jan 21 21:16:30 2015 @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 1999-2004 The Apache Software Foundation. @@ -28,55 +27,37 @@ import javax.xml.xpath.XPathFunctionResolver; import javax.xml.xpath.XPathVariableResolver; import javax.xml.xpath.XPathExpression; - -import com.sun.org.apache.xml.internal.dtm.DTM; import com.sun.org.apache.xpath.internal.*; import com.sun.org.apache.xpath.internal.objects.XObject; -import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; -import com.sun.org.apache.xalan.internal.res.XSLMessages; -import com.sun.org.apache.xalan.internal.utils.FactoryImpl; import com.sun.org.apache.xalan.internal.utils.FeatureManager; - -import org.w3c.dom.Node; import org.w3c.dom.Document; -import org.w3c.dom.traversal.NodeIterator; - import org.xml.sax.InputSource; -import org.xml.sax.SAXException; +import javax.xml.transform.TransformerException; +import javax.xml.xpath.XPathEvaluationResult; -import javax.xml.parsers.*; - -import java.io.IOException; - /** * The XPathImpl class provides implementation for the methods defined in - * javax.xml.xpath.XPath interface. This provide simple access to the results + * javax.xml.xpath.XPath interface. This provides simple access to the results * of an XPath expression. * - * * @author Ramesh Mandava + * + * Updated 12/04/2014: + * New methods: evaluateExpression + * Refactored to share code with XPathExpressionImpl. */ -public class XPathImpl implements javax.xml.xpath.XPath { +public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath { // Private variables - private XPathVariableResolver variableResolver; - private XPathFunctionResolver functionResolver; private XPathVariableResolver origVariableResolver; private XPathFunctionResolver origFunctionResolver; private NamespaceContext namespaceContext=null; - private JAXPPrefixResolver prefixResolver; - // By default Extension Functions are allowed in XPath Expressions. If - // Secure Processing Feature is set on XPathFactory then the invocation of - // extensions function need to throw XPathFunctionException - private boolean featureSecureProcessing = false; - private boolean useServiceMechanism = true; - private final FeatureManager featureManager; - XPathImpl( XPathVariableResolver vr, XPathFunctionResolver fr ) { + XPathImpl(XPathVariableResolver vr, XPathFunctionResolver fr) { this(vr, fr, false, true, new FeatureManager()); } - XPathImpl( XPathVariableResolver vr, XPathFunctionResolver fr, + XPathImpl(XPathVariableResolver vr, XPathFunctionResolver fr, boolean featureSecureProcessing, boolean useServiceMechanism, FeatureManager featureManager) { this.origVariableResolver = this.variableResolver = vr; @@ -86,447 +67,135 @@ this.featureManager = featureManager; } - /** - *

Establishes a variable resolver.

- * - * @param resolver Variable Resolver - */ + + //-Override- public void setXPathVariableResolver(XPathVariableResolver resolver) { - if ( resolver == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPathVariableResolver"} ); - throw new NullPointerException( fmsg ); - } + requireNonNull(resolver, "XPathVariableResolver"); this.variableResolver = resolver; } - /** - *

Returns the current variable resolver.

- * - * @return Current variable resolver - */ + //-Override- public XPathVariableResolver getXPathVariableResolver() { return variableResolver; } - /** - *

Establishes a function resolver.

- * - * @param resolver XPath function resolver - */ + //-Override- public void setXPathFunctionResolver(XPathFunctionResolver resolver) { - if ( resolver == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPathFunctionResolver"} ); - throw new NullPointerException( fmsg ); - } + requireNonNull(resolver, "XPathFunctionResolver"); this.functionResolver = resolver; } - /** - *

Returns the current function resolver.

- * - * @return Current function resolver - */ + //-Override- public XPathFunctionResolver getXPathFunctionResolver() { return functionResolver; } - /** - *

Establishes a namespace context.

- * - * @param nsContext Namespace context to use - */ + //-Override- public void setNamespaceContext(NamespaceContext nsContext) { - if ( nsContext == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"NamespaceContext"} ); - throw new NullPointerException( fmsg ); - } + requireNonNull(nsContext, "NamespaceContext"); this.namespaceContext = nsContext; - this.prefixResolver = new JAXPPrefixResolver ( nsContext ); + this.prefixResolver = new JAXPPrefixResolver (nsContext); } - /** - *

Returns the current namespace context.

- * - * @return Current Namespace context - */ + //-Override- public NamespaceContext getNamespaceContext() { return namespaceContext; } - private static Document d = null; - - private DocumentBuilder getParser() { - try { - // we'd really like to cache those DocumentBuilders, but we can't because: - // 1. thread safety. parsers are not thread-safe, so at least - // we need one instance per a thread. - // 2. parsers are non-reentrant, so now we are looking at having a - // pool of parsers. - // 3. then the class loading issue. The look-up procedure of - // DocumentBuilderFactory.newInstance() depends on context class loader - // and system properties, which may change during the execution of JVM. - // - // so we really have to create a fresh DocumentBuilder every time we need one - // - KK - DocumentBuilderFactory dbf = FactoryImpl.getDOMFactory(useServiceMechanism); - dbf.setNamespaceAware( true ); - dbf.setValidating( false ); - return dbf.newDocumentBuilder(); - } catch (ParserConfigurationException e) { - // this should never happen with a well-behaving JAXP implementation. - throw new Error(e); - } - } - - + /** + * Evaluate an {@code XPath} expression in the specified context. + * @param expression The XPath expression. + * @param contextItem The starting context. + * @return an XObject as the result of evaluating the expression + * @throws TransformerException if evaluating fails + */ private XObject eval(String expression, Object contextItem) - throws javax.xml.transform.TransformerException { - com.sun.org.apache.xpath.internal.XPath xpath = new com.sun.org.apache.xpath.internal.XPath( expression, - null, prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT ); - com.sun.org.apache.xpath.internal.XPathContext xpathSupport = null; - if ( functionResolver != null ) { - JAXPExtensionsProvider jep = new JAXPExtensionsProvider( - functionResolver, featureSecureProcessing, featureManager ); - xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext( jep ); - } else { - xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext(); - } + throws TransformerException { + requireNonNull(expression, "XPath expression"); + com.sun.org.apache.xpath.internal.XPath xpath = new com.sun.org.apache.xpath.internal.XPath(expression, + null, prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT); - XObject xobj = null; - - xpathSupport.setVarStack(new JAXPVariableStack(variableResolver)); - - // If item is null, then we will create a a Dummy contextNode - if ( contextItem instanceof Node ) { - xobj = xpath.execute (xpathSupport, (Node)contextItem, - prefixResolver ); - } else { - xobj = xpath.execute ( xpathSupport, DTM.NULL, prefixResolver ); - } - - return xobj; + return eval(contextItem, xpath); } - /** - *

Evaluate an XPath expression in the specified context and return the result as the specified type.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If returnType is not one of the types defined in {@link XPathConstants} ( - * {@link XPathConstants#NUMBER NUMBER}, - * {@link XPathConstants#STRING STRING}, - * {@link XPathConstants#BOOLEAN BOOLEAN}, - * {@link XPathConstants#NODE NODE} or - * {@link XPathConstants#NODESET NODESET}) - * then an IllegalArgumentException is thrown.

- * - *

If a null value is provided for - * item, an empty document will be used for the - * context. - * If expression or returnType is null, then a - * NullPointerException is thrown.

- * - * @param expression The XPath expression. - * @param item The starting context (node or node list, for example). - * @param returnType The desired return type. - * - * @return Result of evaluating an XPath expression as an Object of returnType. - * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If expression or returnType is null. - */ + //-Override- public Object evaluate(String expression, Object item, QName returnType) throws XPathExpressionException { - if ( expression == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPath expression"} ); - throw new NullPointerException ( fmsg ); - } - if ( returnType == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"returnType"} ); - throw new NullPointerException ( fmsg ); - } - // Checking if requested returnType is supported. returnType need to - // be defined in XPathConstants - if ( !isSupported ( returnType ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString() } ); - throw new IllegalArgumentException ( fmsg ); - } + //this check is necessary before calling eval to maintain binary compatibility + requireNonNull(expression, "XPath expression"); + isSupported(returnType); try { - XObject resultObject = eval( expression, item ); - return getResultAsType( resultObject, returnType ); - } catch ( java.lang.NullPointerException npe ) { + XObject resultObject = eval(expression, item); + return getResultAsType(resultObject, returnType); + } catch (java.lang.NullPointerException npe) { // If VariableResolver returns null Or if we get // NullPointerException at this stage for some other reason // then we have to reurn XPathException - throw new XPathExpressionException ( npe ); - } catch ( javax.xml.transform.TransformerException te ) { + throw new XPathExpressionException (npe); + } catch (TransformerException te) { Throwable nestedException = te.getException(); - if ( nestedException instanceof javax.xml.xpath.XPathFunctionException ) { + if (nestedException instanceof javax.xml.xpath.XPathFunctionException) { throw (javax.xml.xpath.XPathFunctionException)nestedException; } else { // For any other exceptions we need to throw - // XPathExpressionException ( as per spec ) - throw new XPathExpressionException ( te ); + // XPathExpressionException (as per spec) + throw new XPathExpressionException (te); } } } - private boolean isSupported( QName returnType ) { - if ( ( returnType.equals( XPathConstants.STRING ) ) || - ( returnType.equals( XPathConstants.NUMBER ) ) || - ( returnType.equals( XPathConstants.BOOLEAN ) ) || - ( returnType.equals( XPathConstants.NODE ) ) || - ( returnType.equals( XPathConstants.NODESET ) ) ) { - - return true; - } - return false; - } - - private Object getResultAsType( XObject resultObject, QName returnType ) - throws javax.xml.transform.TransformerException { - // XPathConstants.STRING - if ( returnType.equals( XPathConstants.STRING ) ) { - return resultObject.str(); - } - // XPathConstants.NUMBER - if ( returnType.equals( XPathConstants.NUMBER ) ) { - return new Double ( resultObject.num()); - } - // XPathConstants.BOOLEAN - if ( returnType.equals( XPathConstants.BOOLEAN ) ) { - return new Boolean( resultObject.bool()); - } - // XPathConstants.NODESET ---ORdered, UNOrdered??? - if ( returnType.equals( XPathConstants.NODESET ) ) { - return resultObject.nodelist(); - } - // XPathConstants.NODE - if ( returnType.equals( XPathConstants.NODE ) ) { - NodeIterator ni = resultObject.nodeset(); - //Return the first node, or null - return ni.nextNode(); - } - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString()}); - throw new IllegalArgumentException( fmsg ); - } - - - - /** - *

Evaluate an XPath expression in the specified context and return the result as a String.

- * - *

This method calls {@link #evaluate(String expression, Object item, QName returnType)} with a returnType of - * {@link XPathConstants#STRING}.

- * - *

See "Evaluation of XPath Expressions" of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If a null value is provided for - * item, an empty document will be used for the - * context. - * If expression is null, then a NullPointerException is thrown.

- * - * @param expression The XPath expression. - * @param item The starting context (node or node list, for example). - * - * @return The String that is the result of evaluating the expression and - * converting the result to a String. - * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws NullPointerException If expression is null. - */ + //-Override- public String evaluate(String expression, Object item) throws XPathExpressionException { - return (String)this.evaluate( expression, item, XPathConstants.STRING ); + return (String)this.evaluate(expression, item, XPathConstants.STRING); } - /** - *

Compile an XPath expression for later evaluation.

- * - *

If expression contains any {@link XPathFunction}s, - * they must be available via the {@link XPathFunctionResolver}. - * An {@link XPathExpressionException} will be thrown if the XPathFunction - * cannot be resovled with the XPathFunctionResolver.

- * - *

If expression is null, a NullPointerException is thrown.

- * - * @param expression The XPath expression. - * - * @return Compiled XPath expression. - - * @throws XPathExpressionException If expression cannot be compiled. - * @throws NullPointerException If expression is null. - */ + //-Override- public XPathExpression compile(String expression) throws XPathExpressionException { - if ( expression == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPath expression"} ); - throw new NullPointerException ( fmsg ); - } + requireNonNull(expression, "XPath expression"); try { com.sun.org.apache.xpath.internal.XPath xpath = new XPath (expression, null, - prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT ); + prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT); // Can have errorListener XPathExpressionImpl ximpl = new XPathExpressionImpl (xpath, prefixResolver, functionResolver, variableResolver, - featureSecureProcessing, useServiceMechanism, featureManager ); + featureSecureProcessing, useServiceMechanism, featureManager); return ximpl; - } catch ( javax.xml.transform.TransformerException te ) { - throw new XPathExpressionException ( te ) ; + } catch (TransformerException te) { + throw new XPathExpressionException (te) ; } } - - /** - *

Evaluate an XPath expression in the context of the specified InputSource - * and return the result as the specified type.

- * - *

This method builds a data model for the {@link InputSource} and calls - * {@link #evaluate(String expression, Object item, QName returnType)} on the resulting document object.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If returnType is not one of the types defined in {@link XPathConstants}, - * then an IllegalArgumentException is thrown.

- * - *

If expression, source or returnType is null, - * then a NullPointerException is thrown.

- * - * @param expression The XPath expression. - * @param source The input source of the document to evaluate over. - * @param returnType The desired return type. - * - * @return The Object that encapsulates the result of evaluating the expression. - * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If expression, source or returnType - * is null. - */ + //-Override- public Object evaluate(String expression, InputSource source, QName returnType) throws XPathExpressionException { - // Checking validity of different parameters - if( source== null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"source"} ); - throw new NullPointerException ( fmsg ); - } - if ( expression == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPath expression"} ); - throw new NullPointerException ( fmsg ); - } - if ( returnType == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"returnType"} ); - throw new NullPointerException ( fmsg ); - } + isSupported(returnType); - //Checking if requested returnType is supported. - //returnType need to be defined in XPathConstants - if ( !isSupported ( returnType ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString() } ); - throw new IllegalArgumentException ( fmsg ); - } - try { - - Document document = getParser().parse( source ); - - XObject resultObject = eval( expression, document ); - return getResultAsType( resultObject, returnType ); - } catch ( SAXException e ) { - throw new XPathExpressionException ( e ); - } catch( IOException e ) { - throw new XPathExpressionException ( e ); - } catch ( javax.xml.transform.TransformerException te ) { + Document document = getDocument(source); + XObject resultObject = eval(expression, document); + return getResultAsType(resultObject, returnType); + } catch (TransformerException te) { Throwable nestedException = te.getException(); - if ( nestedException instanceof javax.xml.xpath.XPathFunctionException ) { + if (nestedException instanceof javax.xml.xpath.XPathFunctionException) { throw (javax.xml.xpath.XPathFunctionException)nestedException; } else { - throw new XPathExpressionException ( te ); + throw new XPathExpressionException (te); } } - } - - - - /** - *

Evaluate an XPath expression in the context of the specified InputSource - * and return the result as a String.

- * - *

This method calls {@link #evaluate(String expression, InputSource source, QName returnType)} with a - * returnType of {@link XPathConstants#STRING}.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If expression or source is null, - * then a NullPointerException is thrown.

- * - * @param expression The XPath expression. - * @param source The InputSource of the document to evaluate over. - * - * @return The String that is the result of evaluating the expression and - * converting the result to a String. - * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws NullPointerException If expression or source is null. - */ + //-Override- public String evaluate(String expression, InputSource source) throws XPathExpressionException { - return (String)this.evaluate( expression, source, XPathConstants.STRING ); + return (String)this.evaluate(expression, source, XPathConstants.STRING); } - /** - *

Reset this XPath to its original configuration.

- * - *

XPath is reset to the same state as when it was created with - * {@link XPathFactory#newXPath()}. - * reset() is designed to allow the reuse of existing XPaths - * thus saving resources associated with the creation of new XPaths.

- * - *

The reset XPath is not guaranteed to have the same - * {@link XPathFunctionResolver}, {@link XPathVariableResolver} - * or {@link NamespaceContext} Objects, e.g. {@link Object#equals(Object obj)}. - * It is guaranteed to have a functionally equal XPathFunctionResolver, - * XPathVariableResolver - * and NamespaceContext.

- */ + //-Override- public void reset() { this.variableResolver = this.origVariableResolver; this.functionResolver = this.origFunctionResolver; @@ -533,4 +202,38 @@ this.namespaceContext = null; } + //-Override- + public T evaluateExpression(String expression, Object item, Class type) + throws XPathExpressionException { + isSupportedClassType(type); + try { + XObject resultObject = eval(expression, item); + if (type.isAssignableFrom(XPathEvaluationResult.class)) { + return getXPathResult(resultObject, type); + } else { + return XPathResultImpl.getValue(resultObject, type); + } + } catch (TransformerException te) { + throw new XPathExpressionException (te); + } + } + + //-Override- + public XPathEvaluationResult evaluateExpression(String expression, Object item) + throws XPathExpressionException { + return evaluateExpression(expression, item, XPathEvaluationResult.class); + } + + //-Override- + public T evaluateExpression(String expression, InputSource source, Class type) + throws XPathExpressionException { + Document document = getDocument(source); + return evaluateExpression(expression, document, type); + } + + //-Override- + public XPathEvaluationResult evaluateExpression(String expression, InputSource source) + throws XPathExpressionException { + return evaluateExpression(expression, source, XPathEvaluationResult.class); + } } --- old/src/java.xml/share/classes/javax/xml/xpath/XPath.java Wed Jan 21 21:16:31 2015 +++ new/src/java.xml/share/classes/javax/xml/xpath/XPath.java Wed Jan 21 21:16:31 2015 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,12 @@ package javax.xml.xpath; -import org.xml.sax.InputSource; -import javax.xml.namespace.QName; import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import org.xml.sax.InputSource; /** - *

XPath provides access to the XPath evaluation environment and expressions.

+ * {@code XPath} provides access to the XPath evaluation environment and expressions. * * * @@ -39,7 +39,6 @@ * * * - * * * * * * @@ -65,7 +64,7 @@ * If the expression contains a function reference, the function will be found through the {@link XPathFunctionResolver} * set with {@link #setXPathFunctionResolver(XPathFunctionResolver resolver)}. * An {@link XPathExpressionException} is raised if the function resolver is undefined or - * the function resolver returns null for the function.

+ * the function resolver returns {@code null} for the function. * * * @@ -80,7 +79,7 @@ * * *
Evaluation of XPath Expressions.
context @@ -55,8 +54,8 @@ * If the expression contains a variable reference, its value will be found through the {@link XPathVariableResolver} * set with {@link #setXPathVariableResolver(XPathVariableResolver resolver)}. * An {@link XPathExpressionException} is raised if the variable resolver is undefined or - * the resolver returns null for the variable. - * The value of a variable must be immutable through the course of any single evaluation.

+ * the resolver returns {@code null} for the variable. + * The value of a variable must be immutable through the course of any single evaluation. *
* This result of evaluating an expression is converted to an instance of the desired return type. * Valid return types are defined in {@link XPathConstants}. - * Conversion to the return type follows XPath conversion rules.

+ * Conversion to the return type follows XPath conversion rules. *
@@ -88,9 +87,9 @@ *

An XPath object is not thread-safe and not reentrant. * In other words, it is the application's responsibility to make * sure that one {@link XPath} object is not used from - * more than one thread at any given time, and while the evaluate + * more than one thread at any given time, and while the {@code evaluate} * method is invoked, applications may not recursively call - * the evaluate method. + * the {@code evaluate} method. *

* * @author Norman Walsh @@ -100,36 +99,38 @@ */ public interface XPath { - /** - *

Reset this XPath to its original configuration.

- * - *

XPath is reset to the same state as when it was created with - * {@link XPathFactory#newXPath()}. - * reset() is designed to allow the reuse of existing XPaths - * thus saving resources associated with the creation of new XPaths.

- * - *

The reset XPath is not guaranteed to have the same {@link XPathFunctionResolver}, {@link XPathVariableResolver} - * or {@link NamespaceContext} Objects, e.g. {@link Object#equals(Object obj)}. - * It is guaranteed to have a functionally equal XPathFunctionResolver, XPathVariableResolver - * and NamespaceContext.

- */ - public void reset(); /** - *

Establish a variable resolver.

+ * Reset this {@code XPath} to its original configuration. * - *

A NullPointerException is thrown if resolver is null.

+ *

{@code XPath} is reset to the same state as when it was created with + * {@link XPathFactory#newXPath()}. + * {@code reset()} is designed to allow the reuse of existing {@code XPath}s + * thus saving resources associated with the creation of new {@code XPath}s. * + *

The reset {@code XPath} is not guaranteed to have the same + * {@link XPathFunctionResolver}, {@link XPathVariableResolver} + * or {@link NamespaceContext} {@code Object}s, e.g. {@link Object#equals(Object obj)}. + * It is guaranteed to have a functionally equal {@code XPathFunctionResolver}, + * {@code XPathVariableResolver} and {@code NamespaceContext}. + */ + public void reset(); + + /** + * Establish a variable resolver. + * + *

A {@code NullPointerException} is thrown if {@code resolver} is {@code null}. + * * @param resolver Variable resolver. * - * @throws NullPointerException If resolver is null. + * @throws NullPointerException If {@code resolver} is {@code null}. */ public void setXPathVariableResolver(XPathVariableResolver resolver); /** - *

Return the current variable resolver.

+ * Return the current variable resolver. * - *

null is returned in no variable resolver is in effect.

+ *

{@code null} is returned in no variable resolver is in effect. * * @return Current variable resolver. */ @@ -136,40 +137,40 @@ public XPathVariableResolver getXPathVariableResolver(); /** - *

Establish a function resolver.

+ * Establish a function resolver. * - *

A NullPointerException is thrown if resolver is null.

+ *

A {@code NullPointerException} is thrown if {@code resolver} is {@code null}. * * @param resolver XPath function resolver. * - * @throws NullPointerException If resolver is null. + * @throws NullPointerException If {@code resolver} is {@code null}. */ public void setXPathFunctionResolver(XPathFunctionResolver resolver); /** - *

Return the current function resolver.

+ * Return the current function resolver. + *

+ * {@code null} is returned in no function resolver is in effect. * - *

null is returned in no function resolver is in effect.

- * * @return Current function resolver. */ public XPathFunctionResolver getXPathFunctionResolver(); /** - *

Establish a namespace context.

+ * Establish a namespace context. * - *

A NullPointerException is thrown if nsContext is null.

+ *

A {@code NullPointerException} is thrown if {@code nsContext} is {@code null}. * * @param nsContext Namespace context to use. * - * @throws NullPointerException If nsContext is null. + * @throws NullPointerException If {@code nsContext} is {@code null}. */ public void setNamespaceContext(NamespaceContext nsContext); /** - *

Return the current namespace context.

+ * Return the current namespace context. * - *

null is returned in no namespace context is in effect.

+ *

{@code null} is returned in no namespace context is in effect. * * @return Current Namespace context. */ @@ -176,115 +177,111 @@ public NamespaceContext getNamespaceContext(); /** - *

Compile an XPath expression for later evaluation.

+ * Compile an XPath expression for later evaluation. * - *

If expression contains any {@link XPathFunction}s, + *

If {@code expression} contains any {@link XPathFunction}s, * they must be available via the {@link XPathFunctionResolver}. * An {@link XPathExpressionException} will be thrown if the - * XPathFunction - * cannot be resovled with the XPathFunctionResolver.

+ * {@code XPathFunction} + * cannot be resovled with the {@code XPathFunctionResolver}. * - *

If expression contains any variables, the + *

If {@code expression} contains any variables, the * {@link XPathVariableResolver} in effect - * at compile time will be used to resolve them.

+ * at compile time will be used to resolve them. * - *

If expression is null, a NullPointerException is thrown.

- * * @param expression The XPath expression. * * @return Compiled XPath expression. - * @throws XPathExpressionException If expression cannot be compiled. - * @throws NullPointerException If expression is null. + * @throws XPathExpressionException If {@code expression} cannot be compiled. + * @throws NullPointerException If {@code expression} is {@code null}. */ public XPathExpression compile(String expression) throws XPathExpressionException; /** - *

Evaluate an XPath expression in the specified context and return the result as the specified type.

+ * Evaluate an {@code XPath} expression in the specified context and + * return the result as the specified type. * - *

See Evaluation of XPath Expressions for context item evaluation, - * variable, function and QName resolution and return type conversion.

+ *

+ * See Evaluation of XPath Expressions + * for context item evaluation, variable, function and {@code QName} resolution + * and return type conversion. + *

+ * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. * - *

If returnType is not one of the types defined in {@link XPathConstants} ( - * {@link XPathConstants#NUMBER NUMBER}, - * {@link XPathConstants#STRING STRING}, - * {@link XPathConstants#BOOLEAN BOOLEAN}, - * {@link XPathConstants#NODE NODE} or - * {@link XPathConstants#NODESET NODESET}) - * then an IllegalArgumentException is thrown.

+ * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. * - *

If a null value is provided for - * item, an empty document will be used for the - * context. - * If expression or returnType is null, then a - * NullPointerException is thrown.

- * * @param expression The XPath expression. - * @param item The starting context (a node, for example). - * @param returnType The desired return type. + * @param item The context the XPath expression will be evaluated in. + * @param returnType The result type expected to be returned by the XPath expression. * - * @return Result of evaluating an XPath expression as an Object of returnType. + * @return The result of evaluating an XPath expression as an {@code Object} of {@code returnType}. * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If expression or returnType is null. + * @throws XPathExpressionException If {@code expression} cannot be evaluated. + * @throws IllegalArgumentException If {@code returnType} is not one of the types defined in {@link XPathConstants} ( + * {@link XPathConstants#NUMBER NUMBER}, + * {@link XPathConstants#STRING STRING}, + * {@link XPathConstants#BOOLEAN BOOLEAN}, + * {@link XPathConstants#NODE NODE} or + * {@link XPathConstants#NODESET NODESET}). + * @throws NullPointerException If {@code expression or returnType} is {@code null}. */ public Object evaluate(String expression, Object item, QName returnType) throws XPathExpressionException; /** - *

Evaluate an XPath expression in the specified context and return the result as a String.

+ * Evaluate an XPath expression in the specified context and return the result as a {@code String}. * - *

This method calls {@link #evaluate(String expression, Object item, QName returnType)} with a returnType of - * {@link XPathConstants#STRING}.

+ *

This method calls {@link #evaluate(String expression, Object item, QName returnType)} with a {@code returnType} of + * {@link XPathConstants#STRING}. * *

See Evaluation of XPath Expressions for context item evaluation, - * variable, function and QName resolution and return type conversion.

+ * variable, function and QName resolution and return type conversion. * - *

If a null value is provided for - * item, an empty document will be used for the - * context. - * If expression is null, then a NullPointerException is thrown.

+ *

+ * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. * + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. + * * @param expression The XPath expression. - * @param item The starting context (a node, for example). + * @param item The context the XPath expression will be evaluated in. * - * @return The String that is the result of evaluating the expression and - * converting the result to a String. + * @return The result of evaluating an XPath expression as a {@code String}. * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws NullPointerException If expression is null. + * @throws XPathExpressionException If {@code expression} cannot be evaluated. + * @throws NullPointerException If {@code expression} is {@code null}. */ public String evaluate(String expression, Object item) throws XPathExpressionException; /** - *

Evaluate an XPath expression in the context of the specified InputSource - * and return the result as the specified type.

+ * Evaluate an XPath expression in the context of the specified {@code InputSource} + * and return the result as the specified type. * *

This method builds a data model for the {@link InputSource} and calls - * {@link #evaluate(String expression, Object item, QName returnType)} on the resulting document object.

+ * {@link #evaluate(String expression, Object item, QName returnType)} on the resulting document object. * *

See Evaluation of XPath Expressions for context item evaluation, - * variable, function and QName resolution and return type conversion.

+ * variable, function and QName resolution and return type conversion. * - *

If returnType is not one of the types defined in {@link XPathConstants}, - * then an IllegalArgumentException is thrown.

- * - *

If expression, source or returnType is null, - * then a NullPointerException is thrown.

- * * @param expression The XPath expression. * @param source The input source of the document to evaluate over. * @param returnType The desired return type. * - * @return The Object that encapsulates the result of evaluating the expression. + * @return The {@code Object} that encapsulates the result of evaluating the expression. * * @throws XPathExpressionException If expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If expression, source or returnType - * is null. + * @throws IllegalArgumentException If {@code returnType} is not one of the types defined in {@link XPathConstants}. + * @throws NullPointerException If {@code expression, source or returnType} is {@code null}. */ public Object evaluate( String expression, @@ -293,27 +290,209 @@ throws XPathExpressionException; /** - *

Evaluate an XPath expression in the context of the specified InputSource - * and return the result as a String.

+ * Evaluate an XPath expression in the context of the specified {@code InputSource} + * and return the result as a {@code String}. * *

This method calls {@link #evaluate(String expression, InputSource source, QName returnType)} with a - * returnType of {@link XPathConstants#STRING}.

+ * {@code returnType} of {@link XPathConstants#STRING}. * *

See Evaluation of XPath Expressions for context item evaluation, - * variable, function and QName resolution and return type conversion.

+ * variable, function and QName resolution and return type conversion. * - *

If expression or source is null, - * then a NullPointerException is thrown.

- * * @param expression The XPath expression. - * @param source The InputSource of the document to evaluate over. + * @param source The {@code InputSource} of the document to evaluate over. * - * @return The String that is the result of evaluating the expression and - * converting the result to a String. + * @return The {@code String} that is the result of evaluating the expression and + * converting the result to a {@code String}. * * @throws XPathExpressionException If expression cannot be evaluated. - * @throws NullPointerException If expression or source is null. + * @throws NullPointerException If {@code expression or source} is {@code null}. */ public String evaluate(String expression, InputSource source) throws XPathExpressionException; + + /** + * Evaluate an XPath expression in the specified context and return + * the result with the type specified through the {@code class type} + * + *

+ * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. + * + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + *

 {@code
+     *     (T)evaluate(expression, item,
+     *           XPathEvaluationResult.XPathResultType.getQNameType(type));
+     * }
+ * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type, specifying + * XPathEvaluationResult as the type will result in IllegalArgumentException. + * Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must override + * this method. + * + * @param The class type that will be returned by the XPath expression. + * @param expression The XPath expression. + * @param item The context the XPath expression will be evaluated in. + * @param type The class type expected to be returned by the XPath expression. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If {@code type} is not of the types + * corresponding to the types defined in the {@link XPathEvaluationResult.XPathResultType}, + * or XPathEvaluationResult is specified as the type but an implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type is not available. + * @throws NullPointerException If {@code expression or type} is {@code null}. + * + * @since 1.9 + */ + default T evaluateExpression(String expression, Object item, Class type) + throws XPathExpressionException { + return type.cast(evaluate(expression, item, + XPathEvaluationResult.XPathResultType.getQNameType(type))); + } + + /** + * Evaluate an XPath expression in the specified context. This is equivalent to + * calling {@link #evaluateExpression(String expression, Object item, Class type)} + * with type {@link XPathEvaluationResult}: + *
 {@code
+     *     evaluateExpression(expression, item, XPathEvaluationResult.class);
+     * }
+ *

+ * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. + * + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + *

 {@code
+     *     evaluateExpression(expression, item, XPathEvaluationResult.class);
+     * }
+ * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} + * type, the default implementation of this method will always throw an + * IllegalArgumentException. Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must therefore + * override this method. + * + * @param expression The XPath expression. + * @param item The context the XPath expression will be evaluated in. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If the implementation of this method + * does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type. + * @throws NullPointerException If {@code expression} is {@code null}. + * + * @since 1.9 + */ + default XPathEvaluationResult evaluateExpression(String expression, Object item) + throws XPathExpressionException + { + return evaluateExpression(expression, item, XPathEvaluationResult.class); + } + + /** + * Evaluate an XPath expression in the context of the specified {@code source} + * and return the result as specified. + *

+ * This method builds a data model for the {@link InputSource} and calls + * {@link #evaluateExpression(String expression, Object item, Class type)} + * on the resulting document object. The data model is usually + * {@link org.w3c.dom.Document} + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + *

 {@code
+           (T)evaluate(expression, source,
+                XPathEvaluationResult.XPathResultType.getQNameType(type));
+     * }
+ * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type, specifying + * XPathEvaluationResult as the type will result in IllegalArgumentException. + * Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must override + * this method. + * + * @param The class type that will be returned by the XPath expression. + * @param expression The XPath expression. + * @param source The input source of the document to evaluate over. + * @param type The class type expected to be returned by the XPath expression. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If {@code type} is not of the types + * corresponding to the types defined in the {@link XPathEvaluationResult.XPathResultType + * XPathResultType}, or XPathEvaluationResult is specified as the type but an + * implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type is not available. + * @throws NullPointerException If {@code expression, source or type}is {@code null}. + * + * @since 1.9 + */ + default T evaluateExpression(String expression, InputSource source, Class type) + throws XPathExpressionException + { + return type.cast(evaluate(expression, source, + XPathEvaluationResult.XPathResultType.getQNameType(type))); + } + + /** + * Evaluate an XPath expression in the specified context. This is equivalent to + * calling {@link #evaluateExpression(String expression, Object item, Class type)} + * with type {@link XPathEvaluationResult}: + *
 {@code
+     *     evaluateExpression(expression, item, XPathEvaluationResult.class);
+     * }
+ *

+ * + * @implSpec + * The default implementation in the XPath API is equivalent to: + *

 {@code
+     *     evaluateExpression(expression, source, XPathEvaluationResult.class);
+     * }
+ * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} + * type, the default implementation of this method will always throw an + * IllegalArgumentException. Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must therefore + * override this method. + * + * @param expression The XPath expression. + * @param source The input source of the document to evaluate over. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If the implementation of this method + * does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type. + * @throws NullPointerException If {@code expression or source} is {@code null}. + * + * @since 1.9 + */ + default XPathEvaluationResult evaluateExpression(String expression, InputSource source) + throws XPathExpressionException + { + return evaluateExpression(expression, source, XPathEvaluationResult.class); + } } --- old/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java Wed Jan 21 21:16:32 2015 +++ new/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java Wed Jan 21 21:16:31 2015 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,11 @@ package javax.xml.xpath; -import org.xml.sax.InputSource; import javax.xml.namespace.QName; +import org.xml.sax.InputSource; /** - *

XPathExpression provides access to compiled XPath expressions.

+ *

{@code XPathExpression} provides access to compiled XPath expressions.

* * * @@ -53,7 +53,7 @@ * * @@ -62,7 +62,7 @@ * * * @@ -84,9 +84,9 @@ *

An XPath expression is not thread-safe and not reentrant. * In other words, it is the application's responsibility to make * sure that one {@link XPathExpression} object is not used from - * more than one thread at any given time, and while the evaluate + * more than one thread at any given time, and while the {@code evaluate} * method is invoked, applications may not recursively call - * the evaluate method. + * the {@code evaluate} method. *

* * @author Norman Walsh @@ -96,6 +96,7 @@ */ public interface XPathExpression { + /** *

Evaluate the compiled XPath expression in the specified context and return the result as the specified type.

* @@ -102,45 +103,50 @@ *

See Evaluation of XPath Expressions for context item evaluation, * variable, function and QName resolution and return type conversion.

* - *

If returnType is not one of the types defined in {@link XPathConstants}, - * then an IllegalArgumentException is thrown.

+ *

+ * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. * - *

If a null value is provided for - * item, an empty document will be used for the - * context. - * If returnType is null, then a NullPointerException is thrown.

+ * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. * - * @param item The starting context (a node, for example). - * @param returnType The desired return type. + * @param item The context the XPath expression will be evaluated in. + * @param returnType The result type expected to be returned by the XPath expression. * - * @return The Object that is the result of evaluating the expression and converting the result to - * returnType. + * @return The {@code Object} that is the result of evaluating the expression and converting the result to + * {@code returnType}. * * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If returnType is null. + * @throws IllegalArgumentException If {@code returnType} is not one of the types defined in {@link XPathConstants}. + * @throws NullPointerException If {@code returnType} is {@code null}. */ public Object evaluate(Object item, QName returnType) throws XPathExpressionException; /** - *

Evaluate the compiled XPath expression in the specified context and return the result as a String.

+ *

Evaluate the compiled XPath expression in the specified context and return the result as a {@code String}.

* - *

This method calls {@link #evaluate(Object item, QName returnType)} with a returnType of + *

This method calls {@link #evaluate(Object item, QName returnType)} with a {@code returnType} of * {@link XPathConstants#STRING}.

* *

See Evaluation of XPath Expressions for context item evaluation, * variable, function and QName resolution and return type conversion.

* - *

If a null value is provided for - * item, an empty document will be used for the - * context. + *

+ * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. * - * @param item The starting context (a node, for example). + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. * - * @return The String that is the result of evaluating the expression and converting the result to a - * String. + * @param item The context the XPath expression will be evaluated in. * + * @return The result of evaluating an XPath expression as a {@code String}. + * * @throws XPathExpressionException If the expression cannot be evaluated. */ public String evaluate(Object item) @@ -147,7 +153,7 @@ throws XPathExpressionException; /** - *

Evaluate the compiled XPath expression in the context of the specified InputSource and return the result as the + *

Evaluate the compiled XPath expression in the context of the specified {@code InputSource} and return the result as the * specified type.

* *

This method builds a data model for the {@link InputSource} and calls @@ -156,45 +162,225 @@ *

See Evaluation of XPath Expressions for context item evaluation, * variable, function and QName resolution and return type conversion.

* - *

If returnType is not one of the types defined in {@link XPathConstants}, - * then an IllegalArgumentException is thrown.

+ *

If {@code returnType} is not one of the types defined in {@link XPathConstants}, + * then an {@code IllegalArgumentException} is thrown.

* - *

If source or returnType is null, - * then a NullPointerException is thrown.

+ *

If {@code source} or {@code returnType} is {@code null}, + * then a {@code NullPointerException} is thrown.

* - * @param source The InputSource of the document to evaluate over. + * @param source The {@code InputSource} of the document to evaluate over. * @param returnType The desired return type. * - * @return The Object that is the result of evaluating the expression and converting the result to - * returnType. + * @return The {@code Object} that is the result of evaluating the expression and converting the result to + * {@code returnType}. * * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If source or returnType is null. + * @throws IllegalArgumentException If {@code returnType} is not one of the types defined in {@link XPathConstants}. + * @throws NullPointerException If {@code source or returnType} is {@code null}. */ public Object evaluate(InputSource source, QName returnType) throws XPathExpressionException; /** - *

Evaluate the compiled XPath expression in the context of the specified InputSource and return the result as a - * String.

+ *

Evaluate the compiled XPath expression in the context of the specified {@code InputSource} and return the result as a + * {@code String}.

* - *

This method calls {@link #evaluate(InputSource source, QName returnType)} with a returnType of + *

This method calls {@link #evaluate(InputSource source, QName returnType)} with a {@code returnType} of * {@link XPathConstants#STRING}.

* *

See Evaluation of XPath Expressions for context item evaluation, * variable, function and QName resolution and return type conversion.

* - *

If source is null, then a NullPointerException is thrown.

+ *

If {@code source} is {@code null}, then a {@code NullPointerException} is thrown.

* - * @param source The InputSource of the document to evaluate over. + * @param source The {@code InputSource} of the document to evaluate over. * - * @return The String that is the result of evaluating the expression and converting the result to a - * String. + * @return The {@code String} that is the result of evaluating the expression and converting the result to a + * {@code String}. * * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws NullPointerException If source is null. + * @throws NullPointerException If {@code source} is {@code null}. */ public String evaluate(InputSource source) throws XPathExpressionException; + + /** + * Evaluate the compiled XPath expression in the specified context, and return + * the result with the type specified through the {@code class type}. + * + *

+ * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. + * + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + *

 {@code
+     *     (T)evaluate(item, XPathEvaluationResult.XPathResultType.getQNameType(type));
+     * }
+ * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type, specifying + * XPathEvaluationResult as the type will result in IllegalArgumentException. + * Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must override + * this method. + * + * @param The class type that will be returned by the XPath expression. + * @param item The context the XPath expression will be evaluated in. + * @param type The class type expected to be returned by the XPath expression. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If {@code type} is not of the types + * corresponding to the types defined in the {@link XPathEvaluationResult.XPathResultType + * XPathResultType}, or XPathEvaluationResult is specified as the type but an + * implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type is not available. + * @throws NullPointerException If {@code type} is {@code null}. + * + * @since 1.9 + */ + default T evaluateExpression(Object item, Class type) + throws XPathExpressionException + { + return type.cast(evaluate(item, XPathEvaluationResult.XPathResultType.getQNameType(type))); + } + + /** + * Evaluate the compiled XPath expression in the specified context. This is + * equivalent to calling {@link #evaluateExpression(Object item, Class type)} + * with type {@link XPathEvaluationResult}: + *
 {@code
+     *     evaluateExpression(item, XPathEvaluationResult.class);
+     * }
+ *

+ * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. + * + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + *

 {@code
+     *     evaluateExpression(item, XPathEvaluationResult.class);
+     * }
+ * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} + * type, the default implementation of this method will always throw an + * IllegalArgumentException. Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must therefore + * override this method. + * + * @param item The context the XPath expression will be evaluated in. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If the implementation of this method + * does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type. + * + * @since 1.9 + */ + default XPathEvaluationResult evaluateExpression(Object item) + throws XPathExpressionException + { + return evaluateExpression(item, XPathEvaluationResult.class); + } + + /** + * Evaluate the compiled XPath expression in the specified context, + * and return the result with the type specified through the {@code class type} + *

+ * This method builds a data model for the {@link InputSource} and calls + * {@link #evaluateExpression(Object item, Class type)} on the resulting + * document object. + *

+ * By default, the JDK's data model is {@link org.w3c.dom.Document}. + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + *

 {@code
+           (T)evaluate(source, XPathEvaluationResult.XPathResultType.getQNameType(type));
+     * }
+ * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type, specifying + * XPathEvaluationResult as the type will result in IllegalArgumentException. + * Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must override + * this method. + * + * @param The class type that will be returned by the XPath expression. + * @param source The {@code InputSource} of the document to evaluate over. + * @param type The class type expected to be returned by the XPath expression. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If {@code type} is not of the types + * corresponding to the types defined in the {@link XPathEvaluationResult.XPathResultType + * XPathResultType}, or XPathEvaluationResult is specified as the type but an + * implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type + * is not available. + * @throws NullPointerException If {@code source or type} is {@code null}. + * + * @since 1.9 + */ + default T evaluateExpression(InputSource source, Class type) + throws XPathExpressionException + { + return type.cast(evaluate(source, XPathEvaluationResult.XPathResultType.getQNameType(type))); + } + + /** + * Evaluate the compiled XPath expression in the specified context. This is + * equivalent to calling {@link #evaluateExpression(InputSource source, Class type)} + * with type {@link XPathEvaluationResult}: + *
 {@code
+     *     evaluateExpression(source, XPathEvaluationResult.class);
+     * }
+ *

+ * + * @implSpec + * The default implementation in the XPath API is equivalent to: + *

 {@code
+     *     (XPathEvaluationResult)evaluateExpression(source, XPathEvaluationResult.class);
+     * }
+ * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} + * type, the default implementation of this method will always throw an + * IllegalArgumentException. Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must therefore + * override this method. + * + * @param source The {@code InputSource} of the document to evaluate over. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If the implementation of this method + * does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type. + * @throws NullPointerException If {@code source} is {@code null}. + * + * @since 1.9 + */ + default XPathEvaluationResult evaluateExpression(InputSource source) + throws XPathExpressionException + { + return evaluateExpression(source, XPathEvaluationResult.class); + } } --- old/src/java.xml/share/classes/javax/xml/xpath/XPathFactory.java Wed Jan 21 21:16:32 2015 +++ new/src/java.xml/share/classes/javax/xml/xpath/XPathFactory.java Wed Jan 21 21:16:32 2015 @@ -117,7 +117,7 @@ * and returns it if it is successfully created. * *
  • - * ${java.home}/conf/jaxp.properties is read and the value associated with the key being the system property above is looked for. + * ${java.home}/lib/jaxp.properties is read and the value associated with the key being the system property above is looked for. * If present, the value is processed just like above. *
  • *
  • --- old/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java Wed Jan 21 21:16:33 2015 +++ new/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java Wed Jan 21 21:16:33 2015 @@ -176,9 +176,9 @@ String javah = ss.getSystemProperty( "java.home" ); String configFile = javah + File.separator + - "conf" + File.separator + "jaxp.properties"; + "lib" + File.separator + "jaxp.properties"; - // try to read from $java.home/conf/jaxp.properties + // try to read from $java.home/lib/jaxp.properties try { if(firstTime){ synchronized(cacheProps){ @@ -193,7 +193,7 @@ } } final String factoryClassName = cacheProps.getProperty(propertyName); - debugPrintln("found " + factoryClassName + " in $java.home/conf/jaxp.properties"); + debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties"); if (factoryClassName != null) { xpathFactory = createInstance(factoryClassName, true); --- old/src/java.xml/share/classes/javax/xml/xpath/package.html Wed Jan 21 21:16:34 2015 +++ new/src/java.xml/share/classes/javax/xml/xpath/package.html Wed Jan 21 21:16:34 2015 @@ -1,6 +1,8 @@ - + + + - - - - -javax.xml.xpath - - - - - + - - -

    This package provides an object-model neutral API for the +This package provides an object-model neutral API for the evaluation of XPath expressions and access to the evaluation environment. -

    -

    The following XML standards apply:

    +

    +The XPath API supports + XML Path Language (XPath) Version 1.0 +


    + +

    + +

    1. XPath Overview

    -
    - -

    XPath Overview

    -

    The XPath language provides a simple, concise syntax for selecting nodes from an XML document. XPath also provides rules for converting a node in an XML document object model (DOM) tree to a boolean, double, @@ -67,7 +69,8 @@ replace many lines of DOM API code.

    -

    XPath Expressions

    + +

    2. XPath Expressions

    An XPath expression is composed of a location path and one or more optional predicates. Expressions @@ -76,18 +79,22 @@

    The following is an example of a simple XPath expression:

    +
     /foo/bar
     
    +

    This example would select the <bar> element in an XML document such as the following:

    +
     <foo>
    -<bar/>
    +    <bar/>
     </foo>
     
    +

    The expression /foo/bar is an example of a location path. While XPath location paths resemble Unix-style file system @@ -96,13 +103,15 @@ <bar> elements in the following document would be selected by the /foo/bar expression:

    +
     <foo>
    -<bar/>
    -<bar/>
    -<bar/>
    +    <bar/>
    +    <bar/>
    +    <bar/>
     </foo>
     
    +

    A special location path operator, //, selects nodes at any depth in an XML document. The following example selects all @@ -109,17 +118,21 @@ <bar> elements regardless of their location in a document:

    +
     //bar
     
    +

    A wildcard operator, *, causes all element nodes to be selected. The following example selects all children elements of a -<foo> element:

    +<foo> element: +
     /foo/*
     
    +

    In addition to element nodes, XPath location paths may also address attribute nodes, text nodes, comment nodes, and processing instruction @@ -166,35 +179,27 @@ <foo> elements that contain an include attribute with the value of true:

    +
     //foo[@include='true']
     
    +

    Predicates may be appended to each other to further refine an expression, such as:

    +
     //foo[@include='true'][@mode='bar']
     
    +
    -

    Using the XPath API

    + +

    3. XPath Data Types

    -

    -The following example demonstrates using the XPath API to select one -or more nodes from an XML document:

    - -
    -XPath xpath = XPathFactory.newInstance().newXPath();
    -String expression = "/widgets/widget";
    -InputSource inputSource = new InputSource("widgets.xml");
    -NodeList nodes = (NodeList) xpath.evaluate(expression, inputSource, XPathConstants.NODESET);
    -
    - -

    XPath Expressions and Types

    -

    While XPath expressions select nodes in the XML document, the XPath API allows the selected nodes to be coalesced into one of the -following other data types:

    +following data types:

    • Boolean
    • @@ -202,14 +207,10 @@
    • String
    -

    The desired return type is specified by a {@link -javax.xml.namespace.QName} parameter in method call used to evaluate -the expression, which is either a call to -XPathExpression.evalute(...) or to one of the -XPath.evaluate(...) convenience methods. The allowed -QName values are specified as constants in the {@link -javax.xml.xpath.XPathConstants} class; they are:

    - + +

    3.1 QName types

    +The XPath API defines the following {@link javax.xml.namespace.QName} types to +represent return types of an XPath evaluation:
    • {@link javax.xml.xpath.XPathConstants#NODESET}
    • {@link javax.xml.xpath.XPathConstants#NODE}
    • @@ -218,26 +219,71 @@
    • {@link javax.xml.xpath.XPathConstants#NUMBER}
    +

    The return type is specified by a {@link javax.xml.namespace.QName} parameter +in method call used to evaluate the expression, which is either a call to +XPathExpression.evalute(...) or XPath.evaluate(...) +methods. +

    When a Boolean return type is requested, Boolean.TRUE is returned if one or more nodes were -selected; otherwise, Boolean.FALSE is returned.

    +selected; otherwise, Boolean.FALSE is returned.

    The String return type is a convenience for retrieving the character data from a text node, attribute node, comment node, or processing-instruction node. When used on an element node, the value of the child text nodes is returned. -

    The Number return type attempts to coalesce the text of a node to a double data type. -

    -

    XPath Context

    + +

    3.2 Class types

    +In addition to the QName types, the XPath API supports the use of Class types +through the XPathExpression.evaluteExpression(...) or +XPath.evaluateExpression(...) methods. +The XPath data types are mapped to Class types as follows: +
      +
    • Boolean -- Boolean.class
    • +
    • Number -- Number.class
    • +
    • String -- String.class
    • +
    • Nodeset -- XPathNodes.class
    • +
    • Node -- Node.class
    • +
    + +

    +Of the subtypes of Number, only Double, Integer and Long are supported. + + +

    3.3 Enum types

    +Enum types are defined in {@link javax.xml.xpath.XPathEvaluationResult.XPathResultType} +that provide mappings between the QName and Class types above. The result of +evaluating an expression using the XPathExpression.evaluteExpression(...) +or XPath.evaluateExpression(...) methods will be of one of these types. + + +

    4. XPath Context

    +

    XPath location paths may be relative to a particular node in the -document, known as the context. Consider the following -XML document:

    +document, known as the context. A context consists of: +
      +
    • a node (the context node)
    • +
    • a pair of non-zero positive integers (the context position and the context size)
    • +
    • a set of variable bindings
    • +
    • a function library
    • +
    • the set of namespace declarations in scope for the expression
    • +
    +

    +It is an XML document tree represented as a hierarchy of nodes, a +{@link org.w3c.dom.Node} for example, in the JDK implementation. + + +

    5. Using the XPath API

    + +Consider the following XML document: +

    +

     <widgets>
     <widget>
    @@ -246,36 +292,88 @@
     </widget>
     </widgets>
     
    +
    -

    The <widget> element can be selected with the -following XPath API code:

    +

    +The <widget> element can be selected with the following process: +

     // parse the XML as a W3C Document
     DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
     Document document = builder.parse(new File("/widgets.xml"));
     
    +//Get an XPath object and evaluate the expression
     XPath xpath = XPathFactory.newInstance().newXPath();
     String expression = "/widgets/widget";
     Node widgetNode = (Node) xpath.evaluate(expression, document, XPathConstants.NODE);
    +
    +//or using the evaluateExpression method
    +Node widgetNode = xpath.evaluateExpression(expression, document, Node.class);
     
    +

    With a reference to the <widget> element, a -relative XPath expression can now written to select the +relative XPath expression can be written to select the <manufacturer> child element:

    +
     XPath xpath = XPathFactory.newInstance().newXPath();
     String expression = "manufacturer";
     Node manufacturerNode = (Node) xpath.evaluate(expression, widgetNode, XPathConstants.NODE);
    +
    +//or using the evaluateExpression method
    +Node manufacturerNode = xpath.evaluateExpression(expression, widgetNode, Node.class);
     
    +
    - +

    +In the above example, the XML file is read into a DOM Document before being passed +to the XPath API. The following code demonstrates the use of InputSource to +leave it to the XPath implementation to process it: + +

    +
    +XPath xpath = XPathFactory.newInstance().newXPath();
    +String expression = "/widgets/widget";
    +InputSource inputSource = new InputSource("widgets.xml");
    +NodeList nodes = (NodeList) xpath.evaluate(expression, inputSource, XPathConstants.NODESET);
    +
    +//or using the evaluateExpression method
    +XPathNodes nodes = xpath.evaluate(expression, inputSource, XPathNodes.class);
    +
    +
    + +

    +In the above cases, the type of the expected results are known. In case where +the result type is unknown or any type, the {@link javax.xml.xpath.XPathEvaluationResult} +may be used to determine the return type. The following code demonstrates the usage: +

    +
    +XPathEvaluationResult<?> result = xpath.evaluateExpression(expression, document);
    +switch (result.type()) {
    +    case NODESET:
    +        XPathNodes nodes = (XPathNodes)result.value();
    +        ...
    +        break;
    +}
    +
    +
    + +

    +The XPath 1.0 Number data type is defined as a double. However, the XPath +specification also provides functions that returns Integer type. To facilitate +such operations, the XPath API allows Integer and Long to be used in +{@code evaluateExpression} method such as the following code: +

    +

    +
    +int count = xpath.evaluate("count(/widgets/widget)", document, Integer.class);
    +
    +
    + +@since 1.5 + --- /dev/null Wed Jan 21 21:16:35 2015 +++ new/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java Wed Jan 21 21:16:35 2015 @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.org.apache.xpath.internal.jaxp; + +import com.sun.org.apache.xalan.internal.res.XSLMessages; +import com.sun.org.apache.xalan.internal.utils.FactoryImpl; +import com.sun.org.apache.xalan.internal.utils.FeatureManager; +import com.sun.org.apache.xml.internal.dtm.DTM; +import com.sun.org.apache.xpath.internal.objects.XObject; +import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; +import java.io.IOException; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathEvaluationResult; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFunctionResolver; +import javax.xml.xpath.XPathNodes; +import javax.xml.xpath.XPathVariableResolver; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.traversal.NodeIterator; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * This class contains several utility methods used by XPathImpl and + * XPathExpressionImpl + */ +class XPathImplUtil { + XPathFunctionResolver functionResolver; + XPathVariableResolver variableResolver; + JAXPPrefixResolver prefixResolver; + boolean useServiceMechanism = true; + // By default Extension Functions are allowed in XPath Expressions. If + // Secure Processing Feature is set on XPathFactory then the invocation of + // extensions function need to throw XPathFunctionException + boolean featureSecureProcessing = false; + FeatureManager featureManager; + + /** + * Evaluate an XPath context using the internal XPath engine + * @param contextItem The XPath context + * @param xpath The internal XPath engine + * @return an XObject + * @throws javax.xml.transform.TransformerException If the expression cannot be evaluated. + */ + XObject eval(Object contextItem, com.sun.org.apache.xpath.internal.XPath xpath) + throws javax.xml.transform.TransformerException { + com.sun.org.apache.xpath.internal.XPathContext xpathSupport; + if (functionResolver != null) { + JAXPExtensionsProvider jep = new JAXPExtensionsProvider( + functionResolver, featureSecureProcessing, featureManager); + xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext(jep); + } else { + xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext(); + } + + xpathSupport.setVarStack(new JAXPVariableStack(variableResolver)); + XObject xobj; + + Node contextNode = (Node)contextItem; + // We always need to have a ContextNode with Xalan XPath implementation + // To allow simple expression evaluation like 1+1 we are setting + // dummy Document as Context Node + if (contextNode == null) { + xobj = xpath.execute(xpathSupport, DTM.NULL, prefixResolver); + } else { + xobj = xpath.execute(xpathSupport, contextNode, prefixResolver); + } + + return xobj; + } + + /** + * Parse the input source and return a Document. + * @param source The {@code InputSource} of the document + * @return a DOM Document + * @throws XPathExpressionException if there is an error parsing the source. + */ + Document getDocument(InputSource source) + throws XPathExpressionException { + requireNonNull(source, "Source"); + try { + // we'd really like to cache those DocumentBuilders, but we can't because: + // 1. thread safety. parsers are not thread-safe, so at least + // we need one instance per a thread. + // 2. parsers are non-reentrant, so now we are looking at having a + // pool of parsers. + // 3. then the class loading issue. The look-up procedure of + // DocumentBuilderFactory.newInstance() depends on context class loader + // and system properties, which may change during the execution of JVM. + // + // so we really have to create a fresh DocumentBuilder every time we need one + // - KK + DocumentBuilderFactory dbf = FactoryImpl.getDOMFactory(useServiceMechanism); + dbf.setNamespaceAware(true); + dbf.setValidating(false); + return dbf.newDocumentBuilder().parse(source); + } catch (ParserConfigurationException | SAXException | IOException e) { + throw new XPathExpressionException (e); + } + } + + /** + * Get result depending on the QName type defined in XPathConstants + * @param resultObject the result of an evaluation + * @param returnType the return type + * @return result per the return type + * @throws TransformerException if the result can not be converted to + * the specified return type. + */ + Object getResultAsType(XObject resultObject, QName returnType) + throws TransformerException { + // XPathConstants.STRING + if (returnType.equals(XPathConstants.STRING)) { + return resultObject.str(); + } + // XPathConstants.NUMBER + if (returnType.equals(XPathConstants.NUMBER)) { + return resultObject.num(); + } + // XPathConstants.BOOLEAN + if (returnType.equals(XPathConstants.BOOLEAN)) { + return resultObject.bool(); + } + // XPathConstants.NODESET ---ORdered, UNOrdered??? + if (returnType.equals(XPathConstants.NODESET)) { + return resultObject.nodelist(); + } + // XPathConstants.NODE + if (returnType.equals(XPathConstants.NODE)) { + NodeIterator ni = resultObject.nodeset(); + //Return the first node, or null + return ni.nextNode(); + } + // If isSupported check is already done then the execution path + // shouldn't come here. Being defensive + String fmsg = XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, + new Object[] { returnType.toString()}); + throw new IllegalArgumentException (fmsg); + } + + + /** + * Get result depending on the class type defined in XPathExpressionResult + * @param resultObject the result of an evaluation + * @return XPathExpressionResult + * @throws TransformerException if there is an error converting the result + * to the specified type. It's unlikely to happen. This is mostly needed + * by the internal XPath engine. + */ + T getXPathResult(XObject resultObject, Class type) + throws TransformerException { + int resultType = resultObject.getType(); + + switch (resultType) { + case XObject.CLASS_BOOLEAN : + return type.cast(new XPathResultImpl<>(resultObject, Boolean.class)); + case XObject.CLASS_NUMBER : + return type.cast(new XPathResultImpl<>(resultObject, Double.class)); + case XObject.CLASS_STRING : + return type.cast(new XPathResultImpl<>(resultObject, String.class)); + case XObject.CLASS_NODESET : + return type.cast(new XPathResultImpl<>(resultObject, XPathNodes.class)); + case XObject.CLASS_RTREEFRAG : //NODE + return type.cast(new XPathResultImpl<>(resultObject, Node.class)); + } + + return null; + } + + /** + * Check whether or not the specified type is supported + * @param The class type + * @param type The type to be checked + * @throws IllegalArgumentException if the type is not supported + */ + void isSupportedClassType(Class type) { + requireNonNull(type, "The class type"); + if (type.isAssignableFrom(Boolean.class) || + type.isAssignableFrom(Double.class) || + type.isAssignableFrom(Integer.class) || + type.isAssignableFrom(Long.class) || + type.isAssignableFrom(String.class) || + type.isAssignableFrom(XPathNodes.class) || + type.isAssignableFrom(Node.class) || + type.isAssignableFrom(XPathEvaluationResult.class)) { + return; + } + String fmsg = XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, + new Object[] { type.toString() }); + throw new IllegalArgumentException (fmsg); + } + + /** + * Check if the requested returnType is supported. + * @param returnType the return type + * @throws IllegalArgumentException if the return type is not supported + */ + void isSupported(QName returnType) { + requireNonNull(returnType, "returnType"); + if (returnType.equals(XPathConstants.STRING) || + returnType.equals(XPathConstants.NUMBER) || + returnType.equals(XPathConstants.BOOLEAN) || + returnType.equals(XPathConstants.NODE) || + returnType.equals(XPathConstants.NODESET)) { + return; + } + String fmsg = XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, + new Object[] { returnType.toString() }); + throw new IllegalArgumentException (fmsg); + } + + /** + * Checks that the specified parameter is not {@code null}. + * + * @param the type of the reference + * @param param the parameter to check for nullity + * @param paramName the parameter name + * @throws NullPointerException if {@code param} is {@code null} + */ + void requireNonNull(T param, String paramName) { + if (param == null) { + String fmsg = XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, + new Object[] {paramName}); + throw new NullPointerException (fmsg); + } + } +} --- /dev/null Wed Jan 21 21:16:36 2015 +++ new/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathNodesImpl.java Wed Jan 21 21:16:36 2015 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.org.apache.xpath.internal.jaxp; + +import java.util.Iterator; +import javax.xml.xpath.XPathException; +import javax.xml.xpath.XPathNodes; +import javax.xml.xpath.XPathEvaluationResult.XPathResultType; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * This class implements XPathNodes that represents a set of nodes selected by + * evaluating an expression. + */ +public class XPathNodesImpl implements XPathNodes { + XPathResultType type; + Class elementType; + NodeList nodeList = null; + + public XPathNodesImpl(NodeList nodeList, XPathResultType type, Class elementType) { + this.nodeList = nodeList; + this.type = type; + this.elementType = elementType; + } + + @Override + public Iterator iterator() { + return new NodeSetIterator<>(elementType); + } + + class NodeSetIterator implements Iterator { + int currentIndex; + Class elementType; + NodeSetIterator(Class elementType) { + this.elementType = elementType; + } + public boolean hasNext() { + if (type != XPathResultType.NODE) { + throw new UnsupportedOperationException("Incorrect type: result" + + "type requested: " + type + ", but assumed" + + "Node."); + } + if (nodeList != null) { + return currentIndex < nodeList.getLength(); + } + + return false; + } + + public E next() { + if (nodeList != null && nodeList.getLength() > 0) { + return elementType.cast(nodeList.item(currentIndex++)); + } + return null; + } + } + + @Override + public int size() { + if (nodeList != null) { + return nodeList.getLength(); + } + return 0; + } + + @Override + public Node get(int index) throws XPathException { + if (index <0 || index >= size()) { + throw new IndexOutOfBoundsException("Index " + index + " is out of bounds"); + } + if (nodeList != null) { + return nodeList.item(index); + } + return null; + } +} --- /dev/null Wed Jan 21 21:16:37 2015 +++ new/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathResultImpl.java Wed Jan 21 21:16:37 2015 @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.org.apache.xpath.internal.jaxp; + +import com.sun.org.apache.xpath.internal.objects.XObject; +import java.util.Objects; +import javax.xml.transform.TransformerException; +import javax.xml.xpath.XPathNodes; +import javax.xml.xpath.XPathEvaluationResult; +import javax.xml.xpath.XPathEvaluationResult.XPathResultType; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.traversal.NodeIterator; + + +/** + * This is the implementation of XPathEvaluationResult that represents the + * result of the evaluation of an XPath expression within the context of a + * particular node. + */ +class XPathResultImpl implements XPathEvaluationResult { + + XObject resultObject; + int resultType; + Class type; + XPathResultType mapToType; + NodeList nodeList = null; + int currentIndex; + Node currentNode; + + boolean boolValue = false; + Node node = null; + double numValue; + String strValue; + + /** + * Construct an XPathEvaluationResult object. + * + * @param resultObject internal XPath result object + * @param type class type + * @throws TransformerException if there is an error reading the XPath + * result. + */ + public XPathResultImpl(XObject resultObject, Class type) + throws TransformerException { + this.resultObject = resultObject; + resultType = resultObject.getType(); + this.type = type; + getResult(resultObject); + } + + /** + * Return the result type as an enum specified by {@code XPathResultType} + * @return the result type + */ + @Override + public XPathResultType type() { + return mapToType; + } + + /** + * Returns the value of the result as the type <T> specified for the class. + * + * @return The value of the result. + */ + @Override + public T value() { + Objects.requireNonNull(type); + try { + return getValue(resultObject, type); + } catch (TransformerException ex) { + throw new RuntimeException(ex); + } + } + + /** + * Read the XObject and set values in accordance with the result type + * @param resultObject internal XPath result object + * @throws TransformerException if there is an error reading the XPath + * result. + */ + private void getResult(XObject resultObject) throws TransformerException { + switch (resultType) { + case XObject.CLASS_BOOLEAN: + boolValue = resultObject.bool(); + mapToType = XPathResultType.BOOLEAN; + break; + case XObject.CLASS_NUMBER: + numValue = resultObject.num(); + mapToType = XPathResultType.NUMBER; + break; + case XObject.CLASS_STRING: + strValue = resultObject.str(); + mapToType = XPathResultType.STRING; + break; + case XObject.CLASS_NODESET: + mapToType = XPathResultType.NODESET; + nodeList = resultObject.nodelist(); + break; + case XObject.CLASS_RTREEFRAG: //NODE + mapToType = XPathResultType.NODE; + NodeIterator ni = resultObject.nodeset(); + //Return the first node, or null + node = ni.nextNode(); + break; + } + } + + /** + * Read the internal result object and return the value in accordance with + * the type specified. + * + * @param The expected class type. + * @param resultObject internal XPath result object + * @param type the class type + * @return The value of the result. + * @throws TransformerException if there is an error reading the XPath + * result. + */ + static T getValue(XObject resultObject, Class type) throws TransformerException { + Objects.requireNonNull(type); + if (type.isAssignableFrom(XPathEvaluationResult.class)) { + return type.cast(new XPathResultImpl(resultObject, type)); + } + int resultType = classToInternalType(type); + switch (resultType) { + case XObject.CLASS_BOOLEAN: + return type.cast(resultObject.bool()); + case XObject.CLASS_NUMBER: + if (Double.class.isAssignableFrom(type)) { + return type.cast(resultObject.num()); + } else if (Integer.class.isAssignableFrom(type)) { + return type.cast((int)resultObject.num()); + } else if (Long.class.isAssignableFrom(type)) { + return type.cast((long)resultObject.num()); + } + /* + This is to suppress warnings. By the current specification, + among numeric types, only Double, Integer and Long are supported. + */ + break; + case XObject.CLASS_STRING: + return type.cast(resultObject.str()); + case XObject.CLASS_NODESET: + XPathNodes nodeSet = new XPathNodesImpl(resultObject.nodelist(), + classToType(Node.class), Node.class); + return type.cast(nodeSet); + case XObject.CLASS_RTREEFRAG: //NODE + NodeIterator ni = resultObject.nodeset(); + //Return the first node, or null + return type.cast(ni.nextNode()); + } + + return null; + } + + /** + * Map class types to the XPathResultType + * + * @param The expected class type. + * @param type the class type + * @return an XPathResultType enum type + */ + static XPathResultType classToType(Class type) { + if (type.isAssignableFrom(Boolean.class)) { + return XPathResultType.BOOLEAN; + } else if (type.isAssignableFrom(Double.class)) { + return XPathResultType.NUMBER; + } else if (type.isAssignableFrom(String.class)) { + return XPathResultType.STRING; + } else if (type.isAssignableFrom(NodeList.class)) { + return XPathResultType.NODESET; + } else if (type.isAssignableFrom(Node.class)) { + return XPathResultType.NODE; + } + return XPathResultType.ANY; + } + + /** + * Map the specified class type to the internal result type + * + * @param The expected class type. + * @param type the class type + * @return the internal XObject type. + */ + static int classToInternalType(Class type) { + if (type.isAssignableFrom(Boolean.class)) { + return XObject.CLASS_BOOLEAN; + } else if (Number.class.isAssignableFrom(type)) { + return XObject.CLASS_NUMBER; + } else if (type.isAssignableFrom(String.class)) { + return XObject.CLASS_STRING; + } else if (type.isAssignableFrom(XPathNodes.class)) { + return XObject.CLASS_NODESET; + } else if (type.isAssignableFrom(Node.class)) { + return XObject.CLASS_RTREEFRAG; + } + return XObject.CLASS_NULL; + } +} --- /dev/null Wed Jan 21 21:16:38 2015 +++ new/src/java.xml/share/classes/javax/xml/xpath/XPathEvaluationResult.java Wed Jan 21 21:16:37 2015 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javax.xml.xpath; + +import java.util.Objects; +import javax.xml.namespace.QName; +import org.w3c.dom.Node; +/** + * The {@code XPathEvaluationResult} interface represents the result of the + * evaluation of an XPath expression within the context of a particular node. + * The evaluation of an XPath expression can result in various result types as + * defined in XML Path Language (XPath) Version 1.0. + *

    + * + * @param the object type returned by the XPath evaluation. + * @see XML Path Language (XPath) Version + * 1.0 + * + * @since 1.9 + */ +public interface XPathEvaluationResult { + + /** + * XPathResultType represents possible return types of an XPath evaluation. + * Provided as an enum type, it allows the use of switch statement. At the + * same time, a mapping is provided between the original QName types in + * {@link XPathConstants} and class types used in the generic methods. + */ + public static enum XPathResultType { + /** + * Any type that represents any of the 5 other types listed below. + * Maps to {@link XPathEvaluationResult}. + */ + ANY(new QName("http://www.w3.org/1999/XSL/Transform", "any"), XPathEvaluationResult.class), + /** + * The XPath 1.0 boolean data type. Maps to Java {@link Boolean}. + */ + BOOLEAN(XPathConstants.BOOLEAN, Boolean.class), + /** + * The XPath 1.0 Number data type. Maps to Java {@link Number}. Of the + * subtypes of Number, only Double, Integer and Long are required. + */ + NUMBER(XPathConstants.NUMBER, Number.class), + /** + * The XPath 1.0 String data type. Maps to Java {@link String}. + */ + STRING(XPathConstants.STRING, String.class), + /** + * The XPath 1.0 NodeSet data type. Maps to {@link org.w3c.dom.NodeList}. + */ + NODESET(XPathConstants.NODESET, XPathNodes.class), + /** + * The XPath 1.0 NodeSet data type. Maps to {@link org.w3c.dom.Node}. + */ + NODE(XPathConstants.NODE, Node.class); + + final QName qnameType; + final Class clsType; + XPathResultType(QName qnameType, Class clsType) { + this.qnameType = qnameType; + this.clsType = clsType; + } + + /** + * Compares this type to the specified class type. + * @param clsType class type + * @return true if the argument is not null and is a class type that + * matches that this type represents, false otherwise. + */ + private boolean equalsClassType(Class clsType) { + Objects.nonNull(clsType); + if (clsType.isAssignableFrom(this.clsType)) { + return true; + } + return false; + } + + /** + * Returns the QName type as specified in {@link XPathConstants} that + * corresponds to the specified class type. + * @param clsType a class type that the enum type supports + * @return the QName type that matches with the specified class type, + * null if there is no match + */ + static public QName getQNameType(Class clsType) { + for (XPathResultType type : XPathResultType.values()) { + if (type.equalsClassType(clsType)) { + return type.qnameType; + } + } + return null; + } + } + + /** + * Return the result type as an enum specified by {@code XPathResultType} + * @return the result type + */ + public XPathResultType type(); + + /** + * Returns the value of the result as the type <T> specified for the class. + * + * @return The value of the result. + */ + public T value(); + +} --- /dev/null Wed Jan 21 21:16:39 2015 +++ new/src/java.xml/share/classes/javax/xml/xpath/XPathNodes.java Wed Jan 21 21:16:38 2015 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.xml.xpath; + +import java.util.Iterator; +import org.w3c.dom.Node; + +/** + * XPathNodes represents a set of nodes selected by a location path as specified + * in XML Path Language (XPath) + * Version 1.0, 3.3 Node-sets. + * + * @since 1.9 + */ +public interface XPathNodes extends Iterable { + + /** + * Returns an iterator of the Nodes. + * + * @return an Iterator. + */ + @Override + public abstract Iterator iterator(); + + /** + * Returns the number of items in the result + * + * @return The number of items in the result + */ + public abstract int size(); + + /** + * Returns a Node at the specified position + * + * @param index Index of the element to return. + * @return The Node at the specified position. + * @throws javax.xml.xpath.XPathException If the index is out of range + * (index < 0 || index >= size()) + */ + public abstract Node get(int index) + throws XPathException; +} --- /dev/null Wed Jan 21 21:16:39 2015 +++ new/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathAnyTypeTest.java Wed Jan 21 21:16:39 2015 @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javax.xml.xpath; + +import java.io.File; +import javax.xml.xpath.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import org.testng.annotations.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +/* + * @bug 8054196 + * @summary Test for the project XPath: support any type. This test covers the new + * evaluateExpression methods of XPath, as well as XPathNodes and XPathEvaluationResult. + */ +public class XPathAnyTypeTest extends XPathTestBase { + /* + Test for resolveFunction(QName functionName,int arity); evaluate throws + NPE if functionName is null. + */ + + @Test(dataProvider = "xpath", expectedExceptions = NullPointerException.class) + public void testCheckXPathFunctionResolver02(XPath xpath) throws XPathExpressionException { + xpath.setXPathFunctionResolver((functionName, arity) -> null); + assertEquals(xpath.evaluate(null, "5"), "2"); + } + /* + Check that NPE is thrown when expression is null. + */ + + @Test(dataProvider = "xpath", expectedExceptions = NullPointerException.class) + public void test01(XPath xpath) throws XPathExpressionException { + double result = xpath.evaluateExpression(null, (Object) null, Double.class); + } + + /* + Check that NPE is thrown when the class type is null. + */ + @Test(dataProvider = "xpath", expectedExceptions = NullPointerException.class) + public void test02(XPath xpath) throws XPathExpressionException { + double result = xpath.evaluateExpression("1+1", (Object) null, null); + } + + /* + Parameter item can be null when the expression does not depends on the + context. + */ + @Test(dataProvider = "xpath") + public void test03(XPath xpath) throws XPathExpressionException { + int result = xpath.evaluateExpression("1+1", (Object) null, Integer.class); + assertTrue(result == 2); + } + + /* + * Test return type: boolean. + */ + @Test(dataProvider = "document") + public void test04(XPath xpath, Document doc) throws XPathExpressionException { + boolean result1 = xpath.evaluateExpression("boolean(/Customers/Customer[@id=3])", doc, Boolean.class); + assertTrue(result1); + } + + /* + * Test return type: numeric. Subtypes supported: Double, Integer and Long + */ + @Test(dataProvider = "document") + public void test05(XPath xpath, Document doc) throws XPathExpressionException { + double result1 = xpath.evaluateExpression("count(/Customers/Customer)", doc, Double.class); + assertTrue(result1 == 3.0); + int result2 = xpath.evaluateExpression("count(/Customers/Customer)", doc, Integer.class); + assertTrue(result2 == 3); + long result3 = xpath.evaluateExpression("count(/Customers/Customer)", doc, Long.class); + assertTrue(result3 == 3); + } + + /* + * Test return type: numeric. Of the subtypes of Number, only Double, + * Integer and Long are required. + */ + @Test(dataProvider = "invalidNumericTypes", expectedExceptions = IllegalArgumentException.class) + public void test06(XPath xpath, Class type) throws XPathExpressionException { + xpath.evaluateExpression("1+1", (Object) null, type); + } + + /* + * Test return type: String. + */ + @Test(dataProvider = "document") + public void test07(XPath xpath, Document doc) throws XPathExpressionException { + String result1 = xpath.evaluateExpression("string(/Customers/Customer[@id=3]/Phone/text())", doc, String.class); + assertTrue(result1.equals("3333333333")); + } + + /* + * Test return type: NodeSet. + */ + @Test(dataProvider = "document") + public void test08(XPath xpath, Document doc) throws XPathExpressionException { + XPathNodes nodes = xpath.evaluateExpression("/Customers/Customer", doc, XPathNodes.class); + assertTrue(nodes.size() == 3); + for (Node n : nodes) { + assertEquals(n.getLocalName(), "Customer"); + } + } + + /* + * Test return type: Node. + */ + @Test(dataProvider = "document") + public void test09(XPath xpath, Document doc) throws XPathExpressionException { + Node n = xpath.evaluateExpression("/Customers/Customer[@id=3]", doc, Node.class); + assertEquals(n.getLocalName(), "Customer"); + } + + /* + * Test return type: Unsupported type. + */ + @Test(dataProvider = "document", expectedExceptions = IllegalArgumentException.class) + public void test10(XPath xpath, Document doc) throws XPathExpressionException { + File n = xpath.evaluateExpression("/Customers/Customer[@id=3]", doc, File.class); + } + + /* + * Test return type: Any::Boolean. + */ + @Test(dataProvider = "document") + public void test11(XPath xpath, Document doc) throws XPathExpressionException { + XPathEvaluationResult result = xpath.evaluateExpression("boolean(/Customers/Customer[@id=3])", doc); + verifyResult(result, true); + } + + /* + * Test return type: Any::Number. + */ + @Test(dataProvider = "document") + public void test12(XPath xpath, Document doc) throws XPathExpressionException { + XPathEvaluationResult result = xpath.evaluateExpression("count(/Customers/Customer)", doc); + verifyResult(result, 3.0); + } + + /* + * Test return type: Any::String. + */ + @Test(dataProvider = "document") + public void test13(XPath xpath, Document doc) throws XPathExpressionException { + XPathEvaluationResult result = xpath.evaluateExpression( + "string(/Customers/Customer[@id=3]/Phone/text())", doc, XPathEvaluationResult.class); + verifyResult(result, "3333333333"); + } + + /* + * Test return type: Any::Nodeset. + */ + @Test(dataProvider = "document") + public void test14(XPath xpath, Document doc) throws XPathExpressionException { + XPathEvaluationResult result = xpath.evaluateExpression("/Customers/Customer", doc); + verifyResult(result, "Customer"); + } + + /* + * Test return type: Any::Node. + */ + @Test(dataProvider = "document") + public void test15(XPath xpath, Document doc) throws XPathExpressionException { + XPathEvaluationResult result = xpath.evaluateExpression("/Customers/Customer[@id=3]", doc); + verifyResult(result, "Customer"); + } +} --- /dev/null Wed Jan 21 21:16:40 2015 +++ new/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathExpAnyTypeTest.java Wed Jan 21 21:16:40 2015 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.xml.xpath; + +import java.io.File; +import javax.xml.xpath.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import org.testng.annotations.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +/* + * @bug 8054196 + * @summary Test for the project XPath: support any type. This test covers the new + * evaluateExpression methods of XPathExpression. + */ +public class XPathExpAnyTypeTest extends XPathTestBase { + + /* + * Check that NPE is thrown when the class type is null. + */ + @Test(dataProvider = "xpath", expectedExceptions = NullPointerException.class) + public void test02(XPath xpath) throws XPathExpressionException { + XPathExpression exp = xpath.compile("1+1"); + double result = exp.evaluateExpression((Object)null, null); + } + + /* + * Parameter item can be null when the expression does not depends on the + * context. + */ + @Test(dataProvider = "xpath") + public void test03(XPath xpath) throws XPathExpressionException { + XPathExpression exp = xpath.compile("1+1"); + int result = exp.evaluateExpression((Object)null, Integer.class); + assertTrue(result == 2); + } + + /* + * Test return type: boolean. + */ + @Test(dataProvider = "document") + public void test04(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("boolean(/Customers/Customer[@id=3])"); + boolean result1 = exp.evaluateExpression(doc, Boolean.class); + assertTrue(result1); + } + + /* + * Test return type: numeric. + */ + @Test(dataProvider = "document") + public void test05(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("count(/Customers/Customer)"); + double result1 = exp.evaluateExpression(doc, Double.class); + assertTrue(result1 == 3.0); + + int result2 = exp.evaluateExpression(doc, Integer.class); + assertTrue(result2 == 3); + } + + /* + * Test return type: String. + */ + @Test(dataProvider = "document") + public void test06(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("string(/Customers/Customer[@id=3]/Phone/text())"); + String result1 = exp.evaluateExpression(doc, String.class); + assertTrue(result1.equals("3333333333")); + } + + /* + * Test return type: NodeSet. + */ + @Test(dataProvider = "document") + public void test07(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("/Customers/Customer"); + XPathNodes nodes = exp.evaluateExpression(doc, XPathNodes.class); + assertTrue(nodes.size() == 3); + for (Node n : nodes) { + assertEquals(n.getLocalName(), "Customer"); + } + } + + /* + * Test return type: Node. + */ + @Test(dataProvider = "document") + public void test08(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("/Customers/Customer[@id=3]"); + Node n = exp.evaluateExpression(doc, Node.class); + assertEquals(n.getLocalName(), "Customer"); + } + + /* + * Test return type: Unsupported type. + */ + @Test(dataProvider = "document", expectedExceptions = IllegalArgumentException.class) + public void test09(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("/Customers/Customer[@id=3]"); + File n = exp.evaluateExpression(doc, File.class); + } + + /* + * Test return type: Any::Boolean. + */ + @Test(dataProvider = "document") + public void test10(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("boolean(/Customers/Customer[@id=3])"); + XPathEvaluationResult result = exp.evaluateExpression(doc); + verifyResult(result, true); + } + + /* + * Test return type: Any::Number. + */ + @Test(dataProvider = "document") + public void test11(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("count(/Customers/Customer)"); + XPathEvaluationResult result = exp.evaluateExpression(doc); + verifyResult(result, 3.0); + } + + /* + * Test return type: Any::String. + */ + @Test(dataProvider = "document") + public void test12(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("string(/Customers/Customer[@id=3]/Phone/text())"); + XPathEvaluationResult result = exp.evaluateExpression(doc, XPathEvaluationResult.class); + verifyResult(result, "3333333333"); + } + + /* + * Test return type: Any::Nodeset. + */ + @Test(dataProvider = "document") + public void test13(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("/Customers/Customer"); + XPathEvaluationResult result = exp.evaluateExpression(doc); + verifyResult(result, "Customer"); + } + + /* + * Test return type: Any::Node. + */ + @Test(dataProvider = "document") + public void test14(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("/Customers/Customer[@id=3]"); + XPathEvaluationResult result = exp.evaluateExpression(doc); + verifyResult(result, "Customer"); + } + +} --- /dev/null Wed Jan 21 21:16:41 2015 +++ new/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathTestBase.java Wed Jan 21 21:16:41 2015 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javax.xml.xpath; + +import java.io.ByteArrayInputStream; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import javax.xml.parsers.DocumentBuilderFactory; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; +import org.testng.annotations.DataProvider; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +/* + * Base class for XPath test + */ +class XPathTestBase { + + static final String rawXML + = "" + + "" + + " " + + " name1" + + " 1111111111" + + " 123@xyz.com" + + "

    " + + " 1111 111st ave" + + " The City" + + " The State" + + "
    " + + " " + + " " + + " name1" + + " 2222222222" + + " 123@xyz.com" + + "
    " + + " 2222 222nd ave" + + " The City" + + " The State" + + "
    " + + "
    " + + " " + + " name1" + + " 3333333333" + + " 123@xyz.com" + + "
    " + + " 3333 333rd ave" + + " The City" + + " The State" + + "
    " + + "
    " + + ""; + + void verifyResult(XPathEvaluationResult result, Object expected) { + switch (result.type()) { + case BOOLEAN: + assertTrue(((Boolean) result.value()).equals(expected)); + return; + case NUMBER: + assertTrue(((Double) result.value()).equals(expected)); + return; + case STRING: + assertTrue(((String) result.value()).equals(expected)); + return; + case NODESET: + XPathNodes nodes = (XPathNodes) result.value(); + for (Node n : nodes) { + assertEquals(n.getLocalName(), expected); + } + return; + case NODE: + assertTrue(((Node) result.value()).getLocalName().equals(expected)); + return; + } + assertFalse(true, "Unsupported type"); + } + + /* + * DataProvider: XPath object + */ + @DataProvider(name = "xpath") + Object[][] getXPath() { + return new Object[][]{{XPathFactory.newInstance().newXPath()}}; + } + + /* + * DataProvider: Numeric types not supported + */ + @DataProvider(name = "invalidNumericTypes") + Object[][] getInvalidNumericTypes() { + XPath xpath = XPathFactory.newInstance().newXPath(); + return new Object[][]{{xpath, AtomicInteger.class}, + {xpath, AtomicInteger.class}, + {xpath, AtomicLong.class}, + {xpath, BigDecimal.class}, + {xpath, BigInteger.class}, + {xpath, Byte.class}, + {xpath, Float.class}, + {xpath, Short.class} + }; + } + + /* + * DataProvider: XPath and Document objects + */ + @DataProvider(name = "document") + Object[][] getDocument() throws Exception { + DocumentBuilderFactory dBF = DocumentBuilderFactory.newInstance(); + dBF.setValidating(false); + dBF.setNamespaceAware(true); + Document doc = dBF.newDocumentBuilder().parse( + new ByteArrayInputStream(rawXML.getBytes("UTF-8"))); + + return new Object[][]{{XPathFactory.newInstance().newXPath(), doc}}; + } +}
  • * If the expression contains a variable reference, its value will be found through the {@link XPathVariableResolver}. * An {@link XPathExpressionException} is raised if the variable resolver is undefined or - * the resolver returns null for the variable. + * the resolver returns {@code null} for the variable. * The value of a variable must be immutable through the course of any single evaluation.

    *
    * If the expression contains a function reference, the function will be found through the {@link XPathFunctionResolver}. * An {@link XPathExpressionException} is raised if the function resolver is undefined or - * the function resolver returns null for the function.

    + * the function resolver returns {@code null} for the function.

    *