Объектная оболочка Python для lxml etree?

#python #xml #lxml

#python #xml #lxml

Вопрос:

С учетом lxml.etree возможно ли каким-либо образом создать объектное представление дерева, чтобы к вложенным элементам можно было обращаться объектно-подобным образом (с помощью оператора ‘.’)?

Я знаю, что в lxml есть библиотека под названием objectify, но, похоже, ее можно создать только с учетом необработанного XML, а для добавления новых элементов в дерево все еще требуется пройти через создание узла, подобного etree.

В идеале то, чего я хочу достичь, это:

 tree = objectify( etree_root )
print tree.somenode.get( 'attrib_name' )
tree.somenode.set( 'attrib_name', 'some_val' )
Node( tree.somenode, "somechild" )
tree.somenode.somechild.set( 'attrib', 'foo' ) 
  

Ответ №1:

Я думаю, вам нужно переопределить __setattribute__ соответственно __getattribute__ операторы. Я думаю, вам нужно создать подкласс etree.Класс элемента для достижения этого.

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

Для поиска элементов вы также можете использовать выражения XPath, которые соответствуют вашей идее. API выглядит следующим образом:

 subchild = root.find('child/subchild')
  

Комментарии:

1. Не совсем непрактично. С помощью некоторых разумных изменений вы можете сделать его полезным для некоторых типов данных. Вы можете переопределить __get_attribute__ таким образом, что если node.childname на него ссылаются, он будет возвращать только к первому дочернему элементу, но для `node.childnames (с ‘s’ в конце) он вернет их список. Действительно ли этот дизайн полезен или нет, зависит от ваших XML-данных.

2. Спасибо за совет. На самом деле это проще, чем я думал. Мне удалось объективизировать каждый элемент в довольно большом XML-дереве (~ 20 мс). Это позволяет делать такие вещи, как: root.child.nonexistentchild[ "attrib" ] = "hello" Это создает nonexistentchild на лету и добавляет атрибут attrib со значением hello . Требуется просто переопределение __setattr__ , __getattr__ , __get__ __set__ . Затем вы просто создаете объективированное дерево, беря каждый узел и создавая объектную оболочку для каждого родственного элемента.

3. аккуратно 🙂 случайно, нельзя ли откуда-нибудь взять код?

4. Нет, боюсь, по юридическим причинам я не могу этого сделать. Одна вещь, с которой следует быть осторожным, — это последовательности. Поскольку при объективизации вы не утверждаете в схеме XSD, если в исходном XML-дереве есть один элемент, у вас нет способа узнать, является ли он частью последовательности или нет. Вы можете обойти это, предоставив метод для «преобразования» в последовательность, если требуется.