2017-02-14 35 views
0

У меня есть XML-файл с большим количеством полей мультимедиа. Кусок примера XML:Извлечь несколько полей с именованными полями, используя xmllint

<root> 
    <item> 
     <name>Item 1</name> 
     <mediaList> 
      <media> 
       <name>Name 1</name> 
       <URL><![CDATA[http://example.com/image1.jpg]]></URL> 
      </media> 
      <media> 
       <name>Name 2</name> 
       <URL><![CDATA[http://example.com/image2.jpg]]></URL> 
      </media> 
     </mediaList> 
    </item> 
    <item> 
     <name>Item 2</name> 
     <mediaList> 
      <media> 
       <name>Name 3</name> 
       <URL><![CDATA[http://example.com/image3.jpg]]></URL> 
      </media> 
      <media> 
       <name>Name 4</name> 
       <URL><![CDATA[http://example.com/image4.jpg]]></URL> 
      </media> 
     </mediaList> 
    </item> 
</root> 

Все предметы построены таким же образом. Используя XMLLint с XPath, я пытаюсь получить список всех URL-адресов. Однако до сих пор я еще не нашел лучшего способа сделать это. Некоторые из способов, которые я пробовал его являются:

xmllint --xpath "string(/root/item/mediaList/URL)" file.xml >> log.txt

Это один возвращает хороший URL, но останавливается после первого пункта (давая мне только 1 изображение)

xmllint --xpath "/root/item/mediaList/URL" file.xml >> log.txt

Этот дает мне все предметы, но все находится на одной линии и отображается как <URL><![CDATA[http://example.com/image.jpg]]></URL> для каждого элемента.

xmllint --xpath "/root/item/mediaList/URL/text()" file.xml >> log.txt

Это ближе, но все равно возвращает <![CDATA[]]> теги вокруг него, и снова все в одной строке.

Я также пробовал перебирать предметы, но это было очень медленно и не работало должным образом.

В результате я и добиваюсь является TXT-файл со всеми изображениями ниже друг друга, так как:

http://example.com/image1.jpg 
http://example.com/image2.jpg 
http://example.com/image3.jpg 
http://example.com/image4.jpg 
+1

Параметр '--nocdata' извлекает текст с каждого узла CDATA. Однако я не уверен, как получить каждый URL-адрес на отдельной строке. – chepner

+0

Спасибо! Неплохо. Еще одна проблема, о которой стоит подумать. –

ответ

2

xmllint не поддерживает string(...) для нескольких матчей XPath. (Поэтому он показывает только 1-й результат).

Вы можете использовать xmlstarlet как:

xmlstarlet sel -T -t -m /root/item/mediaList/media/URL -v . -n file.xml 

и производит

http://example.com/image1.jpg 
http://example.com/image2.jpg 
http://example.com/image3.jpg 
http://example.com/image4.jpg 

или также PERL (с установленным XML::LibXML модулем), как:

perl -MXML::LibXML -E 'say $_->to_literal for XML::LibXML->load_xml(location=>q{file.xml})->findnodes(q{/root/item/mediaList/media/URL})' 

также производит тот же результат как указано выше.

+0

Опция 'xmlstarlet' решила его для меня. Спасибо. –

0

Я думаю, вы должны изменить парсер в W3C Document:

Каждый символ в секции CDATA рассматривается как символьные данные. Таким образом, <! [CDATA [<]]> в исходном документе будет обрабатываться так же, как <. Оба будут приводить к одному знаку < в текстовом узле в дереве . Таким образом, секция CDATA обрабатывается так, как если бы были удалены <! [CDATA [и]]> , и все случаи < и & были заменены на < и & соответственно.

CDATA будут автоматически удалены, я проверить его в Python:

tree = etree.fromstring(xml) 
tree.xpath('//URL/text()') 

из:

['http://example.com/image1.jpg', 
'http://example.com/image2.jpg', 
'http://example.com/image3.jpg', 
'http://example.com/image4.jpg'] 

Ваш XPath правильно.

 Смежные вопросы

  • Нет связанных вопросов^_^