Перетворити Python ElementTree на рядок


85

Щоразу, коли я телефоную 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'

Відповіді:


107

Elementоб'єкти не мають .getroot()методу. Відкиньте цей дзвінок, і .tostring()дзвінок спрацює:

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

7
Для тих, хто пізно шукає пошукову систему: коли кодування має значення 'utf8', воно додає <?xml version='1.0' encoding='utf8'?>заголовок. Коли це utf-8заголовок, не входить. Крім того, якщо це etбуло ElementTree, ви повинні пройти et.getroot().
Kenji Noguchi

24
У Python 3 encoding='utf8'повертає байтовий рядок замість рядка. Я рекомендую використовувати tostring(xml, encoding="unicode")замість цього .
Стевойсяк

2
@StevenVascellaro: XML - це справді двійковий формат , оскільки формат даних складається з байтів у заданому кодуванні (зазначеному в декларації XML вгорі, за замовчуванням UTF-8, якщо його немає). У Python 2 strце такий самий об’єкт, як і bytesPython 3. Виведення байтів є цілком коректним, unicodeоскільки використання як вихід є по суті доповненням, яке дозволяє уникнути необхідності декодування, якщо вам потрібен рядок Unicode, а не для вашого конкретного випадку використання.
Мартін Пітерс

1
Відповідно до help, лише encoding="unicode"поверне рядок.
cz

46

Як конвертувати 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()повертає bytestring за замовчуванням у 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" />

Дякую Мартіну Петерсу за вказівку на те, що 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>

1
У Python 2 ElementTree.tostring()також генерує побітове тестування. strТип є байтовой рядки в Python 2 (Python 3 в strтип називається unicodeв Python 2).
Мартін Пітерс

1
Ця функція була додана лише до версії Python 3, а не повернута до Python 2. Якби вона була, ви unicodeповернули б рядок.
Мартін Пітерс

0

Розширення нелатинських відповідей

Розширення відповіді @ 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" />

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.