Объединить несколько элементов xml с помощью xmlstarlet

Я пытаюсь написать сценарий bash для извлечения нескольких «режиссеров» из XML-файла , такого как этот и соедините их, разделив их вертикальной чертой, т.е. Tom Tykwer|Andy Wachowski.

Соответствующий раздел xml:

<directors>
<item>Tom Tykwer</item>
<item>Andy Wachowski</item>
</directors>

С xmlstarlet в скрипте bash следующие команды:

DIRECTORS=$(xmlstarlet sel -t -v "imdbdocument/directors/item" mymoviexml)
echo $DIRECTORS

дай мне

Tom Tykwer Andy Wachowski

и эта команда прямо на терминале

xmlstarlet sel -t -v "imdbdocument/directors/item" mymovieapi.xml

дает мне:

(empty line)
Tom Tykwer
Andy Wachowski

Я не знаю, почему добавляются новые строки, когда я не указываю параметр -n.

Некоторые из моих поисков предложили что-то вроде этого:

xmlstarlet sel -t -m "imdbdocument/directors" -v "item" -o "|" mymovieapi.xml 

но это просто дает мне:

Tom Tykwer
Andy Wachowski|

Я был бы признателен за любую помощь, которую я могу получить. Я вижу такое поведение с xmlstarlet 1.3.1 в Debian Wheezy и xmlstarlet 1.5.0 в Xubuntu 13.10.


person hillbillydetective    schedule 01.01.2014    source источник
comment
Вы должны использовать --text (или -T), так как вам не нужен вывод XML.   -  person npostavs    schedule 02.01.2014
comment
Я попробовал параметр --text, но это не повлияло на вывод.   -  person hillbillydetective    schedule 02.01.2014


Ответы (2)


Решение, использующее только xmlstarlet:

xmlstarlet sel -T -t -v '/imdbdocument/directors/item[1]' -m '/imdbdocument/directors/item[position()>1]' -o '|' -v . mymovieapi.xml

Я тестировал с версией 1.5, но думаю, что она должна работать и с более ранними версиями.


Альтернатива, использующая --if вместо двух выражений XPath:

xmlstarlet sel -T -t -m '/imdbdocument/directors/item' --if 'position() > 1' -o '|' -b -v . mymovieapi.xml

-b — это --break, он завершает текущий оператор (условный или циклический), как } в C.

person npostavs    schedule 02.01.2014
comment
Большое спасибо, это то, что я искал. Теперь я вижу, что моя проблема заключалась в непонимании соответствия -m и -v . синтаксис. Я предполагаю, что вы разделили элементы на [1] и [position()›1], так что канал печатается только между элементами, а не в начале или конце вывода. - person hillbillydetective; 03.01.2014
comment
Получение каналов только между элементами также может быть выполнено с помощью --if, как в решении awk. Я сделал это первым способом, потому что склонен думать наборами, когда пишу XPath. - person npostavs; 03.01.2014

Можешь попробовать

xmlstarlet sel -t -v "imdbdocument/directors/item" mymovieapi.xml |  awk '1' ORS='|'

с выходом

|Tom Tykwer|Andy Wachowski|

или если вам не нужны ведущие и конечные каналы |:

xmlstarlet sel -t -v "imdbdocument/directors/item" mymovieapi.xml | awk 'NF>0 {if (i++) printf "|"; printf "%s", $0 } END { printf "\n" }'

дает

Tom Tykwer|Andy Wachowski
person Håkon Hægland    schedule 01.01.2014
comment
Спасибо, я подтверждаю, что это работает для моих целей и позволит мне продолжить. Очень признателен. Мне было бы интересно, есть ли решение, использующее только xmlstarlet. Мое чтение показало, что это возможно, но мои версии xmlstarlet, похоже, не ведут себя таким же образом. - person hillbillydetective; 02.01.2014