Python 在lxml树上迭代时向节点添加深度

Python 在lxml树上迭代时向节点添加深度,python,recursion,tree,lxml,Python,Recursion,Tree,Lxml,我想为每个节点添加一个深度,为此我提出了以下递归函数: import lxml.html def add_depth(node, depth = 0): node.depth = depth print(node.tag, node.depth) for n in node.iterchildren(): add_depth(n , depth + 1) html = """<html> <body>

我想为每个节点添加一个深度,为此我提出了以下递归函数:

import lxml.html

def add_depth(node, depth = 0):
    node.depth = depth
    print(node.tag, node.depth)
    for n in node.iterchildren(): 
        add_depth(n , depth + 1)

html = """<html>
            <body>
              <div>
                <a></a>
                <h1></h1>
              </div>
            </body>
          </html>"""

tree = lxml.html.fromstring(html)

add_depth(tree)

for x in tree.iter():
    print(x)
    if not hasattr(x, 'depth'):
        print('this should not happen', x)
突然,它确实起作用了。这段代码创建了一个巨大的列表,列出了所有元素及其旁边的深度(因此我可以对其进行排序)。即使在对原始树进行迭代时,这一次它们也有深度。但这一点效率都不高,我也不明白

@Maximoo

tree.depth = 0
for x in tree.iter(): 
    if x.getparent() is not None:
        x.depth = x.getparent().depth + 1

AttributeError: 'HtmlElement' object has no attribute 'depth'

这里有几个问题

  • 首先,您试图使递归函数具有 更新原始树的副作用。我不认为这是错误的 可能

  • 第二,您不想使用Python属性,您需要 使用使用
    x.attrib
    访问的xml属性

一段工作代码可能如下所示(这有点尴尬,因为我一直在将深度从string转换为int,因为xml属性不能是整数)。它不使用递归,但我认为这太过分了:

tree.attrib['depth'] = '0'
for x in tree.iter():
    if 'depth' not in x.attrib:
        x.attrib['depth'] = str(int(x.getparent().attrib['depth']) + 1)


print(lxml.html.tostring(tree).decode())

<html depth="0">
            <body depth="1">
              <div depth="2">
                <a depth="3"></a>
                <h1 depth="3"></h1>
              </div>
            </body>
          </html>
tree.attrib['depth']=“0”
对于树中的x.iter():
如果x.attrib中没有“深度”:
x、 attrib['depth']=str(int(x.getparent().attrib['depth'])+1)
打印(lxml.html.tostring(tree.decode())

好吧,我已经看到了
attrib
(并且还看到它需要是一个字符串,而不是整数),但是我不想实际编辑“html”键values.Oh。如果您只想让节点具有Python属性,可以将代码更改为just
x.depth
试试。。。那是不起作用的东西!看看问题中的maxymoo注释部分。我认为设置
node.depth
不起作用的原因是树在某些其他数据结构中保存DOM,并且只在迭代时生成节点元素的副本。因此,修改
节点
不会修改
本身。
tree.attrib['depth'] = '0'
for x in tree.iter():
    if 'depth' not in x.attrib:
        x.attrib['depth'] = str(int(x.getparent().attrib['depth']) + 1)


print(lxml.html.tostring(tree).decode())

<html depth="0">
            <body depth="1">
              <div depth="2">
                <a depth="3"></a>
                <h1 depth="3"></h1>
              </div>
            </body>
          </html>