46

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
3
  • 1
    In XPath2.0 there is string-join, looks more appropriate there.. However, what is with XSLT? I would use that here. Commented Feb 24, 2014 at 19:43
  • Added edit for string-join function. Also added XSLT to tags and requested solution. Commented Feb 24, 2014 at 20:00
  • 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. Commented Feb 24, 2014 at 20:16

6 Answers 6

46

Try this expression...

string-join(//element3/(concat(element4/text(), '.', element5/text())), "&#10;")
Sign up to request clarification or add additional context in comments.

4 Comments

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.
+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, '|')
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), ".").
Garret's simplified form did great things for me. I wanted to export a tilde-delimited set of attributes from a filtered set of elements, and //base/element[@filterattr!='Fixed']/string-join((@attr1,@attr2,@attr3),'~') worked great in XMLSpy. I copied the results to a text file and then opened them in Excel with the text import.
23

I used concat method and works well.

concat(//SomeElement/text(),'_',//OtherElement/text())

Comments

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>

1 Comment

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 XSLT
2

Using XQuery:

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

Comments

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>    

Comments

-1
<xsl:template match="element3">
        <xsl:value-of select="element4,element5" separator="."/>
    </xsl:template>

1 Comment

Just posting code is not a good answer. Please read this how-to-answer if you haven't read it.

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.