43

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
krishna2642
  • 579
  • 1
  • 4
  • 10
  • 1
    In XPath2.0 there is `string-join`, looks more appropriate there.. However, what is with XSLT? I would use that here. – hek2mgl Feb 24 '14 at 19:43
  • Added edit for string-join function. Also added XSLT to tags and requested solution. – krishna2642 Feb 24 '14 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. – nwellnhof Feb 24 '14 at 20:16

6 Answers6

44

Try this expression...

string-join(//element3/(concat(element4/text(), '.', element5/text())), "&#10;")
Tim C
  • 70,053
  • 14
  • 74
  • 93
  • 7
    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, "."), " ")` is another formulation, which IMHO is more readable. – adamretter Feb 24 '14 at 23:19
  • +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, '|')` – Timmah May 05 '22 at 00:25
  • 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 Wilson Jun 18 '23 at 17:38
23

I used concat method and works well.

concat(//SomeElement/text(),'_',//OtherElement/text())
prespic
  • 1,635
  • 1
  • 17
  • 20
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>
hek2mgl
  • 152,036
  • 28
  • 249
  • 266
  • 5
    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 – hek2mgl Oct 25 '16 at 13:49
2

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

bosari
  • 1,922
  • 1
  • 19
  • 38
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>    
diagrams
  • 21
  • 3
-1
<xsl:template match="element3">
        <xsl:value-of select="element4,element5" separator="."/>
    </xsl:template>
  • 2
    Just posting code is not a good answer. Please read this [how-to-answer](http://stackoverflow.com/help/how-to-answer) if you haven't read it. – thewaywewere May 04 '17 at 08:28