Примечание:
Следует заметить, что в отличие от HTML, в XML одиночные (непарные) теги записываются с косой чертой:
, а атрибуты — в кавычках. В XML имеет значение регистр букв в названиях тегов и атрибутов.
Формирование XML–документа
Концептуально существуют два пути обработки XML–документа: последовательная обработка и работа с объектной моделью документа.
В первом случае обычно используется SAX (Simple API for XML, простой программный интерфейс для XML). Работа SAX заключается в чтении источников данных (input source) XML–анализаторами (XML–reader) и генерации последовательности событий (events), которые обрабатываются объектами–обработчиками (handlers). SAX дает последовательный доступ к XML–документу.
Во втором случае анализатор XML строит DOM (Document Object Model, объектная модель документа), предлагая для XML–документа конкретную объектную модель. В рамках этой модели узлы DOM–дерева доступны для произвольного доступа,а для переходов между узлами предусмотрен ряд методов.
Можно применить оба этих подхода для формирования приведенного выше XML–документа.
С помощью SAX документ сформируется так:
Листинг
import sys
from xml.sax.saxutils import XMLGenerator
g = XMLGenerator(sys.stdout)
g.startDocument()
g.startElement(«expression», {})
g.startElement(«operation», {«type»: «+»})
g.startElement(«operand», {})
g.characters(«2»)
g.endElement(«operand»)
g.startElement(«operand», {})
g.startElement(«operation», {«type»: "*"})
g.startElement(«operand», {})
g.characters(«3»)
g.endElement(«operand»)
g.startElement(«operand», {})
g.characters(«4»)
g.endElement(«operand»)
g.endElement(«operation»)
g.endElement(«operand»)
g.endElement(«operation»)
g.endElement(«expression»)
g.endDocument()
Построение дерева объектной модели документа может выглядеть, например, так:
Листинг
from xml.dom import minidom
dom = minidom.Document()
e1 = dom.createElement(«expression»)
dom.appendChild(e1)
p1 = dom.createElement(«operation»)
p1.setAttribute('type', '+')
x1 = dom.createElement(«operand»)
x1.appendChild(dom.createTextNode(«2»))
p1.appendChild(x1)
e1.appendChild(p1)
p2 = dom.createElement(«operation»)
p2.setAttribute('type', '*')
x2 = dom.createElement(«operand»)
x2.appendChild(dom.createTextNode(«3»))
p2.appendChild(x2)
x3 = dom.createElement(«operand»)
x3.appendChild(dom.createTextNode(«4»))
p2.appendChild(x3)
x4 = dom.createElement(«operand»)
x4.appendChild(p2)
p1.appendChild(x4)
print dom.toprettyxml()
Легко заметить, что при использовании SAX команды на генерацию тегов и других частей выдаются последовательно, а вот построение одной и той же DOM можно выполнять различными последовательностями команд формирования узла и его соединения с другими узлами.
Конечно, указанные примеры носят довольно теоретический характер, так как на практике строить XML–документы таким образом обычно не приходится.
Анализ XML–документа
Для работы с готовым XML–документом нужно воспользоваться XML–анализаторами. Анализ XML–документа с порождением объекта класса Document происходит всего в одной строчке, с помощью функции parse(). Здесь стоит заметить, что кроме стандартного пакета xml можно поставить пакет PyXML или альтернативные коммерческие пакеты. Тем не менее, разработчики стараются придерживаться единого API, который продиктован стандартом DOM Level 2:
Листинг
import xml.dom.minidom
dom = xml.dom.minidom.parse(«expression.xml»)
dom.normalize()
def output_tree(node, level=0):
if node.nodeType == node.TEXT_NODE:
if node.nodeValue.strip():
print ". "*level, node.nodeValue.strip()
else: # ELEMENT_NODE или DOCUMENT_NODE
atts = node.attributes or {}
att_string = ", ".join(
["%s=%s " % (k, v) for k, v in atts.items()])
print ". "*level, node.nodeName, att_string
for child in node.childNodes:
output_tree(child, level+1)
output_tree(dom)
В этом примере дерево выводится с помощью определенной функции output_tree(), которая принимает на входе узел и вызывается рекурсивно для всех вложенных узлов.
В результате получается примерно следующее:
Листинг
#document
. expression
. . operation type=+
… operand
… . 2
… operand
… . operation type=*
… . . operand
… … 3
… . . operand
… … 4
Здесь же применяется метод normalize() для того, чтобы все текстовые фрагменты были слиты воедино (в противном случае может следовать подряд несколько узлов с текстом).
Можно заметить, что даже в небольшом примере использовались атрибуты узлов: node.nodeType указывает тип узла, node.nodeValue применяется для доступа к данным, node.nodeName дает имя узла (соответствует названию тега), node.attributes дает доступ к атрибутам узла. node.childNodes применяется для доступа к дочерним узлам. Этих свойств достаточно, чтобы рекурсивно обойти дерево.
Все узлы являются экземплярами подклассов класса Node. Они могут быть следующих типов:
Название Описание Метод для создания
ELEMENT_NODE Элемент createElement(tagname)
ATTRIBUTE_NODE Атрибут createAttribute(name)
TEXT_NODE Текстовый узел createTextNode(data)
CDATA_SECTION_NODE Раздел CDATA
ENTITY_REFERENCE_NODE Ссылка на сущность
ENTITY_NODE Сущность
PROCESSING_INSTRUCTION_NODE Инструкция по обработке createProcessingInstruction(target, data)
Читать дальше