Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Создание XML




ElementTree умеет не только разбирать существующие XML документы, но и создавать их «с нуля».

> > > import xml. etree. ElementTree as etree> > > new_feed = etree. Element('{http: //www. w3. org/2005/Atom}feed', ①... attrib={'{http: //www. w3. org/XML/1998/namespace}lang': 'en'}) ② > > > print(etree. tostring(new_feed))                              ③ < ns0: feed xmlns: ns0='http: //www. w3. org/2005/Atom' xml: lang='en'/>

① Для создания нового элемента необходимо создать объект класса Element. В качестве первого параметра в конструктор мы передаём имя элемента (пространство имён и локальное имя). Данное выражение создаёт элемент feed в пространстве Atom. Этот будет корневой элемент нашего нового документа XML.

② Для того чтобы добавить атрибуты к создаваемому элементу мы передаём словарь имён атрибутов и их значений в втором аргументе attrib. Заметьте, что имена атрибутов должны задаваться в формате ElementTree {пространство_имён}локальное_имя.

③ В любой момент Вы можете сериализовать элемент и его подэлементы используя функцию tostring() библиотеки ElementTree.

Вы удивлены результату сериализации new_feed? Формально ElementTree сериализует XML элементы правильно, но не оптимально. Пример XML документа в начале главы определён в пространстве по умолчанию xmlns='http: //www. w3. org/2005/Atom'. Определение пространства по умолчанию полезно для документов (например, фидов Atom), где все элементы принадлежат одному пространству, то есть Вы можете объявить пространство один раз, а на элементы ссылаться используя локальное имя (< feed>, < link>, < entry> ). Если Вы не собираетесь объявлять элементы из другого пространства имён, то нет необходимости использовать префикс пространства по умолчанию.

Синтаксический анализатор XML не «заметит» разницы между документом XML с пространством по умолчанию и документом с использованием префикса пространства имён перед каждым элементом. Результирующая модель DOM данной сериализации выглядит как

< ns0: feed xmlns: ns0='http: //www. w3. org/2005/Atom' xml: lang='en'/>

что равнозначно

< feed xmlns='http: //www. w3. org/2005/Atom' xml: lang='en'/>

Единственная разница в том, что второй вариант на несколько символов короче. Если мы переделаем наш пример с использованием префикса ns0: в каждом открывающем и закрывающем тэгах, это добавило бы 4 символа на открывающий тэг × 79 тэгов + 4 символа на объявление собственно пространства имён, всего 320 символов. В кодировке UTF-8 это составило бы 320 байт. (После архивации gzip разница уменьшается до 21 байта; однако 21 байт это 21 байт). Возможно, Вы бы не обратили внимания на эти десятки байтов, но для фидов Atom, которые загружаются тысячу раз при изменении, выигрыш нескольких байт на одном запросе быстро превращается в килобайты.

Ещё одно преимущество lxml: в отличие от стандартной библиотеки ElementTree lxml предоставляет более тонкое управление сериализацией элементов.

> > > import lxml. etree> > > NSMAP = {None: 'http: //www. w3. org/2005/Atom'}                ① > > > new_feed = lxml. etree. Element('feed', nsmap=NSMAP)           ② > > > print(lxml. etree. tounicode(new_feed))                        ③ < feed xmlns='http: //www. w3. org/2005/Atom'/> > > > new_feed. set('{http: //www. w3. org/XML/1998/namespace}lang', 'en') ④ > > > print(lxml. etree. tounicode(new_feed))< feed xmlns='http: //www. w3. org/2005/Atom' xml: lang='en'/>

① Для начала определим пространство имён используя словарь. Значения словаря и есть пространство имён; ключи словаря - задаваемый префикс. Используя объект None в качестве префикса мы задаём пространство имён по умолчанию.

② При создании элемента мы передаём специфичный для lxml аргумент nsmap, используемый для передачи префиксов пространств имён.

③ Как и ожидали, при сериализации определено пространство имён по умолчанию Atom и объявлен один элемент feed без префикса пространства имён.

④ Опа, мы забыли добавить атрибут xml: lang. Используя метод set(), можно всегда добавить атрибут к любому элементу. Метод принимает два аргумента: имя атрибута в стандартном формате ElementTree и значение атрибута. (Данный метод есть и в библиотеке ElementTree. Единственное отличие lxml и ElementTree в данном примере это передача аргумента nsmap для указания префиксов пространств имён. )

Разве наши документы ограничены только одним элементом? Конечно, нет. Мы можем запросто создать дочерние элементы.

> > > title = lxml. etree. SubElement(new_feed, 'title',      ①... attrib={'type': 'html'})                          ② > > > print(lxml. etree. tounicode(new_feed))                ③ < feed xmlns='http: //www. w3. org/2005/Atom' xml: lang='en'> < title type='html'/> < /feed> > > > title. text = 'dive into & hellip; '                    ④ > > > print(lxml. etree. tounicode(new_feed))                ⑤ < feed xmlns='http: //www. w3. org/2005/Atom' xml: lang='en'> < title type='html'> dive into & amp; hellip; < /title> < /feed> > > > print(lxml. etree. tounicode(new_feed, pretty_print=True)) ⑥ < feed xmlns='http: //www. w3. org/2005/Atom' xml: lang='en'> < title type='html'> dive into& amp; hellip; < /title> < /feed>

① Для создания подэлемента существующего элемента необходимо создать объект класса SubElement. В конструктор класса передаются элемент родителя (в данном случае new_feed) и имя нового элемента. Мы не объявляем заново пространство имён для создаваемого потомка, так как он наследует пространство имён от родителя.

② Также мы передаём словарь с атрибутами для элемента. В качестве имён атрибутов выступают ключи словаря, в качестве значений атрибутов - значения словаря.

③ Неудивительно, что новый элемент title был создан в пространстве Atom и является подэлементом элемента feed. Так как элемент title не имеет текстового содержания и подэлементов, то lxml сериализует его как пустой элемент и закрывает символами />.

④ Для того чтобы добавить текстовое содержание, мы задаём свойство. text.

⑤ Теперь элемент title сериализуется с только что заданным текстовым содержанием. Если в тексте содержатся знаки «меньше чем» < или «амперсанд» ', то при сериализации они должны быть экранированы escape-последовательностью. Такие ситуации lxml обрабатывает автоматически.

⑥ При сериализации Вы можете применить «приятную печать» («pretty printing»), при которой вставляется разрыв строки после закрывающего тэга или открывающего тэга элементов с подэлементами но без текстового содержания. С технической точки зрения lxml добавляет незначащие пробелы и переносы строк («insignificant whitespace») чтобы вывести XML более читаемым.

Вам, возможно, будет интересно попробовать ещё одну стороннюю библиотеку xmlwitch, которая повсеместно использует оператор Python with для того чтобы сделать код создания XML более читаемым.
Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...