нужна помощь в анализе и преобразовании значений для хранения в CSV.
См. ниже образец XML.
<list type='full' level='state' val='WI'>
<ac val='262'>
<ph val='0000000' />
<ph val='0003639' />
<ph val='0129292' />
</ac>
<ac val='363'>
<ph val='0000000' />
<ph val='0003639' />
</ac>
</list>
Мне нужно, чтобы результат был похож на
262, '0000000'
262, '0003639'
262, '0129292'
363, '0000000'
363, '0003639'
Я попытался просмотреть файл и записи, но проблема в том, что мы не знаем, сколько телефонов мы получаем по каждому AC (коды городов), поэтому цикл извлечения телефона (j) является проблемой.
for i in {1..2}; do
for j in {1..3}; do
echo "i=$i, j=$j"
xmllint --xpath "concat(//ac[$i]/@val,',', //ac/ph[$j]/@val)" test.xml
done
done
Можем ли мы сделать это каким-нибудь простым способом, используя xmllint?
Спасибо
Или это: acid=1;while read acval < <(xmllint --xpath "string(//ac[$acid]/@val)" file.xml) && [[ $acval ]]; do phid=1;while read phval < <(xmllint --xpath "string(//ac[$acid]/ph[$phid]/@val)" file.xml) && [[ $phval ]];do echo "$acval, '$phval'";((phid+=1));done; ((acid+=1));done





Вот один из способов использования xmlstarlet, перебирая /list/ac/ph, а затем объединяя ../@val родительского узла со значениями атрибута @val текущего узла.
xmlstarlet sel -t -m '/list/ac/ph' -v 'concat(../@val, ", ", @val)' --nl file.xml
262, 0000000
262, 0003639
262, 0129292
363, 0000000
363, 0003639
Вот еще один, использующий kislyuk/yq, который имеет встроенный генератор CSV с правильным экранированием:
xq -r '.list.ac[] | [."@val" | tonumber] + (.ph[] | [."@val"]) | @csv' file.xml
262,"0000000"
262,"0003639"
262,"0129292"
363,"0000000"
363,"0003639"
Принимая код города как предсказуемое значение
for ac in 262 363; do
xmllint --xpath "//ac[@val=$ac]/ph/@val" tmp.xml | sed -re "s/ val=([^=]+)/$ac, \1/g"
done
Результат
262,"0000000"
262,"0003639"
262,"0129292"
363,"0000000"
363,"0003639"
Чтобы не анализировать файл для каждого кода города
declare -a xcmd
# setup xmllint shell commands
for ac in $(xmllint --xpath '//ac/@val' tmp.xml | cut -d'=' -f2 | tr -d ' "'); do
xcmd[${#xcmd[@]}] = "cd ac-$ac"
xcmd[${#xcmd[@]}] = "cat //ac[@val=$ac]/ph/@val"
done
# run and parse commands
printf "%s\n" "${xcmd[@]}" | xmllint --shell tmp.xml 2>/dev/null | grep -v ' ----' | \
while read line; do
if grep -q '^[/] > cd ac-[0-9]' <<<"$line"; then
c=$(cut -d '-' -f2 <<<"$line")
else
echo "$line" | sed -nre "s/val=([^=]+)/$c,\1/p"
fi
done | grep -v '^[/] >'
xmllint test.xml | sed -ne '/<ac/{s/.*"\(.*\)".*/\1/;h;};/<ph/{ G;s/.*"\(.*\)".*\n\(.*\)/\2, \o47\1\o47/p }'