Можно ли указать ElementTree для сохранения порядка атрибутов?

Я написал довольно простой фильтр в python, используя ElementTree, чтобы настроить контексты некоторых xml-файлов. И это работает, более или менее.

Но он переупорядочивает атрибуты различных тегов, и я бы хотел, чтобы это не делалось.

Кто-нибудь знает переключатель, который я могу бросить, чтобы он держал их в определенном порядке?

Контекст для этого

Я работаю с инструментом физики частиц, который имеет сложную, но необычно ограниченную конфигурационную систему на основе xml-файлов. Среди множества настроек такой путь – это пути к различным статическим файлам данных. Эти пути жестко закодированы в существующий xml, и нет возможности устанавливать или изменять их на основе переменных среды, а в нашей локальной установке они обязательно находятся в другом месте.

Это не катастрофа, потому что комбинированный инструмент управления источником и сборкой, который мы используем, позволяет нам затенять определенные файлы локальными копиями. Но даже подумал, что поля данных статичны, а xml – нет, поэтому я написал скрипт для исправления путей, но с перестановкой атрибутов различия между локальной и главной версиями сложнее читать, чем необходимо.


Это мой первый раз, когда ElementTree для вращения (и только мой пятый или шестой проект python), поэтому, возможно, я просто делаю это неправильно.

Аннотация для простоты код выглядит следующим образом:

tree = elementtree.ElementTree.parse(inputfile) i = tree.getiterator() for e in i: e.text = filter(e.text) tree.write(outputfile) 

Разумный или немой?


Ссылки по теме:

  • Как я могу получить порядок списка атрибутов элементов с помощью Python xml.sax?
  • Сохранять порядок атрибутов при изменении с помощью мини-диска

6 Solutions collect form web for “Можно ли указать ElementTree для сохранения порядка атрибутов?”

С помощью ответа @ bobince и этих двух ( установка порядка атрибутов , переопределение методов модуля )

Мне удалось заразить эту обезьяну грязной, и я бы предложил использовать другой модуль, который лучше справляется с этим сценарием, но когда это не возможно:

 # ======================================================================= # Monkey patch ElementTree import xml.etree.ElementTree as ET def _serialize_xml(write, elem, encoding, qnames, namespaces): tag = elem.tag text = elem.text if tag is ET.Comment: write("<!--%s-->" % ET._encode(text, encoding)) elif tag is ET.ProcessingInstruction: write("<?%s?>" % ET._encode(text, encoding)) else: tag = qnames[tag] if tag is None: if text: write(ET._escape_cdata(text, encoding)) for e in elem: _serialize_xml(write, e, encoding, qnames, None) else: write("<" + tag) items = elem.items() if items or namespaces: if namespaces: for v, k in sorted(namespaces.items(), key=lambda x: x[1]): # sort on prefix if k: k = ":" + k write(" xmlns%s=\"%s\"" % ( k.encode(encoding), ET._escape_attrib(v, encoding) )) #for k, v in sorted(items): # lexical order for k, v in items: # Monkey patch if isinstance(k, ET.QName): k = k.text if isinstance(v, ET.QName): v = qnames[v.text] else: v = ET._escape_attrib(v, encoding) write(" %s=\"%s\"" % (qnames[k], v)) if text or len(elem): write(">") if text: write(ET._escape_cdata(text, encoding)) for e in elem: _serialize_xml(write, e, encoding, qnames, None) write("</" + tag + ">") else: write(" />") if elem.tail: write(ET._escape_cdata(elem.tail, encoding)) ET._serialize_xml = _serialize_xml from collections import OrderedDict class OrderedXMLTreeBuilder(ET.XMLTreeBuilder): def _start_list(self, tag, attrib_in): fixname = self._fixname tag = fixname(tag) attrib = OrderedDict() if attrib_in: for i in range(0, len(attrib_in), 2): attrib[fixname(attrib_in[i])] = self._fixtext(attrib_in[i+1]) return self._target.start(tag, attrib) # ======================================================================= 

Затем в вашем коде:

 tree = ET.parse(pathToFile, OrderedXMLTreeBuilder()) 

Неа. ElementTree использует словарь для хранения значений атрибутов, поэтому он по своей сути неупорядочен.

Даже DOM не гарантирует упорядочения атрибутов, а DOM предоставляет намного больше деталей XML-информации, чем ElementTree. (Есть некоторые DOM, которые предлагают это как функцию, но это не стандарт.)

Можно ли это исправить? Может быть. Вот удар, который заменяет словарь при разборе с упорядоченным ( collections.OrderedDict() ).

 from xml.etree import ElementTree from collections import OrderedDict import StringIO class OrderedXMLTreeBuilder(ElementTree.XMLTreeBuilder): def _start_list(self, tag, attrib_in): fixname = self._fixname tag = fixname(tag) attrib = OrderedDict() if attrib_in: for i in range(0, len(attrib_in), 2): attrib[fixname(attrib_in[i])] = self._fixtext(attrib_in[i+1]) return self._target.start(tag, attrib) >>> xmlf = StringIO.StringIO('<ab="c" d="e" f="g" j="k" h="i"/>') >>> tree = ElementTree.ElementTree() >>> root = tree.parse(xmlf, OrderedXMLTreeBuilder()) >>> root.attrib OrderedDict([('b', 'c'), ('d', 'e'), ('f', 'g'), ('j', 'k'), ('h', 'i')]) 

Выглядит потенциально многообещающим.

 >>> s = StringIO.StringIO() >>> tree.write(s) >>> s.getvalue() '<ab="c" d="e" f="g" h="i" j="k" />' 

Ба, сериализатор выводит их в каноническом порядке.

Это похоже на линию вины, в ElementTree._write :

  items.sort() # lexical order 

Подклассификация или патч обезьяны, которая будет раздражать, поскольку это правильно в середине большого метода.

Если вы не сделали что-то неприятное, как подкласс OrderedDict и взломать items чтобы вернуть специальный подкласс list который игнорирует вызовы sort() . Нет, наверное, это еще хуже, и я должен ложиться спать, прежде чем придумать что-нибудь более ужасное.

Неверный вопрос. Должно быть: «Где я могу найти гаджет diff который отлично работает с файлами XML?

Ответ: Google – ваш друг. Первый результат для поиска по «xml diff» => this . Есть еще несколько возможностей.

Из раздела 3.1 рекомендации XML :

Обратите внимание, что порядок спецификаций атрибутов в теге start-tag или теге элемента невелик.

Любая система, которая опирается на порядок атрибутов в элементе XML, сломается.

У вас была ваша проблема. Сначала искал сценарий Python для канонизации, не нашел никого. Затем начал думать о создании. Наконец xmllint решил.

Да, с lxml

 >>> from lxml import etree >>> root = etree.Element("root", interesting="totally") >>> etree.tostring(root) b'<root interesting="totally"/>' >>> print(root.get("hello")) None >>> root.set("hello", "Huhu") >>> print(root.get("hello")) Huhu >>> etree.tostring(root) b'<root interesting="totally" hello="Huhu"/>' 

Вот прямая ссылка на документацию, из которой приведенный выше пример слегка адаптирован.

Также обратите внимание, что lxml имеет, по своему усмотрению, хорошую совместимость API со стандартным xml.etree.ElementTree

  • Python BeautifulSoup XML Parsing
  • Как заказать атрибуты элемента xml в Python?
  • Потерянный в XML и Python
  • Напишите xml с указанием пути и значения
  • Использование urllib и minidom для извлечения данных XML
  • Как очистить XML-ленту с помощью xmlfeedspider
  • Работа с пространством имен при анализе XML с использованием ElementTree
  • Запись XML-файла с использованием библиотеки lxml в Python
  •  
    Interesting Posts for Van-Lav

    Ускорение scipy griddata для множественных интерполяций между двумя нерегулярными сетками

    Модули Python PostgreSQL. Что лучше?

    Как подсчитать количество файлов в каталоге с помощью Python

    Почему len (<a list object>) так медленно?

    Сельдерей: как ограничить количество заданий в очереди и прекратить кормить, когда они полны?

    запуск c ++-кода из python

    Как переформатировать блок данных с различными функциями, применяемыми к каждому столбцу?

    Есть ли эквивалент Python для Haskell 'let'

    Как я могу установить PATH для супервизора, чтобы найти исполняемые файлы

    Как торговать на пару с помощью python

    OSX: определение нового обработчика URL, который указывает прямо на скрипт Python

    Найдите дату понедельника с Python

    Почему urllib2.urlopen не может открывать такие страницы, как «http: // localhost / new-post # comment-29»?

    Возвращение сообщений об ошибках API с помощью Python и Flask

    ошибка из памяти при чтении файла csv в куске

    Python - лучший язык программирования в мире.