3

I want to pass a parameter into an XPath expression.

(//a/b/c[x=?],myParamForXAttribute)

Can I do this with XPath 1.0 ? (I tried string-join but it is not there in XPath 1.0)

Then how can I do this ?

My XML looks like

<a>
 <b>
  <c>
   <x>val1</x>
   <y>abc</y>
  </c>
  <c>
   <x>val2</x>
   <y>abcd</y>
  </c>
</b>
</a>

I want to get <y> element value where x element value is val1

I tried //a/b/c[x='val1']/y but it did not work.

kjhughes
  • 106,133
  • 27
  • 181
  • 240
user2694734
  • 401
  • 2
  • 7
  • 14
  • If you're using the Axiom library, you should tag your question Java, and expect an answer that includes some Java in it. – Charles Duffy May 20 '15 at 15:14
  • 1
    You started with one problem (how to use variables in XPath expressions). I've [answered that below](http://stackoverflow.com/a/30353346/290085). Now, you've added another problem (your new XPath, which doesn't use a variable and tries to select a *completely different* element, isn't working). Add a new question for your new problem, and include sufficient detail and context to reproduce your problem -- you've not done so here. – kjhughes May 20 '15 at 15:17
  • BTW, why bother with `//a/b/c`? If you're going to go to all the performance hit of a recursive search (which is silly, but that's what you do when you use `//` instead of `/` to start), might as well use `//x[.='val1']/../y`, and not need to care about `a` or `b`. – Charles Duffy May 20 '15 at 15:53

2 Answers2

6

Given that you're using the Axiom XPath library, which in turn uses Jaxen, you'll need to follow the following three steps to do this in a thoroughly robust manner:

  • Create a SimpleVariableContext, and call context.setVariableValue("val", "value1") to assign a value to that variable.
  • On your BaseXPath object, call .setVariableContext() to pass in the context you assigned.
  • Inside your expression, use /a/b/c[x=$val]/y to refer to that value.

Consider the following:

package com.example;

import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.common.AxiomText;
import org.apache.axiom.om.util.AXIOMUtil;
import org.apache.axiom.om.xpath.DocumentNavigator;
import org.jaxen.*;

import javax.xml.stream.XMLStreamException;

public class Main {

    public static void main(String[] args) throws XMLStreamException, JaxenException {
        String xmlPayload="<parent><a><b><c><x>val1</x><y>abc</y></c>" +
                                        "<c><x>val2</x><y>abcd</y></c>" +
                          "</b></a></parent>";
        OMElement xmlOMOBject = AXIOMUtil.stringToOM(xmlPayload);

        SimpleVariableContext svc = new SimpleVariableContext();
        svc.setVariableValue("val", "val2");

        String xpartString = "//c[x=$val]/y/text()";
        BaseXPath contextpath = new BaseXPath(xpartString, new DocumentNavigator());
        contextpath.setVariableContext(svc);
        AxiomText selectedNode = (AxiomText) contextpath.selectSingleNode(xmlOMOBject);
        System.out.println(selectedNode.getText());
    }
}

...which emits as output:

abcd
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Can you please post code snippet as an example for above answer. `String xmlPayload="name1name2"; OMElement xmlOMOBject= AXIOMUtil.stringToOM(xmlPayload);SimpleVariableContext svc=new SimpleVariableContext(); svc.setVariableValue("part1",key1); svc.setVariableValue("part2",key2); String xpartString="$part1$part2"; DocumentNavigator nav=new DocumentNavigator(); BaseXPath contextpath=new BaseXPath(xmlPayload,nav); contextpath.setVariableContext(svc); contextpath.selectSingleNode(xmlOMOBject);` – user2694734 May 28 '15 at 14:17
  • @user2694734, it'd be easier to start with a fully ready-to-run reproducer. Maybe put it in a gist (https://gist.github.com/), to allow that to be forked by anyone who wants to propose changes? – Charles Duffy May 28 '15 at 16:59
  • @user2694734, ...while several years later, I *have* now added a working example. – Charles Duffy Mar 21 '18 at 13:03
5

It depends on the language in which you're using XPath.

In XSLT:

 "//a/b/c[x=$myParamForXAttribute]"

Note that, unlike the approach above, the three below are open to XPath injection attacks and should never be used with uncontrolled or untrusted inputs; to avoid this, use a mechanism provided by your language or library to pass in variables out-of-band. [Credit: Charles Duffy]

In C#:

String.Format("//a/b/c[x={0}]", myParamForXAttribute);

In Java:

String.format("//a/b/c[x=%s]", myParamForXAttribute);

In Python:

 "//a/b/c[x={}]".format(myParamForXAttribute)
kjhughes
  • 106,133
  • 27
  • 181
  • 240
  • I edited my question with my xml. Please have a look. x is a child element of c – user2694734 May 20 '15 at 15:01
  • my scenario is pure Xpath. the evaluated xpath is sent to the java programme. So I want that solution in pure xpath expression – user2694734 May 20 '15 at 15:07
  • 1
    There is no pure XPath technique for variable evaluation; it depends on the hosting language as I've shown. – kjhughes May 20 '15 at 15:11
  • my case is like XSLT. The xpath is evaluated by AxiomXpath – user2694734 May 20 '15 at 15:12
  • 1
    I disagree that string formatting for generating XPath is a good practice; in all the languages given here -- C#, Java, etc -- native means for passing variables to XPath libraries are available, and should be used in preference. – Charles Duffy May 20 '15 at 15:19
  • 1
    Yes, if your XPath library offers facilities to interpret variables in a manner similar to XSLT, by all means, use it. Since OP didn't originally state his language/library, I answered in general. Many beginners expect there to be a pure XPath solution for embedding variables in XPath, and there is not; as such there's value in leaving this general answer in place. – kjhughes May 20 '15 at 15:26
  • I'd be able to agree with you if this contained an explicit disclaimer ("Note that, unlike the approach above, the three below are open to injection attacks and should never be used with uncontrolled or untrusted inputs; to avoid this, use a mechanism provided by your language or library to pass in variables out-of-band"). – Charles Duffy May 20 '15 at 15:28
  • Certainly! Updated. Thank you for your valid and helpful addition. – kjhughes May 20 '15 at 15:33