Подтвердить что ты не робот

Извлечь 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:

Кто-нибудь знает, что я сделал неправильно? Спасибо!

4b9b3361

Ответ 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 &amp; Jobs на Brewster & Jobs) и т.д.

Ответ 3

Я согласен с Чарльзом Даффи в том, что правильный парсер XML - правильный путь.

Но что случилось с вашей командой sed (или вы сделали это специально?).

  • $data не цитировался, поэтому $data подлежит расщеплению ракурса, расширению имени файла среди прочего. Одним из следствий является то, что интервал в фрагменте XML не сохраняется.

Поэтому, учитывая вашу конкретную структуру XML, эта измененная команда sed должна работать

title=$(sed -ne '/title/{s/.*<title>\(.*\)<\/title>.*/\1/p;q;}' <<< "$data")

В основном для строки, содержащей title, извлеките текст между тегами, затем закройте (чтобы вы не извлекли второй <title>)