15

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?

Pops
  • 30,199
  • 37
  • 136
  • 151
Lollo
  • 151
  • 1
  • 3

4 Answers4

22

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!

brabster
  • 42,504
  • 27
  • 146
  • 186
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);
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • 1
    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) – Lukas Eder Jan 20 '12 at 14:14
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());
}
Ron McLeod
  • 643
  • 7
  • 12
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();
Community
  • 1
  • 1
Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509