/* |
|
* 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<T> implements XPathEvaluationResult<T> { |
|
XObject resultObject; |
|
int resultType; |
|
Class<T> 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<T> 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 <T> The expected class type. |
|
* @param resultObject internal XPath result object |
|
* @param type the class type |
|
* @return The value of the result, null in case of unexpected type. |
|
* @throws TransformerException if there is an error reading the XPath |
|
* result. |
|
*/ |
|
static <T> T getValue(XObject resultObject, Class<T> type) throws TransformerException { |
|
Objects.requireNonNull(type); |
|
if (type.isAssignableFrom(XPathEvaluationResult.class)) { |
|
return type.cast(new XPathResultImpl<T>(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(), |
|
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 the specified class type to the internal result type |
|
* |
|
* @param <T> The expected class type. |
|
* @param type the class type |
|
* @return the internal XObject type. |
|
*/ |
|
static <T> int classToInternalType(Class<T> 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; |
|
} |
|
} |