2013-11-21 4 views
0

У меня есть следующий код, который работает:Есть ли лучший способ дать элементы Knowlege своих родителей и в xml.etree.ElementTree XPath

import xml.etree.ElementTree as etree 


def get_path(self): 
    parent = '' 
    path = self.tag 
    sibs = self.parent.findall(self.tag) 
    if len(sibs) > 1: 
     path = path + '[%s]'%(sibs.index(self)+1) 
    current_node = self 
    while True: 
     parent = current_node.parent 
     if not parent: 
      break 
     ptag = parent.tag 
     path = ptag + '/' + path 
     current_node = parent 
    return path 

etree._Element.get_path = get_path 
etree._Element.parent = None 

class XmlDoc(object): 
    def __init__(self): 
     self.root = etree.Element('root') 
     self.doc = etree.ElementTree(self.root) 

    def SubElement(self, parent, tag): 
     new_node = etree.SubElement(parent, tag) 
     new_node.parent = parent 
     return new_node 

doc = XmlDoc() 
a1 = doc.SubElement(doc.root, 'a') 
a2 = doc.SubElement(doc.root, 'a') 
b = doc.SubElement(a2, 'b') 
print etree.tostring(doc.root), '\n' 
print 'element:'.ljust(15), a1 
print 'path:'.ljust(15), a1.get_path() 
print 'parent:'.ljust(15), a1.parent, '\n' 
print 'element:'.ljust(15), a2 
print 'path:'.ljust(15), a2.get_path() 
print 'parent:'.ljust(15), a2.parent, '\n' 
print 'element:'.ljust(15), b 
print 'path:'.ljust(15), b.get_path() 
print 'parent:'.ljust(15), b.parent 

Какие результаты этого вывода:

<root><a /><a><b /></a></root> 

element:  <Element a at 87e3d6c> 
path:   root/a[1] 
parent:   <Element root at 87e3cec> 

element:  <Element a at 87e3fac> 
path:   root/a[2] 
parent:   <Element root at 87e3cec> 

element:  <Element b at 87e758c> 
path:   root/a/b 
parent:   <Element a at 87e3fac> 

Теперь это радикально изменилось с исходного кода, но мне не разрешено делиться этим.

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

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

Просто, чтобы сообщить вам, я думаю, что в качестве последнего средства, использующего выбранную статическую типизацию и для компиляции с помощью cython, я думаю, но по определенным причинам я действительно не хочу этого делать.

Спасибо, что посмотрели.

EDIT: Извините за неправильное использование термина позднего связывания. Иногда мой словарь оставляет желать лучшего. Я имел в виду «обезглавливание обезьян».

EDIT: @Corley Brigman, Guy: Большое спасибо за ваши ответы, которые решают вопрос, однако (и я должен был указать это в исходном сообщении). Я завершил этот проект, прежде чем использовать lxml, который является замечательным библиотека, которая сделала кодирование легким, но из-за новых требований (это должно быть реализовано как аддон к продукту под названием Splunk), который связывает меня с интерпретатором python 2.7, поставляемым с Splunk, и исключает возможность добавления сторонних библиотек, за исключением Джанго.

+0

Когда вы говорите, «позднее связывание», вы на самом деле со ссылкой на обезьяну -patching 'etree._Element' с помощью дополнительного метода? – user4815162342

+0

@ user4815162342 Благодарим вас за исправление. Я задал вопрос, потому что ты прав. – iLoveTux

+0

Хм, вам нужно что-то другое. Вы пытались просто вывести класс из cElementTree.Element/SubElement? Если вы вызываете 'etree.parse' и т. Д., То необходимо использовать патч для обезьян. Но если вы сами генерируете элементы, я бы подумал, что это будет просто. Если вы используете _se_, используя синтаксический анализ, вы можете получить лучшую производительность, разрешив cElementTree его синтаксический анализ, а затем создайте свое собственное параллельное дерево (используя его элементы) с новыми типами + добавленные узлы. Я не знаю, как это повлияло на это. –

ответ

0

Если вам требуется, используйте вместо него lxml - он отслеживает родителей внутри, и по-прежнему C за кулисами, так что это очень быстро.

Однако ... следует помнить, что в отслеживании родителей есть компромисс, поскольку у данного узла может быть только один родитель. Обычно это не является проблемой, однако, если вы делаете что-то вроде следующего, вы получите разные результаты в cElementTree против LXML:

p = Element('x') 
q = Element('y') 
r = SubElement(p, 'z') 
q.append(r) 

cElementTree:

dump(p) 
<x><z /></x> 
dump(q) 
<y><z /></y> 

LXML:

dump(p) 
<x/> 
dump(q) 
<y> 
    <z/> 
</y> 

Поскольку родители отслеживаются, узел может иметь только одного родителя, очевидно. Как вы можете видеть, элемент rскопирован обоим деревьям в cElementTree и переработан/перемещен в lxml.

Возможно, существует только небольшое количество вариантов использования, когда это имеет значение, но что-то, о чем нужно помнить.

+0

Я принимаю этот ответ, потому что чувствую, что он отвечает на мой вопрос перед вторым редактированием. Если у кого есть какие-либо комментарии или другие ответы, я все равно буду их слушать. – iLoveTux

0

вы можете просто использовать XPath, например:

import lxml.html 

def get_path(): 
    for e in doc.xpath("//b//*"): 
     print e 

должны работать, не проверял, хотя ...