com.crabshue.commons.xpath.XPathEvaluator Maven / Gradle / Ivy
package com.crabshue.commons.xpath;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import com.crabshue.commons.exceptions.ApplicationException;
import com.crabshue.commons.xml.XmlDocumentBuilder;
import com.crabshue.commons.xml.inputsource.InputSourceBuilder;
import com.crabshue.commons.xpath.exceptions.XPathErrorContext;
import com.crabshue.commons.xpath.exceptions.XPathErrorType;
import com.crabshue.commons.xpath.saxon.NodeInfoUtils;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
/**
* XPath expression evaluator.
*/
@Slf4j
public class XPathEvaluator {
private InputSource inputSource;
private Map variables = new HashMap<>();
private String xpathExpression;
private QName returnType = XPathConstants.STRING;
private boolean ignoreValidation = false;
/**
* Prepare an XPath evaluator with no context ({@code }.
*
* @return instance.
*/
public static XPathEvaluator noContext() {
return XPathEvaluator.of(" ");
}
/**
* Prepare an XPath evaluator with an {@link InputSource}.
*
* @param inputSource the input source.
* @return instance.
*/
public static XPathEvaluator of(@NonNull final InputSource inputSource) {
final XPathEvaluator ret = new XPathEvaluator();
ret.inputSource = inputSource;
return ret;
}
/**
* Prepare an XPath evaluator with an XML document as {@link String}.
*
* @param xmlContent the XML document as {@link String}.
* @return instance.
* @see #of(InputSource)
*/
public static XPathEvaluator of(@NonNull final String xmlContent) {
return XPathEvaluator.of(InputSourceBuilder.newInputSource(xmlContent));
}
/**
* Prepare an XPath evaluator with an XML {@link File}.
*
* @param xmlFile the XML file.
* @return instance.
* @see #of(InputSource)
*/
public static XPathEvaluator of(@NonNull final File xmlFile) {
return XPathEvaluator.of(InputSourceBuilder.newInputSource(xmlFile));
}
/**
* Prepare an XPath evaluator with a byte array.
*
* @param xmlByteArray the byte array
* @return instance.
* @see #of(InputSource)
*/
public static XPathEvaluator of(@NonNull final byte[] xmlByteArray) {
return XPathEvaluator.of(InputSourceBuilder.newInputSource(xmlByteArray));
}
/**
* Prepare an XPath evaluator with an XML {@link Node}.
*
* @param xmlNode the XML node.
* @return instance.
* @see #of(InputSource)
*/
public static XPathEvaluator of(@NonNull final Node xmlNode) {
return XPathEvaluator.of(InputSourceBuilder.newInputSource(xmlNode));
}
/**
* Set the XPath expression for XPath evaluation.
*
* @param xpathExpression the XPath expression.
* @return instance.
*/
public XPathEvaluator withXpathExpression(@NonNull final String xpathExpression) {
this.xpathExpression = xpathExpression;
return this;
}
/**
* Add variables for XPath evaluation.
*
* @param variables the variables map.
* @return instance.
*/
public XPathEvaluator withVariables(@NonNull Map variables) {
this.variables.putAll(variables);
return this;
}
/**
* Set the return type for the XPath evaluation.
* The default return type is {@link XPathConstants#STRING}
*
* @param returnType the return type.
* @return instance.
*/
public XPathEvaluator withReturnType(@NonNull final QName returnType) {
this.returnType = returnType;
return this;
}
/**
* Set the flag to ignore validation on the source XML.
* Default value is : {@code false}
*
* @param validationIgnored the flag to ignore validation.
* @return instance.
*/
public XPathEvaluator withValidationIgnored(final boolean validationIgnored) {
this.ignoreValidation = validationIgnored;
return this;
}
/**
* Evaluate the XPath.
*
* @param the return type.
* @return the value.
*/
public T evaluate() {
try {
if (Objects.nonNull(this.inputSource.getByteStream())) {
this.inputSource.getByteStream().reset();
}
} catch (IOException e) {
logger.warn("Could not reset input source stream. Still will try to evaluate XPath", e);
}
final XPath xPath = XPathFactoryUtils.newXPath(this.inputSource, variables);
try {
xPath.compile(this.xpathExpression);
} catch (XPathExpressionException e) {
throw new ApplicationException(XPathErrorType.ERROR_XPATH_EVALUATION, e)
.addContextValue(XPathErrorContext.XPATH, this.xpathExpression);
}
if (ignoreValidation) {
// convert the input source to disable all validations (especially DTD)
final Document document = XmlDocumentBuilder.of(this.inputSource)
.withValidationEnabled(false)
.build();
this.inputSource = InputSourceBuilder.newInputSource(document);
}
try {
return (T) xPath.evaluate(this.xpathExpression, this.inputSource, this.returnType);
} catch (XPathExpressionException e) {
throw new ApplicationException(XPathErrorType.ERROR_XPATH_EVALUATION, e);
}
}
/**
* Evaluate the XPath and return a collection of values.
*
* @return the collection of values.
*/
public Collection evaluateCollection() {
List ret = new ArrayList<>();
this.withReturnType(XPathConstants.NODESET);
List © 2015 - 2025 Weber Informatics LLC | Privacy Policy