I have an XML file containing multiple user entries with some user data like name, email and other data. It seems that this could be done using multiple --value-of (-v) arguments like this:
$ xmlstarlet sel -N n="http://www.w3.org/2005/Atom" -t --nl -v "//n:title" -v "//n:email" ~/tests/test-xml.xml
Some user
Some user #2
Some user #3some.user@example.com
some.user2@example.com
some.user3@example.com
But they're not together, it looks like the tool process all <title> elements first and then all <email> ones. I like to have the following format:
Some user
some.user@example.com
Some user #2
some.user2@example.com
...
Found out that I need the xpath function concat for this. Now I get them at least with comma seperated:
$ xmlstarlet sel -N n="http://www.w3.org/2005/Atom" -t -m "//n:entry" -v "concat(current()//n:title, ',', current()//n:email)" ~/tests/test-xml.xml
Some user,some.user@example.comSome user #2,some.user2@example.comSome user #3,some.user3@example.com
That's exactly what I need, but when I set \n as delimiter instead of ,, it will just print \n instead of doing a line break. The same happens for \\n and \r\n. As a workaround, this could be replaced using sed like this: sed 's/,/\n/g'
However, this doesn't solve the problem that there is no new line between some.user@example.comSome user #2:
$ xmlstarlet sel -N n="http://www.w3.org/2005/Atom" -t -m "//n:entry" -v "concat(current()//n:title, ',', current()//n:email)" ~/tests/test-xml.xml | sed 's/,/\n/g'
Some user
some.user@example.comSome user #2
some.user2@example.comSome user #3
some.user3@example.com
How can I realize this? Would prefer a solution without additional sed command if it makes sense and would be possible.
Workaround
The only workaround I found is to nest it in another concat call to add another char, that identifies the placed where another new line is needed and could be replaced with \n too like this:
$ xmlstarlet sel -N n="http://www.w3.org/2005/Atom" -t -m "//n:entry" -v "concat(concat(current()//n:title, ',', current()//n:email), '|', '')" ~/tests/test-xml.xml | sed -E 's/[,|]+/\n/g'
Some user
some.user@example.com
Some user #2
some.user2@example.com
Some user #3
some.user3@example.com
Altough this works, it seems like a nasty workaround to me. Would like to know if there is a more clean way to do this. I guess it's possible with a deeper experience of xmlstarlet and maybe also xpath.
Test XML document
<?xml version="1.0" encoding="UTF-8"?>
<feed
xmlns="http://www.w3.org/2005/Atom"
xmlns:app="http://www.w3.org/2007/app"
xmlns:snx="http://www.ibm.com/xmlns/prod/sn"
xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">
<opensearch:totalResults
xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">67
</opensearch:totalResults>
<opensearch:startIndex
xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">1
</opensearch:startIndex>
<opensearch:itemsPerPage
xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">100
</opensearch:itemsPerPage>
<entry>
<title>Some user</title>
<contributor>
<email>some.user@example.com</email>
</contributor>
</entry>
<entry>
<title>Some user #2</title>
<contributor>
<email>some.user2@example.com</email>
</contributor>
</entry>
<entry>
<title>Some user #3</title>
<contributor>
<email>some.user3@example.com</email>
</contributor>
</entry>
</feed>