7

I would like the output of the XMLLINT to get put into an BASH array. But all I can get is a single string. The results will return many hits, none with any pattern that can help parse the returned string.

  • I have tried --format and redirect ">" to a text file.
  • I have tried xpath all instances // and just one /

mcv.xml

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <instance>
        <absolutePath>/abc/def</absolutePath>
    </instance>
    <instance>
        <absolutePath>/abc/hij</absolutePath>
    </instance>
</root>

mcv.sh

#!/usr/bin/bash

declare -a wwArray=()

wwCount=$(xmllint --xpath 'count(//absolutePath)' "mcv.xml")

printf "wwCount: '%s' \n" ${wwCount}

i=1

while [ $i -le ${wwCount} ];
do
        wwExtracted=$(xmllint --xpath '//absolutePath['${i}']/text    ()' "mcv.xml")
        printf " - absolutePath: '%s' \n" ${wwExtracted}
        printf " - index: '%d' \n" ${i}
        let i=i+1
done 

Running this, the output is:

wwCount: '2'
 - absolutePath: '/abc/def/abc/hij'
 - index: '1'
XPath set is empty
 - absolutePath: ''
 - index: '2'

...whereas I would expect it to instead be:

wwCount: '2'
 - absolutePath: '/abc/def'
 - index: '1'
 - absolutePath: '/abc/hij'
 - index: '2'
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
paulhr
  • 339
  • 4
  • 17
  • Without having an example input document, we can't actually test this ourselves. That said, note that `ww=$(...)` is a *string* assignment, not an array assignment, and that `for i in $ww` is word-splitting and glob-expanding a string, not iterating over array elements. (Even if `ww` is an array, that operation ignores all but the first element, and operates on that first element as a string). – Charles Duffy Feb 05 '19 at 21:51
  • ...if `ww` truly were an array, iterating over it would be `for i in "${ww[@]}"`, but to make that true you'd need to assign to it in a completely different way. – Charles Duffy Feb 05 '19 at 21:53
  • Also, you don't need to use `for` to run a `printf` string once per array element -- `printf '%s\n' "${ww[@]}"` would do the trick (if, again, you had actually assigned to an array in the first place). – Charles Duffy Feb 05 '19 at 21:53
  • Replaced code with a MCV BASH and XML file as per Charles Duffy – paulhr Feb 06 '19 at 15:30
  • Much better. I also added in actual and (what I presume to be) desired output. – Charles Duffy Feb 06 '19 at 16:44

1 Answers1

10

The smallest change needed to make your existing code work is to add parens before the [$i], like so:

#!/usr/bin/bash
wwCount=$(xmllint --xpath 'count(//absolutePath)' "mcv.xml")
for ((i=1; i<=wwCount; i++)); do
        wwExtracted=$(xmllint --xpath '(//absolutePath)['"$i"']/text()' "mcv.xml")
        printf " - absolutePath: '%s' \n" "$wwExtracted"
        printf " - index: '%d' \n" "$i"
done 

That said, this is really inefficient (running your XPath over and over). Consider switching away from xmllint to use XMLStarlet instead, which can be instructed to insert newlines between output elements, so you can tell bash to load those items directly into a real shell array:

#!/usr/bin/bash
readarray -t items < <(xmlstarlet sel -t -m '//absolutePath' -v './text()' -n <mcv.xml)
printf ' - absolutePath: %s\n' "${items[@]}"

Once you've got contents into an array (as created by readarray above), you can also iterate by index:

for idx in "${!items[@]}"; do
  printf ' - absolutePath: %s\n' "${items[$idx]}"
  printf ' - index: %s\n' "$idx"
done
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Thanks so much Charles. – paulhr Feb 06 '19 at 17:18
  • BTW, if you *want* to use XMLStarlet, but don't have it installed everywhere you need, it's possible to have `xmlstarlet sel` generate an XSLT template you can run anywhere `xsltproc` is installed (which should be available *more* places than `xmllint --xpath`). `xmlstarlet sel -C -t -m '//absolutePath' -v './text()' -n` will generate an XSLT file that can be used in that way. – Charles Duffy Feb 06 '19 at 19:10
  • excellent construction. I used (and referenced) it for [an answer](https://es.stackoverflow.com/a/371968/83) in SOes. – fedorqui Jul 08 '20 at 15:21