1

I want to join the values of all the nodes that match an expression and have them separated by a comma. For example, the following xml should return "num1,num2,num3"

<products>
  <product>
    <id>1</id>
    <other>y</other>
    <notarget>x</notarget>
    <target>num1</target>
    <target>num2</target>
    <target>num3</target>
  </product>
</products>

The XPath /*[name()='products']/*[name()='product']/*[name()='target'] should get the elements, but I just don't understand how to join them.

kjhughes
  • 106,133
  • 27
  • 181
  • 240
user1136342
  • 4,731
  • 10
  • 30
  • 40
  • If you're using xpath 2.0, you could use `string-join()` - for your input `string-join(//target,',')` results in `num1,num2,num3` – matthias_h Jan 19 '15 at 00:31
  • @matthias_h I'm not using xpath 2.0 – user1136342 Jan 19 '15 at 00:44
  • I may be wrong, but I think in xpath 1.0 it's only possible if you know the number of elements and then use `concat()`, see e.g. http://stackoverflow.com/questions/17373041/return-text-from-several-elements-in-one-string-using-xpath – matthias_h Jan 19 '15 at 00:51
  • 1
    possible duplicate of [XPath to return string concatenation of qualifying child node values](http://stackoverflow.com/questions/1403971/xpath-to-return-string-concatenation-of-qualifying-child-node-values) or [Return text from several elements in one string using xPath](http://stackoverflow.com/q/17373041/290085) – kjhughes Jan 19 '15 at 01:45
  • @kjhughes based on those answers, would the path be /*[name()='products']/*[name()='product']/*[name()='target']/text() and then concatenate on my own? I'm asking because it doesn't seem to be providing all the nodes – user1136342 Jan 19 '15 at 02:19
  • First, use `/products/product/target/text()` rather than that convoluted predicate pattern you're using. Second, as the other answers indicate, if you have a fixed number of `target` elements, you can select each and `concat()` them together; otherwise, yes, select them and then join them together outside of XPath if you can't use XPath 2.0. – kjhughes Jan 19 '15 at 02:45

5 Answers5

2

It can't be done in pure XPath 1.0 without some help from the host language. In fact it's difficult even with help from the host language, because XPath 1.0 has no concept of a "sequence of strings".

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
1
<xsl:value-of select="[set of nodes]" separator="."/>

I wanted to do the same thing and solved it with the separator attribute using XSLT 2.0

0
<xsl:for-each select="/products/product/target">
  <xsl:if test="position() != 1">,</xsl:if><xsl:value-of select="text()"/>
</xsl:for-each>

You can place it inside variable if you want to reuse it later:

<xsl:variable name="concat">
  <xsl:for-each select="products/product/target">
    <xsl:if test="position() != 1">,</xsl:if><xsl:value-of select="text()"/>
  </xsl:for-each>
</xsl:variable>

<xsl:value-of select="$concat"/>
Rudolf Yurgenson
  • 603
  • 6
  • 12
0

With saxon-lint :

saxon-lint --output-separator , --xpath '//target/text()' file

OUTPUT

num1,num2,num3
Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223
0

Use concat with your delimiter (per https://stackoverflow.com/a/25766054/148889)

concat(//SomeElement/text(),'_',//OtherElement/text())
roblogic
  • 1,266
  • 2
  • 13
  • 23