Concatenate multiple node values in xpath
Asked Answered
I

6

44

I have a XML that looks like this

<element1>
    <element2>
        <element3>    
            <element4>Hello</element4>
            <element5>World</element5>
        </element3>
        <element3>    
            <element4>Hello2</element4>
            <element5>World2</element5>
        </element3>
        <element3>    
            <element4>Hello3</element4>
            <element5>World3</element5>
        </element3>
    </element2>
</element1>

I am trying to use Xpath to get a result like this:

Hello.World
Hello2.World2
Hello3.World3

I used concat function below but I did not get correct result.

Concat function:

concat(/element1/element2/element3/element4/text(),".", /element1/element2/element3/element5/text())

Result I got:

Hello.World

How can I get the correct result? I am using XPath with Camel Spring DSL.

Edit:

Solutions in XQuery, XSLT and SPel are also appreciated.

Edit

I tried string-join and it did not work:

string-join function:

string-join((/element1/element2/element3/element4/text(), /element1/element2/element3/element5/text()),".")

Result I got:

Hello.Hello2.Hello3.World.World2.World3
Instigation answered 24/2, 2014 at 19:22 Comment(3)
In XPath2.0 there is string-join, looks more appropriate there.. However, what is with XSLT? I would use that here.Metathesize
Added edit for string-join function. Also added XSLT to tags and requested solution.Instigation
To understand why you get this result: A node-set is converted to a string by returning the string-value of the node in the node-set that is first in document order.Celtuce
B
44

Try this expression...

string-join(//element3/(concat(element4/text(), '.', element5/text())), "&#10;")
Brunner answered 24/2, 2014 at 20:20 Comment(3)
If you want a Sequence of results, the more succinct way is to use //element3/string-join(element4 | element5, "."), and if you must have a single string as a result then, string-join(//element3/string-join(element4 | element5, "."), "&#xa;") is another formulation, which IMHO is more readable.Underworld
+1 for the //el/string-join(el2 | el3, 'separator'). I used this to scrape images and generate a CSV: //img/string-join(@src | @alt | @width | @height, '|')Whiffler
Be careful with //element3/string-join(element4 | element5, "."). Regardless of the order you give element4 and element5, the union operator | will maintain document order! That means //element3/string-join(element5 | element4, ".") will produce the same result as //element3/string-join(element4 | element5, ".") for the same input document. I usually want to control the order, so I prefer to simply list the items using the form //element3/string-join((element4, element5), ".").Packaging
C
23

I used concat method and works well.

concat(//SomeElement/text(),'_',//OtherElement/text())
Cosmogony answered 10/9, 2014 at 12:57 Comment(0)
M
16

Here comes a solution with XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="//element3">
    <xsl:value-of select="element4/text()" />.<xsl:value-of select="element5/text()" />
</xsl:template>
</xsl:stylesheet>
Metathesize answered 24/2, 2014 at 20:23 Comment(1)
What's the point of down-voting this? Note that string-join() is available only for XPath2.0. That's why I suggested to use XSLTMetathesize
B
2

Using XQuery:

for $d in $doc/element2/element3 return fn:string-join(fn:data($d/element()), ".").
$doc stores the Xml.

Baggett answered 25/4, 2017 at 15:18 Comment(0)
L
1

If you need to join xpath-selected text nodes but can not use string-join (when you are stuck with XSL 1.0) this might help:

<xsl:variable name="x">
    <xsl:apply-templates select="..." mode="string-join-mode"/>
</xsl:variable>
joined and normalized: <xsl:value-of select="normalize-space($x)"/>

<xsl:template match="*" mode="string-join-mode">
    <xsl:apply-templates mode="string-join-mode"/>
</xsl:template>    

<xsl:template match="text()" mode="string-join-mode">
    <xsl:value-of select="."/>
</xsl:template>    
Liturgy answered 4/7, 2020 at 14:21 Comment(0)
U
-1
<xsl:template match="element3">
        <xsl:value-of select="element4,element5" separator="."/>
    </xsl:template>
Urgent answered 4/5, 2017 at 8:2 Comment(1)
Just posting code is not a good answer. Please read this how-to-answer if you haven't read it.Damiondamita

© 2022 - 2024 — McMap. All rights reserved.