В стандартной библиотеке Python имеется две реализации этого модуля — xml.etree.ElementTree и xml.etree.cElementTree.
xml.etree.ElementTree — реализация API для работы с XML файлами на чистом Python, а xml.etree.cElementTree — то же, но на C, и даёт существенный прирост производительности при обработке больших файлов.
Можно импортировать их так:
#!/usr/bin/env python try: import xml.etree.cElementTree as ET except ImportError: import xml.etree.ElementTree as ET print ET
Результат:
$ ./xml_par.py <module 'xml.etree.cElementTree' from '/usr/lib64/python2.6/xml/etree/cElementTree.pyc'>
В Python версии 3.3 и выше необходимости в такой try/except нет, т.к. интерпретатор самостоятельно будет выполнять поиск cElementTree при импорте ElementTree (да и в Python 2.6 и 2.7 cElementTree импортируется без проблем).
Содержание
Парсинг XML-файла
Для примера возьмём простой XML-файл с таким содержимым:
<TreeRoot>
<Element1 value1="Value1">
<SubElement1>SubElement1</SubElement1>
<SubElement2>SubElement2</SubElement2>
</Element1>
<Element2 value2="Value2">
<SubElement3>SubElement3</SubElement3>
<SubElement4>SubElement4</SubElement4>
</Element2>
</TreeRoot>
Изменим скрипт:
import os
import xml.etree.cElementTree as ET
XML_FILE = os.path.join(os.environ['HOME'], 'xmlfile.xml')
try:
tree = ET.ElementTree(file=XML_FILE)
print help(tree)
except IOError as e:
print 'nERROR - cant find file: %sn' % e
В результате — мы должны получить список доступных методов для объекта tree:
Help on instance of ElementTree in module __builtin__: class ElementTree(xml.etree.ElementTree.ElementTree) | Methods defined here: | | parse(self, source, parser=None) | | ---------------------------------------------------------------------- | Methods inherited from xml.etree.ElementTree.ElementTree: | | __init__(self, element=None, file=None) | | find(self, path) | | findall(self, path) | | findtext(self, path, default=None) | | getiterator(self, tag=None) | | getroot(self) | | write(self, file, encoding='us-ascii')
В случае ошибки синтаксиса XML — будет вызвана ошибка с указанием точного места:
cElementTree.ParseError: mismatched tag: line 11, column 2
Тогда файл стоит проверить в XML-валидаторе, например — тут>>>.
Для получения корневого элемента — используется метод getroot():
...
try:
tree = ET.ElementTree(file=XML_FILE)
print tree.getroot()
print type(tree.getroot())
...
$ ./xml_par.py <Element 'TreeRoot' at 0x6ffffd96120> <type 'Element'>
Каждый элемент содержит несколько параметров:
tag— строка, отображающая тип данных, которые представляет элемент;attrib— атрибуты элемента, которые сохраняются в словарь Python;text— текстовое значение элемента;- дочерние элементы.
Например — получить тег корневого элемента можно так:
...
try:
tree = ET.ElementTree(file=XML_FILE)
root = tree.getroot()
print root.tag
...
$ ./xml_par.py TreeRoot
Что бы получить список прямых потомков корневого элемента — можно просто вызвать цикл:
...
try:
tree = ET.ElementTree(file=XML_FILE)
root = tree.getroot()
for child_of_root in root:
print child_of_root.tag, child_of_root.attrib
...
Результат:
$ ./xml_par.py
TreeRoot
Element1 {'value1': 'Value1'}
Element2 {'value2': 'Value2'}
Можно так же вывести только ключи, или ключи:значения:
...
for child_of_root in root:
print child_of_root.tag, child_of_root.keys(), child_of_root.items()
...
Результат:
$ ./xml_par.py
Element1 ['value1'] [('value1', 'Value1')]
Element2 ['value2'] [('value2', 'Value2')]
Поиск элементов в файле
Что бы перебрать все элементы в файле — можно воспользоваться методом iter():
...
try:
tree = ET.ElementTree(file=XML_FILE)
root = tree.getroot()
for child_of_root in root.iter():
print 'Tag: %snKeys: %snItems: %snText: %sn' % (child_of_root.tag, child_of_root.keys(), child_of_root.items(), child_of_root.text)
...
Результат:
$ ./xml_par.py
Tag: TreeRoot
Keys: []
Items: []
Text:
Tag: Element1
Keys: ['value1']
Items: [('value1', 'Value1')]
Text:
Tag: SubElement1
Keys: []
Items: []
Text: SubElement1
Tag: SubElement2
Keys: []
Items: []
Text: SubElement2
Tag: Element2
Keys: ['value2']
Items: [('value2', 'Value2')]
Text:
Tag: SubElement3
Keys: []
Items: []
Text: SubElement3
Tag: SubElement4
Keys: []
Items: []
Text: SubElement4
А что бы найти только один элемент — его тег можно передать аргументом этому методу:
...
for child_of_root in root.iter('SubElement1'):
print 'Tag: %snKeys: %snItems: %snText: %sn' % (child_of_root.tag, child_of_root.keys(), child_of_root.items(), child_of_root.text)
...
Результат:
$ ./xml_par.py Tag: SubElement1 Keys: [] Items: [] Text: SubElement1
Можно выполнить поиск с помощью XPath.
Например, что бы отобразить корневой элемент:
...
try:
tree = ET.ElementTree(file=XML_FILE)
root = tree.getroot()
for item in root.iterfind('.'):
print 'Find: %sn' % item.tag
...
Результат:
$ ./xml_par.py Find: TreeRoot
С помощью // можно найти все вложенные элементы:
...
for item in root.iterfind('.//'):
print 'Find: %sn' % item.tag
...
$ ./xml_par.py Find: Element1 Find: SubElement1 Find: SubElement2 Find: Element2 Find: SubElement3 Find: SubElement4
Или вложенные элементы вложенного элемента:
...
for item in root.iterfind('./Element1//'):
print 'Find: %sn' % item.tag
...
Результат:
$ ./xml_par.py Find: SubElement1 Find: SubElement2
Добавление записей в файл
Для начала — добавим функцию prettify:
from xml.dom import minidom
def prettify(elem):
"""Return a pretty-printed XML string for the Element.
"""
rough_string = ET.tostring(elem, 'utf-8')
reparsed = minidom.parseString(rough_string)
return reparsed.toprettyxml(indent='t')
Теперь — отредактируем код:
#!/usr/bin/env python
import os
import xml.etree.cElementTree as ET
from xml.dom import minidom
def prettify(elem):
"""Return a pretty-printed XML string for the Element.
"""
rough_string = ET.tostring(elem, 'utf-8')
reparsed = minidom.parseString(rough_string)
return reparsed.toprettyxml(indent='t')
XML_FILE = os.path.join(os.environ['HOME'], 'xmlfile.xml')
try:
tree = ET.parse(XML_FILE)
root = tree.getroot()
new_element = ET.Element('NewElement')
new_subelement = ET.SubElement(new_element, 'NewSubelement')
new_subelement.text = 'NewSubelement'
root.append(new_element)
print prettify(root)
# пока оставим так
# tree.write(XML_FILE)
except IOError as e:
print 'nERROR - cant find file: %sn' % e
- с помощью
ET.Elementмы создаём новый элемент с именемNewElement; - затем — с помощью
SubElement— мы добавляем новый вложенный элемент с имменемNewSubelementвнутрь элемента в объектеnew_element; - далее — мы определяем параметр
textобъектаnew_subelement, и задаём занчение'NewSubelement'; - после этого — мы добавляем новый элемент
new_elementсо всем содержимым к корню нашего файла; - последним — вызываем
print()и функциюprettify().
Результат:
$ ./xml_par.py
<?xml version="1.0" ?>
<TreeRoot>
<Element1 value1="Value1">
<SubElement1>SubElement1</SubElement1>
<SubElement2>SubElement2</SubElement2>
</Element1>
<Element2 value2="Value2">
<SubElement3>SubElement3</SubElement3>
<SubElement4>SubElement4</SubElement4>
</Element2>
<NewElement>
<NewSubelement>NewSubelement</NewSubelement>
</NewElement>
</TreeRoot>
Для того, что бы в таком виде записать в файл — можно использовать функцию indent():
def indent(elem, level=0):
i = "n" + level*" "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + " "
if not elem.tail or not elem.tail.strip():
elem.tail = i
for elem in elem:
indent(elem, level+1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
И вызвать её, передав корневой элемент, перед запись в файл:
...
indent(root)
tree.write(XML_FILE)
...
Результат:
$ cat xmlfile.xml
<TreeRoot>
<Element1 value1="Value1">
<SubElement1>SubElement1</SubElement1>
<SubElement2>SubElement2</SubElement2>
</Element1>
<Element2 value2="Value2">
<SubElement3>SubElement3</SubElement3>
<SubElement4>SubElement4</SubElement4>
</Element2>
<NewElement>
<NewSubelement>NewSubelement</NewSubelement>
</NewElement>
</TreeRoot>
Файл с функциями можно скачать тут>>>.
Что бы добавить новый элемент внутрь уже имеющегося — можно указать его индекс в корне, например:
...
new_element = ET.Element('NewElementInElement2')
new_subelement = ET.SubElement(new_element, 'NewSubelementInElement2')
new_subelement.text = 'NewSubelementInElement2'
root[1].append(new_element)
...
Результат:
$ ./xml_par.py
<?xml version="1.0" ?>
<TreeRoot>
<Element1 value1="Value1">
<SubElement1>SubElement1</SubElement1>
<SubElement2>SubElement2</SubElement2>
</Element1>
<Element2 value2="Value2">
<SubElement3>SubElement3</SubElement3>
<SubElement4>SubElement4</SubElement4>
<NewElementInElement2>
<NewSubelementInElement2>NewSubelementInElement2</NewSubelementInElement2>
</NewElementInElement2>
</Element2>
<NewElement>
<NewSubelement>NewSubelement</NewSubelement>
</NewElement>
</TreeRoot>
Ссылки по теме




