3

How do I return a comma-separated list of the ids, please?

<nodes>
 <node>
   <id>1</id>
   <name>idbread</name>
 </node>
 <node>
   <id>2</id>
   <name>idbutter</name>
 </node>
</nodes> 

expected output

1,2

I attempted to use XPath, but concat returns only the first value.

xpath node.xml "//nodes/node/id/text()" 2>/dev/null

returns

12

Léa Gris
  • 17,497
  • 4
  • 32
  • 41
mr i.o
  • 952
  • 2
  • 10
  • 20
  • Where does that `xpath` binary/script come from? The only one I [found](https://manpages.ubuntu.com/manpages/xenial/en/man1/xpath.1p.html) does not have the syntax you're using. – fredrik Dec 07 '19 at 21:14
  • @fredrik: OP is probably doing something like this `xmllint --xpath "//nodes/node/id/text()" node.xml` but on my system it returns `12`. Version: `xmllint: using libxml version 20904` – Arkadiusz Drabczyk Dec 07 '19 at 21:16
  • @ArkadiuszDrabczyk how do you come to that conclusion when he states in the question which command he is running? – fredrik Dec 07 '19 at 21:20
  • @fredrik: it's just my guess, he might provide only a part of the real command he's using. In any case, he has to make this question more clear to get an answer. – Arkadiusz Drabczyk Dec 07 '19 at 21:21
  • Maybe OP should tell us which command he's using.... – Jack Fleeting Dec 07 '19 at 21:23
  • 1
    @mri.o you could use `echo $(sed -n 's:\(.*\):\1, :pg' file)` – builder-7000 Dec 07 '19 at 21:24
  • 3
    @sergio: [Don't Parse XML/HTML With Regex.](https://stackoverflow.com/a/1732454/3776858) I suggest to use an XML/HTML parser (xmlstarlet, xmllint ...). – Cyrus Dec 07 '19 at 21:36
  • Hi @fredrik, I am using a Mac, xpath is in it by default, I didn't have to install anything extra to run: xpath node.xml "//nodes/node/id/text()" 2>/dev/null – mr i.o Dec 07 '19 at 23:46
  • @sergio, I am trying as much as possible not to use any other external library to do this, I wil accept your suggestion if you post it as an answer. It works great. – mr i.o Dec 07 '19 at 23:48

2 Answers2

4

You can use for this:

xmlstarlet sel -t -v "/nodes/node[1]/id" -m "/nodes/node[position()>1]" -v "concat(',',id)" input.xml

This outputs the value of the first node/id node and then outputs the following node/ids separated by a comma. The output is as desired.

  • The sel option chooses the Select/Query mode of xmlstarlet
  • The -t indicates the start of an "XSLT template"
  • The first -v option outputs the value of the XPath expression
  • The -m option creates a for-each over the XPath expression
  • The second -v option outputs the value of the XPath expression relative to the context value of the for-each
zx485
  • 28,498
  • 28
  • 50
  • 59
1

A simpler option, using xidel which supports xpath 3.0:

xidel -s node.xml -e "string-join(//nodes/node/id/text(),',')"
Jack Fleeting
  • 24,385
  • 6
  • 23
  • 45