Как заставить XMLLINT поместить результаты --xpath в массив

Я хотел бы, чтобы выходные данные XMLLINT помещались в массив BASH. Но все, что я могу получить, это одна строка. Результаты будут возвращать много совпадений, причем ни один из них не будет содержать шаблон, который может помочь разобрать возвращенную строку.

  • Я попытался --format и перенаправить ">" в текстовый файл.
  • Я пробовал xpath все экземпляры // и только один /

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 

Запустив это, вывод:

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

... тогда как я ожидаю, что вместо этого будет:

wwCount: '2'
 - absolutePath: '/abc/def'
 - index: '1'
 - absolutePath: '/abc/hij'
 - index: '2'

1 ответ

Решение

Наименьшее изменение, необходимое для того, чтобы ваш существующий код заработал, - это добавлять символы перед [$i], вот так:

#!/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 

Тем не менее, это действительно неэффективно (запуск вашего XPath снова и снова). Рассмотреть возможность перехода от xmllint вместо этого использовать XMLStarlet, который может быть инструктирован для вставки новых строк между выходными элементами, так что вы можете сказать bash загрузить эти элементы непосредственно в реальный массив оболочки:

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

Как только вы получили содержимое в массив (как создано readarray выше), вы также можете выполнить итерацию по индексу:

for idx in "${!items[@]}"; do
  printf ' - absolutePath: %s\n' "${items[$idx]}"
  printf ' - index: %s\n' "$idx"
done
Другие вопросы по тегам