24

How can I get xmllint to output multiple results of xpath selector for attributes "per line"?

Take this example:

  <?xml version="1.0" encoding="ISO-8859-1"?>
  <config>
          <tagX key1="value1 " key2=" value2"/>
          <tagY key3="value3" key4=" value4 "/>
  </config>


  $ xmllint example.xml --xpath "/config/*/@*"

The result is:

   key1="value1 " key2=" value2" key3="value3" key4=" value4 "

What I'd like to get is:

   key1="value1 "
   key2=" value2"
   key3="value3"
   key4=" value4 "

Would I need to split after even-numbered quote marks, or is there any neater way to do this?

There's a related question, about the same subject except it's about picking out contents of <tag>value</tag>, and not <tag attribute="value" />

Community
  • 1
  • 1
SF.
  • 13,549
  • 14
  • 71
  • 107
  • Does this help -- `echo 'cat /config/*/@*[starts-with(name(),"key")]' | xmllint --shell input.xml` – devnull Jul 31 '13 at 09:52
  • @devnull: `| grep =` and it's fine. (actually, no `[starts-with()...` just `/@*` I used "key1, key2..." as metasyntactic variables, the actual attribute names would be arbitrary.) – SF. Jul 31 '13 at 10:32
  • Yes, `grep -v` and done! – devnull Jul 31 '13 at 10:34
  • @devnull: I'd prefer inclusive grep (all desired lines contain `=`, and undesired are rather fixed: `/ > cat /config/*/@*` and ` -------` - and it's possible the value might contain `-------`, so `grep '='` is sure to find what I want (unless I use `=` in the selector, which I don't.) – SF. Jul 31 '13 at 10:36
  • @devnull: By the way, post that as an answer and I'll accept. – SF. Jul 31 '13 at 13:28
  • Value only: http://stackoverflow.com/questions/26823736/with-xmllint-xpath-parse-out-the-value-of-several-attributes – Ciro Santilli OurBigBook.com Oct 07 '15 at 12:01

5 Answers5

16

You can try:

$ xmllint --shell inputfile <<< 'cat /config/*/@*'

You might need to grep the output, though, so as to filter the undesired lines.

Socowi
  • 25,550
  • 3
  • 32
  • 54
devnull
  • 118,548
  • 33
  • 236
  • 227
  • Agree with Guss. Also I could work around parsing the diagnostics and the separator lines (with a different XPATH expression in my case), `xmllint --shell /tmp/tt.xml <<< "cat //s/text()" | { read -r diag; while { read -r separator; read -r line; } ; do echo "${line}" ; done ; } > /tmp/tt-words.txt` – eel ghEEz Oct 27 '18 at 21:03
6

If it's an option, try using xmlstarlet instead:

xmlstarlet sel -t -v "/config/*/@*" example.xml

tremby
  • 9,541
  • 4
  • 55
  • 74
1

The question is old but as I came to this post searching a solution to the same problem, here is my solution

On linux add sed substitution to split output:

$ xmllint example.xml --xpath "/config/*/@*" | sed "s| key|\nkey|g"

of course the substitution expression depends on your xml structure and your xpath query.

And you can even add line numbers on each line if you add nl

$ xmllint example.xml --xpath "/config/*/@*" | sed "s| key|\nkey|g" | nl

Which gives

   1 key1="value1 "
   2 key2=" value2"
   3 key3="value3"
   4 key4=" value4 "
Dumitru
  • 11
  • 1
  • 1
    The problem of this is that it depends on consistent naming scheme of the keys (properties). If they are not 'key1, key2' but 'name, birthdate', this won't work. – SF. May 04 '15 at 14:48
1

If using the latest xmllint, results should have been separated by \n now. However, if fields contain \n, you can use this patched version to use \0 as a separator, with --xpath0. For whatever reason the PR hasn't been merged yet.

Cyker
  • 9,946
  • 8
  • 65
  • 93
1

I found that Ubuntu v.14 and v.18 use too old libxml2 versions. So i solved the issue mentioned in the topic by the recompiling of libxml2 v2.9.10.

1) Download the sources of libxml2 from http://linuxfromscratch.org/blfs/view/cvs/general/libxml2.html

2) Download the test suite:

$ wget http://www.w3.org/XML/Test/xmlts20130923.tar.gz

3) Execute:

$ tar xf libxml2-2.9.10.tar.gz

4) Execute:

$ cd libxml2-2.9.10/

5) Execute:

$ sed -i 's/test.test/#&/' python/tests/tstLastError.py

6) Execute:

$ export CPATH="/usr/include/python3.6/:$CPATH"

7) Execute:

$ sudo apt-get install -y python3-libxml2 python3-pip

8) Execute:

$ sudo pip3 install libxml2dom

9) Execute:

$ ./configure --prefix=/usr --disable-static --with-history --with-python=/usr/bin/python3 && make

Ensure here that the returning code ($?) is 0.

10) Execute:

$ tar xf ../xmlts20130923.tar.gz

11) Execute:

make check > check.log

Ensure here that the returning code ($?) is 0.

12) Execute:

$ sudo make install

Enjoy

$ xmllint data.xml -xpath "//some_child/ancestor::some_parent/attribute::id"                                                                               
 id="1"
 id="10010"
 id="10011"
 id="10020"
 id="10021"
kalessinf
  • 11
  • 2