Java : Xpath variable in xpath evaluate

Viewed 220

I wouldike to get nodes of nodes in my xml file :

public Map<String, String> getAllClassesDetails() throws XPathExpressionException {

        Map<String, String> data = new HashMap<>();
        XPath xpath = XPathFactory.newInstance().newXPath();
        NodeList nodesClasses = (NodeList) xpath.evaluate("/Plan/featureMember/node()", document, XPathConstants.NODESET);

        for (int i = 0; i < nodesClasses.getLength(); i++) {
           // System.out.println(nodesClasses.item(i).getNodeName());
            String rawXPath = String.format("/Plan/featureMember/%s/node()", nodesClasses.item(i).getNodeName());
            NodeList nodesDetails = (NodeList) xpath.evaluate(rawXPath, document, XPathConstants.NODESET);
            for (int j = 0; j < nodesDetails.item(i).getChildNodes().getLength(); j++) {
                data.put(nodesClasses.item(i).getNodeName(), nodesDetails.item(j).getNodeName());
            }
        }

        return data;

The problem I have an error in this line : NodeList nodesDetails = (NodeList) xpath.evaluate(rawXPath, document, XPathConstants.NODESET);

Error :

javax.xml.xpath.XPathExpressionException: javax.xml.transform.TransformerException: A location step was expected following the '/' or '//' token

How can I specify variable in xpath.evaluate ?

EDIT : Here my xml file :

<?xml version="1.0" encoding="UTF-8"?>
<Plan>
    <featureMember>
        <TestA>
            <Objet></Objet>
            <nature>03</nature>
            <mastery>5</mastery>
        </TestA>
        <TestB>
            <Objet></Objet>
            <nature>03</nature>
            <mastery>5</mastery>
        </TestB>
        <TestC>
            <Objet></Objet>
            <nature>03</nature>
            <mastery>5</mastery>    
        </TestC>
    </featureMember>
</Plan> 
1 Answers

I can't see exactly why you're hitting the error, but the approach you're using is inefficient. It's also potentially insecure - you need to be aware of the possibility of injection attacks.

Rather than constructing and compiling a new XPath expression for every entry in nodeClasses, use a generic expression with a variable:

"/Plan/featureMember/*[local-name=$className]/node()"

using a variable resolver to bind the variable to a value:

xpath.setXPathVariableResolver(varName -> {
   if (varName.getLocalPart().equals("className")) {
      return nodesClasses.item(i).getNodeName();
   } else {
      return "";
   }
}
Related