Python: пространства имен в xml ElementTree (или lxml) - PullRequest
6 голосов
/ 03 февраля 2011

Я хочу получить устаревший XML-файл, манипулировать и сохранить его.

Вот мой код:

from xml.etree import cElementTree as ET
NS = "{http://www.somedomain.com/XI/Traffic/10}"

def fix_xml(filename):
    f = ET.parse(filename)
    root = f.getroot()
    eventlist = root.findall("%(ns)Event" % {'ns':NS })
    xpath = "%(ns)sEventDetail/%(ns)sEventDescription" % {'ns':NS }
    for event in eventlist:
        desc = event.find(xpath)
        desc.text = desc.text.upper() # do some editting to the text.

    ET.ElementTree(root, nsmap=NS).write("out.xml", encoding="utf-8")


shorten_xml("test.xml")

Загружаемый файл содержит:

xmlns="http://www.somedomain.com/XI/Traffic/10"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.somedomain.com/XI/Traffic/10 10.xds"

в корневом теге.

У меня есть следующие проблемы, связанные с пространством имен:

  • Как вы видите, для каждого вызова тега я дал пространство имен в началеполучить ребенка.
  • В созданном XML-файле нет <?xml version="1.0" encoding="utf-8"?> в начале.
  • Теги на выходе содержат такие <ns0:eventDescription>, в то время как мне нужен вывод как исходный <eventDescription>, без пространства имен в начале.

Как это можно решить?

Ответы [ 2 ]

6 голосов
/ 03 февраля 2011

Ознакомьтесь с разделом учебника lxml по пространствам имен . Также эта статья о пространствах имен в ElementTree .

Проблема 1: мириться с этим, как и все остальные. Вместо "%(ns)Event" % {'ns':NS } попробуйте NS+"Event".

Проблема 2: По умолчанию декларация XML записывается, только если она требуется. Вы можете форсировать его (только lxml), используя xml_declaration=True в своем вызове write().

Проблема 3: Аргумент nsmap выглядит только для lxml. AFAICT это нужно MAPping, а не строка. Попробуйте nsmap={None: NS}. В статье effbot есть раздел, описывающий обходной путь для этого.

1 голос
/ 03 февраля 2011

Чтобы ответить на ваши вопросы по порядку:

  • вы не можете просто игнорировать пространство имен, не в синтаксисе пути, который используется .findall(), но не в "реальном" xpath (также поддерживается lxml): там вы все равно будете вынуждены использовать префикс, и вам все равно потребуется предоставить какое-то отображение префикса в uri.

  • , используйте xml_declaration=True, а такжеencoding='utf-8' с вызовом .write() (доступно в lxml, но в stdlib xml.etree только начиная с python 2.7 Я верю)

  • Я считаю, что lxml будет вести себя так, как вы хотите

...