Извлечь XML-значение в bash script
Я пытаюсь извлечь значение из XML-документа, который был прочитан в моем script как переменная. Исходная переменная $data:
<item>
<title>15:54:57 - George:</title>
<description>Diane DeConn? You saw Diane DeConn!</description>
</item>
<item>
<title>15:55:17 - Jerry:</title>
<description>Something huh?</description>
</item>
и я хочу извлечь первое значение названия, поэтому
15:54:57 - George:
Я использовал команду sed:
title=$(sed -n -e 's/.*<title>\(.*\)<\/title>.*/\1/p' <<< $data)
но это выводит только второе значение заголовка:
15:55:17 - Jerry:
Кто-нибудь знает, что я сделал неправильно?
Спасибо!
Ответы
Ответ 1
Как Чарльз Даффи заявил, что синтаксические анализаторы XML лучше всего разбираются с правильными инструментами анализа XML. За одно время работа должна работать.
grep -oPm1 "(?<=<title>)[^<]+"
Тест:
$ echo "$data"
<item>
<title>15:54:57 - George:</title>
<description>Diane DeConn? You saw Diane DeConn!</description>
</item>
<item>
<title>15:55:17 - Jerry:</title>
<description>Something huh?</description>
$ title=$(grep -oPm1 "(?<=<title>)[^<]+" <<< "$data")
$ echo "$title"
15:54:57 - George:
Ответ 2
XMLStarlet или другой механизм XPath - правильный инструмент для этого задания.
Например, при data.xml
, содержащем следующее:
<root>
<item>
<title>15:54:57 - George:</title>
<description>Diane DeConn? You saw Diane DeConn!</description>
</item>
<item>
<title>15:55:17 - Jerry:</title>
<description>Something huh?</description>
</item>
</root>
... вы можете извлечь только первый заголовок со следующим:
xmlstarlet sel -t -m '//title[1]' -v . -n <data.xml
Пытаясь использовать sed для этого задания, неприятный. Например, подходы, основанные на регулярном выражении, не будут работать, если заголовок имеет атрибуты; не будет обрабатывать разделы CDATA; не будут правильно распознавать сопоставления пространства имен; не может определить, прокомментирована ли часть документированного XML; не будет ссылаться на ссылки на атрибуты unescape (например, изменение Brewster & Jobs
на Brewster & Jobs
) и т.д.
Ответ 3
Я согласен с Чарльзом Даффи в том, что правильный парсер XML - правильный путь.
Но что случилось с вашей командой sed
(или вы сделали это специально?).
-
$data
не цитировался, поэтому $data
подлежит расщеплению ракурса, расширению имени файла среди прочего. Одним из следствий является то, что интервал в фрагменте XML не сохраняется.
Поэтому, учитывая вашу конкретную структуру XML, эта измененная команда sed
должна работать
title=$(sed -ne '/title/{s/.*<title>\(.*\)<\/title>.*/\1/p;q;}' <<< "$data")
В основном для строки, содержащей title
, извлеките текст между тегами, затем закройте (чтобы вы не извлекли второй <title>
)