Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python xml.etree.ElementTree与lxml.etree:不同的内部节点表示形式?_Python_Xml_Python 3.x_Lxml_Elementtree - Fatal编程技术网

Python xml.etree.ElementTree与lxml.etree:不同的内部节点表示形式?

Python xml.etree.ElementTree与lxml.etree:不同的内部节点表示形式?,python,xml,python-3.x,lxml,elementtree,Python,Xml,Python 3.x,Lxml,Elementtree,我一直在将一些原始的xml.etree.ElementTree(ET)代码转换为lxml.etree(lxmlET)。幸运的是,两者之间有很多相似之处。然而,我确实偶然发现了一些我在任何文档中都找不到的奇怪行为。它考虑子节点的内部表示 在ET中,iter()用于迭代元素的所有子代,可以选择按标记名过滤。因为我在文档中找不到关于这方面的任何细节,所以我希望lxmlET也有类似的行为。问题是,通过测试,我得出结论,在lxmlET中,有一个不同的树的内部表示 在下面的示例中,我迭代树中的节点并打印每个

我一直在将一些原始的
xml.etree.ElementTree
ET
)代码转换为
lxml.etree
lxmlET
)。幸运的是,两者之间有很多相似之处。然而,我确实偶然发现了一些我在任何文档中都找不到的奇怪行为。它考虑子节点的内部表示

在ET中,
iter()
用于迭代元素的所有子代,可以选择按标记名过滤。因为我在文档中找不到关于这方面的任何细节,所以我希望lxmlET也有类似的行为。问题是,通过测试,我得出结论,在lxmlET中,有一个不同的树的内部表示

在下面的示例中,我迭代树中的节点并打印每个节点的子节点,但除此之外,我还创建这些子节点的所有不同组合并打印这些子节点。这意味着,如果一个元素有子元素
('A','B','C')
我会创建更改,即树
[('A'),('A','B'),('A','C'),('B'),('B','C'),('C')]

但是,当您使用
lxml
模块而不是
xml
(取消对lxmlET的导入的注释,并对ET的导入进行注释)并运行代码时,您将看到输出是

2-3
2
3
node 2 has no children
因此,不会访问更深的子代节点。这可以通过以下两种方式来避免:

  • 使用
    deepcopy
    (在
    get\u composition\u trees()
    中注释/取消注释相关部分),或
  • parse_xml()
    中为node.xpath('.//node')中的子节点使用
    ,而不是
    iter()
  • 所以我知道有办法解决这个问题,但我主要想知道发生了什么调试这个花了我很多时间,我找不到任何文档。这两个模块之间到底有什么区别?在处理非常大的树时,最有效的解决方法是什么?

    复制问题 通常,当您操作XML树并希望在树中的多个位置复制信息时(通过反对将信息从一个位置移动到另一个位置),安全的做法是是对这些元素执行深度复制操作,而不仅仅是将它们添加到它们的新位置。绝大多数生成树的XML解析库都要求执行深度复制,如果您想复制周围的结构。如果你不深度复制,他们就不会给你想要的结果
    lxml
    就是这样一个库,它要求您深度复制要复制的结构

    在我的经验中,
    xml.etree.ElementTree
    的工作方式使得
    .append
    有效地允许您在树中的两个位置拥有相同的元素,这一事实肯定是不寻常的

    边走边修改问题 您提到node.xpath('.//node')中的子节点的
    也解决了这个问题。请注意,如果对列表中的子节点(node.iter('node'))使用
    ,则会得到相同的结果。这里的情况是,使用
    list(node.iter('node'))
    node.xpath('.//node')
    或使用
    deepcopy
    复制节点而不是移动节点,可以防止代码出现另一个问题:您在修改结构时正在遍历它。

    iter('node')
    创建一个迭代器,在迭代XML结构时遍历它。如果将其包装在
    list()
    中,则会立即遍历该结构,并将结果放入列表中。因此,在行走之前,您已经有效地拍摄了结构的快照。这样可以防止行走操作受到树更改的影响。如果执行
    node.xpath('.//node')
    操作,则在遍历树之前还将获取树的快照,因为该方法返回节点列表。如果对节点执行
    deepcopy
    ,并附加节点的副本,而不是附加原始节点,则在遍历树时不会修改正在遍历的树

    使用XPath还是使用
    node.XPath('.//node')
    而不是使用
    deepcopy
    取决于您打算如何处理组合。您在问题中显示的代码会在您创建组合后立即将其打印到屏幕上。打印时它们看起来很好,但是如果不使用
    deepcopy
    来创建它们,那么一旦创建新组合,旧组合就会混乱,因为出现在旧组合中并且需要出现在新组合中的任何节点都将被移动而不是复制


    在处理非常大的树木时,最有效的方法是什么

    这取决于应用程序的具体情况和需要解析的数据。您给出了一个示例,它是一个小文档,但您询问的是“大树”。适用于小文档的内容不一定会转移到大文档。您可以针对案例X进行优化,但如果案例X在实际数据中很少发生,那么您的优化可能不会成功。在某些情况下,它实际上可能是有害的

    在我的一个应用程序中,我必须用结构本身替换对某些结构的引用。一个简化的示例是一个包含
    ..
    等元素和
    等引用的文档。
    ref
    的每个实例都必须替换为它所指向的
    define
    。通常,这可能意味着多次复制单个
    define
    ,但有时一个
    define
    可能只被一个
    ref
    引用,因此一个优化是在只有一个引用的情况下检测到这一点并跳过深度复制。我得到这个优化“免费”,因为应用程序
    2-3
    2
    3
    node 2 has no children
    4-6
    4
    6
    5
    node 5 has no children
    node 6 has no children
    
    2-3
    2
    3
    node 2 has no children
    
    def append(self, subelement):
        """Add *subelement* to the end of this element.
        The new element will appear in document order after the last existing
        subelement (or directly after the text, if it's the first subelement),
        but before the end tag for this element.
        """
        self._assert_is_element(subelement)
        self._children.append(subelement)
    
    self._children = []
    
    def append(self, _Element element not None):
        u"""append(self, element)
        Adds a subelement to the end of this element.
        """
        _assertValidNode(self)
        _assertValidNode(element)
        _appendChild(self, element)
    
    cdef int _appendChild(_Element parent, _Element child) except -1:
        u"""Append a new child to a parent element.
        """
        c_node = child._c_node
        c_source_doc = c_node.doc
        # prevent cycles
        if _isAncestorOrSame(c_node, parent._c_node):
            raise ValueError("cannot append parent to itself")
        # store possible text node
        c_next = c_node.next
        # move node itself
        tree.xmlUnlinkNode(c_node)
        tree.xmlAddChild(parent._c_node, c_node)
        _moveTail(c_next, c_node)
        # uh oh, elements may be pointing to different doc when
        # parent element has moved; change them too..
        moveNodeToDocument(parent._doc, c_source_doc, c_node)
        return 0