Anton Grindplak
Anton Grindplak

Reputation: 3

java xpath list concatenation

I am using java XPathFactory to get values from a simple xml file:

<Obama>
    <coolnessId>0</coolnessId>
    <cars>0</cars>
    <cars>1</cars>
    <cars>2</cars>
</Obama>

With the xpression //Obama/coolnessId | //Obama/cars the result is:

0
0
1
2

From this result, I cannot distinguish between what is the coolnessId and what is the car id. I would need something like:

CoolnessId: 0
CarId: 0
CarId: 1
CarId: 2

With concat('c_id: ', //Obama/coolnessId,' car_id: ',//Obama/cars) I am close to the solution, but concat cannot be used for a list of values. Unfortunately, I cannot use string-join, because it seems not be known in my xpath library. And I cannot manipulate the given xml.

What other tricks can I use to get a list of values with something like an alias?

Upvotes: 0

Views: 424

Answers (2)

Michael Kay
Michael Kay

Reputation: 163342

Assuming you ask for the result of the evaluation as a NODELIST, your XPath expression actually returns a sequence of four element nodes, not a sequence of four strings as you suggest. If your input uses the DOM tree model, these will be returned in the form of a DOM NodeList. You can process the Node objects in this NodeList to get the names of the nodes as well as their string values.

If you switch to an XPath 3.1 engine such as Saxon, you can get the result directly as a single string using the XPath expression:

string-join((//Obama/coolnessId | //Obama/cars) ! (name() || ': ' || string()), '\n')

To invoke XPath expressions in Saxon you can use either the JAXP API (javax.xml.xpath) or Saxon's s9api interface: I would recommend s9api because it understands the richer type system of XPath 2.0 and beyond.

Upvotes: 1

teppic
teppic

Reputation: 7286

If you select the elements rather than their text content you'll have some context:

public static void main(String[] args) throws Exception {

    String xml =
        "<Obama>" +
        "    <coolnessId>0</coolnessId>" +
        "    <cars>0</cars>" +
        "    <cars>1</cars>" +
        "    <cars>2</cars>" +
        "</Obama>";

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setNamespaceAware(true);

    Document doc = factory.newDocumentBuilder().parse(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)));
    XPath xpath = XPathFactory.newInstance().newXPath();

    XPathExpression expr = xpath.compile("//Obama/cars | //Obama/coolnessId");
    NodeList result = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
    for (int i = 0; i < result.getLength(); i++) {
        Element item = (Element) result.item(i);
        System.out.println(item.getTagName() + ": " + item.getTextContent());
    }
}

Upvotes: 2

Related Questions