Проанализируйте XML-файл, чтобы получить полный тег, используя пакет lxml Python

#python #xml #lxml

#python #xml #lxml

Вопрос:

У меня есть следующий XML-файл:

 <root>

    <scene name="scene1">
        <view ath="0" atv="10"/>
        <image url="img1.jgp"/>
        <hotspot name="hot1"/>
    </scene>

    <scene name="scene2">
        <view ath="20" atv="10"/>
        <image url="img2.jgp"/>
        <hotspot name="hot2"/>
    </scene>

</root>
  

Я пишу скрипт на Python с использованием пакета lxml, чтобы получить весь view тег внутри scene1 . Это:

 <view ath="0" atv="10" />
  

Я прочитал документацию по lxml, но все, что я могу найти, это как получить тег, его атрибуты или содержимое, но не весь тег.

Может ли кто-нибудь хотя бы указать мне правильное направление? Есть ли в lxml функция или метод для достижения этой цели?

Спасибо,

Рафаэль

Комментарии:

1. Проанализируйте файл с lxml.etree;parse помощью , используйте выражение XPath для поиска ваших элементов, см.: XPath и XSLT с помощью lxml . Сериализуйте результат с помощью lxml.etree.tostring .

2. Обратите внимание: я отредактировал ваш образец XML, потому что он недействителен. Ожидание рецензирования…

Ответ №1:

Содержимое XML представляет собой строку, подобную этой:

 content = u"""
<root>

    <scene name="scene1">
        <view ath="0" atv="10"/>
        <image url="img1.jgp"/>
        <hotspot name="hot1"/>
    </scene>

    <scene name="scene2">
        <view ath="20" atv="10"/>
        <image url="img2.jgp"/>
        <hotspot name="hot2"/>
    </scene>

</root>
"""
  

Вы можете проанализировать файл; Но здесь я анализирую StringIO:

 tree = etree.parse(io.StringIO(content))
  

Все загружается в ElementTree .

Чтобы найти представления, я использую выражение XPath:

 views = tree.xpath("//scene/view")
  

Результатом всегда является список:

 for view in views:
    print(etree.tostring(view, with_tail=False))
  

Вы получите:

 <view ath="0" atv="10"/>
<view ath="20" atv="10"/>
  

Ответ №2:

Ваш данный XML-источник содержит некоторые ошибки; Я исправил их, см. Мой источник ниже:

 from lxml import etree

source = """
<root>
  <scene name="scene1">
    <view ath="0" atv="10" />
    <image url="img1.jgp" />
    <hotspot name="hot1" />
  </scene>

  <scene name="scene2">
    <view ath="20" atv="10" />
    <image url="img2.jgp" />
    <hotspot name="hot2" />
  </scene>
</root>
"""
  

Для анализа этого источника вы создадите etree:

 tree = etree.fromstring(source)
  

(Для источника, поступающего из файла, используйте etree.parse() вместо этого.)

Теперь вы можете просматривать проанализированный XML tree , получив правильный доступ. Мой любимый способ сделать это — перейти с помощью XPaths (освоение их выходит за рамки вашего вопроса):

 allViews = tree.xpath('//root/scene/view')
for view in allViews:
  print view.attrib
  

При этом будут напечатаны все атрибуты XML для каждого тега представления, найденного XPath:

 {'atv': '10', 'ath': '0'}
{'atv': '10', 'ath': '20'}
  

Конечно, вы также можете получить доступ к другим атрибутам элементов представления, таким как их встроенный текст (который здесь, конечно, пустой) или их подэлементы (дочерние элементы) (конечно, в вашем примере у них также нет дочерних элементов).

Формулировка вашего вопроса предполагает, что вы, возможно, не поняли того факта, что этот view объект действительно является «тегом всего представления». Вы можете запросить у view объекта тег, из которого он состоит ( view ), его атрибуты (см. Выше), его содержимое ( view.text ) и даже его подэлементы ( view.getchildren() , но их нет).

Вы можете преобразовать проанализированную структуру XML обратно в представление ASCII с помощью вызова etree.tostring(view) ; это вернет строку like '<view ath="20" atv="10"/>n ' . В большинстве случаев вы этого не сделаете.

Вы также можете получить доступ к элементам, просмотреть дочерние элементы элементов:

 print tree.getchildren()[1].getchildren()[0].attrib
  

Это выведет XML-атрибуты 0-го дочернего элемента (a view ) первого дочернего элемента (a scene ) tree элемента:

 {'atv': '10', 'ath': '20'}