16

I have an XPath expression that searches for a static value. In this example, "test" is that value:

XPathExpression expr = xpath.compile("//doc[contains(., 'test')]/*/text()");

How can I pass a variable instead of a fixed string? I use Java with Eclipse. Is there a way to use the value of a Java String to declare an XPath variable?

4 Answers 4

23

You can define a variable resolver and have the evaluation of the expression resolve variables such as $myvar, for example:

XPathExpression expr = xpath.compile("//doc[contains(., $myVar)]/*/text()");

There's a fairly good explanation here. I haven't actually done this before myself, so I might have a go and provide a more complete example.


Update:

Given this a go, works a treat. For an example of a very simple implementation, you could define a class that returns the value for a given variable from a map, like this:

class MapVariableResolver implements XPathVariableResolver {
  // local store of variable name -> variable value mappings
  Map<String, String> variableMappings = new HashMap<String, String>();

  // a way of setting new variable mappings 
  public void setVariable(String key, String value)  {
    variableMappings.put(key, value);
  }

  // override this method in XPathVariableResolver to 
  // be used during evaluation of the XPath expression      
  @Override
  public Object resolveVariable(QName varName) {
    // if using namespaces, there's more to do here
    String key = varName.getLocalPart();
    return variableMappings.get(key);
  }
}

Now, declare and initialise an instance of this resolver in the program, for example

MapVariableResolver vr = new MapVariableResolver() ;
vr.setVariable("myVar", "text");
...
XPath xpath = factory.newXPath();
xpath.setXPathVariableResolver(vr);

Then, during evaluation of the XPath expression XPathExpression expr = xpath.compile("//doc[contains(., $myVar)]/*/text()");, the variable $myVar will be replaced with the string text.

Nice question, I learnt something useful myself!

Sign up to request clarification or add additional context in comments.

1 Comment

This is a very old (but good) answer; to expand on this, it is also possible to define the "global" XPath variable resolver by setting on the XPath FACTORY itself! This way, all XPath objects created by the factory will inherit the same variable resolver...
0

You don't need to evaluate Java (or whatever else PL variables in XPath). In C# (don't know Java well) I'll use:

    string XPathExpression = 
"//doc[contains(., " + myVar.ToString() + ")]/*/text()";

    XmlNodelist result = xmlDoc.SelectNodes(XPathExpression);

1 Comment

I find simple inlining of variables a bit cumbersome, compared to the possibility of using true variables. Besides, you'll have to think of syntactical integrity (e.g. what if myVar contains quotes? etc)
0

Apart from this answer here, that explains well how to do it with the standard Java API, you could also use a third-party library like jOOX that can handle variables in a simple way:

List<String> list = $(doc).xpath("//doc[contains(., $1)]/*", "test").texts();

Comments

0

I use something similar to @brabster:

// expression: "/message/PINConfiguration/pinValue[../keyReference=$keyReference]";

Optional<Node> getNode(String xpathExpression, Map<String, String> variablesMap)
        throws XPathExpressionException {
    XPath xpath = XPathFactory.newInstance().newXPath();
    xpath.setXPathVariableResolver(qname -> variablesMap.get(qname.getLocalPart()));
    return Optional.ofNullable((Node) xpath.evaluate(xpathExpression, document, 
            XPathConstants.NODE));
}

Optional<Node> getNode(String xpathExpression) throws XPathExpressionException {
    return getNode(xpathExpression, Collections.emptyMap());
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.