Преобразование Python ElementTree в строку

86

Каждый раз, когда я звоню ElementTree.tostring(e), я получаю следующее сообщение об ошибке:

AttributeError: 'Element' object has no attribute 'getroot'

Есть ли другой способ преобразовать объект ElementTree в строку XML?

Проследить:

Traceback (most recent call last):
  File "Development/Python/REObjectSort/REObjectResolver.py", line 145, in <module>
    cm = integrateDataWithCsv(cm, csvm)
  File "Development/Python/REObjectSort/REObjectResolver.py", line 137, in integrateDataWithCsv
    xmlstr = ElementTree.tostring(et.getroot(),encoding='utf8',method='xml')
AttributeError: 'Element' object has no attribute 'getroot'
Stevoisiak
источник

Ответы:

111

Elementу объектов нет .getroot()метода. Отбросьте этот звонок, и .tostring()звонок заработает:

xmlstr = ElementTree.tostring(et, encoding='utf8', method='xml')

Вам нужно только использовать, .getroot()если у вас есть ElementTreeэкземпляр .

Прочие примечания:

  • Это создает строку байтов , которая в Python 3 является bytesтипом.
    Если вам нужен strобъект, у вас есть два варианта:

    1. Декодируйте полученное значение байтов из UTF-8: xmlstr.decode("utf8")

    2. Использование encoding='unicode'; это позволяет избежать цикла кодирования / декодирования:

      xmlstr = ElementTree.tostring(et, encoding='unicode', method='xml')
      
  • Если вам нужно значение байтовой строки в кодировке UTF-8 или вы используете Python 2, примите во внимание, что ElementTree не распознает должным образом utf8стандартную кодировку XML, поэтому он добавит <?xml version='1.0' encoding='utf8'?>объявление. Используйте utf-8или UTF-8(с тире), если хотите предотвратить это. При использовании encoding="unicode"не добавляется заголовок объявления.

Мартейн Питерс
источник
47

Как преобразовать ElementTree.Elementв строку?

Для Python 3:

xml_str = ElementTree.tostring(xml, encoding='unicode')

Для Python 2:

xml_str = ElementTree.tostring(xml, encoding='utf-8')

Следующее совместимо с Python 2 и 3, но работает только с латинскими символами :

xml_str = ElementTree.tostring(xml).decode()

Пример использования

from xml.etree import ElementTree

xml = ElementTree.Element("Person", Name="John")
xml_str = ElementTree.tostring(xml).decode()
print(xml_str)

Вывод:

<Person Name="John" />

Объяснение

Несмотря на то, что подразумевает название, ElementTree.tostring()по умолчанию возвращает строку байтов в Python 2 и 3. Это проблема в Python 3, который использует Unicode для строк .

В Python 2 вы можете использовать этот strтип как для текстовых, так и для двоичных данных . К сожалению, это слияние двух разных концепций могло привести к нестабильному коду, который иногда работал с любыми типами данных, а иногда - нет. [...]

Чтобы сделать различие между текстом и двоичными данными более четким и явным, [Python 3] сделал текст и двоичные данные отдельными типами, которые нельзя слепо смешивать вместе .

Источник: Перенос кода Python 2 на Python 3

Если мы знаем, какая версия Python используется, мы можем указать кодировку как unicodeили utf-8. В противном случае, если нам нужна совместимость с Python 2 и 3, мы можем использовать decode()для преобразования в правильный тип.

Для справки я включил сравнение .tostring()результатов между Python 2 и Python 3.

ElementTree.tostring(xml)
# Python 3: b'<Person Name="John" />'
# Python 2: <Person Name="John" />

ElementTree.tostring(xml, encoding='unicode')
# Python 3: <Person Name="John" />
# Python 2: LookupError: unknown encoding: unicode

ElementTree.tostring(xml, encoding='utf-8')
# Python 3: b'<Person Name="John" />'
# Python 2: <Person Name="John" />

ElementTree.tostring(xml).decode()
# Python 3: <Person Name="John" />
# Python 2: <Person Name="John" />

Спасибо Martijn Peters за указание на изменение strтипа данных между Python 2 и 3.


Почему бы не использовать str ()?

В большинстве сценариев использование str()было бы « каноническим » способом преобразования объекта в строку. К сожалению, использование этого с Elementвозвращает местоположение объекта в памяти как шестнадцатеричную строку, а не строковое представление данных объекта.

from xml.etree import ElementTree

xml = ElementTree.Element("Person", Name="John")
print(str(xml))  # <Element 'Person' at 0x00497A80>
Stevoisiak
источник
1
В Python 2 ElementTree.tostring()также создается строка байтов. strТип является байтовой строки в Python 2 (Python 3 в strтип называется unicodeв Python 2).
Мартейн Питерс
1
Эта функция была добавлена ​​только в версию Python 3 и не была перенесена на Python 2. Если бы это было так, вы бы unicodeвернули строку.
Мартейн Питерс
1

Нелатинское расширение ответа

Расширение ответа @ Stevoisiak и работа с нелатинскими символами. Только один способ отобразит вам нелатинские символы. Один метод отличается как на Python 3, так и на Python 2.

Ввод

xml = ElementTree.fromstring('<Person Name="크리스" />')
xml = ElementTree.Element("Person", Name="크리스")  # Read Note about Python 2

ПРИМЕЧАНИЕ. В Python 2 при вызове toString(...)кода назначение xmlс ElementTree.Element("Person", Name="크리스")вызовет ошибку ...

UnicodeDecodeError: 'ascii' codec can't decode byte 0xed in position 0: ordinal not in range(128)

Вывод

ElementTree.tostring(xml)
# Python 3 (크리스): b'<Person Name="&#53356;&#47532;&#49828;" />'
# Python 3 (John): b'<Person Name="John" />'

# Python 2 (크리스): <Person Name="&#53356;&#47532;&#49828;" />
# Python 2 (John): <Person Name="John" />


ElementTree.tostring(xml, encoding='unicode')
# Python 3 (크리스): <Person Name="크리스" />             <-------- Python 3
# Python 3 (John): <Person Name="John" />

# Python 2 (크리스): LookupError: unknown encoding: unicode
# Python 2 (John): LookupError: unknown encoding: unicode

ElementTree.tostring(xml, encoding='utf-8')
# Python 3 (크리스): b'<Person Name="\xed\x81\xac\xeb\xa6\xac\xec\x8a\xa4" />'
# Python 3 (John): b'<Person Name="John" />'

# Python 2 (크리스): <Person Name="크리스" />             <-------- Python 2
# Python 2 (John): <Person Name="John" />

ElementTree.tostring(xml).decode()
# Python 3 (크리스): <Person Name="&#53356;&#47532;&#49828;" />
# Python 3 (John): <Person Name="John" />

# Python 2 (크리스): <Person Name="&#53356;&#47532;&#49828;" />
# Python 2 (John): <Person Name="John" />

Кристофер Ручински
источник
1
Хороший отзыв о нелатинских символах. Я обновил свой пост, чтобы упомянуть об этом.
Stevoisiak
0

Если вам это нужно просто для отладки, чтобы увидеть, как выглядит XML, тогда вместо print(xml.etree.ElementTree.tostring(e)) вы можете использовать dumpвот так:

xml.etree.ElementTree.dump(e)

И это работает как с Element и ElementTreeобъекты , как e, так что не должно быть никакой необходимости getroot.

Документацияdump говорится:

xml.etree.ElementTree.dump(elem)

Записывает дерево элементов или структуру элементов в sys.stdout. Эта функция должна использоваться только для отладки.

Точный формат вывода зависит от реализации. В этой версии он написан как обычный XML-файл.

elem дерево элементов или отдельный элемент.

Изменено в версии 3.8 : dump()функция теперь сохраняет порядок атрибутов, указанный пользователем.

Пол Тобиас
источник