【问题标题】:Check if XML Element has children or not, in ElementTree检查 XML 元素是否有子元素,在 ElementTree
【发布时间】:2014-11-15 00:50:46
【问题描述】:

我以这种方式检索 XML 文档:

import xml.etree.ElementTree as ET

root = ET.parse(urllib2.urlopen(url))
for child in root.findall("item"):
  a1 = child[0].text # ok
  a2 = child[1].text # ok
  a3 = child[2].text # ok
  a4 = child[3].text # BOOM
  # ...

XML 如下所示:

<item>
  <a1>value1</a1>
  <a2>value2</a2>
  <a3>value3</a3>
  <a4>
    <a11>value222</a11>
    <a22>value22</a22>
  </a4>
</item>

我如何检查a4(在这种特殊情况下,但它可能是任何其他元素)是否有孩子?

【问题讨论】:

    标签: python xml elementtree children


    【解决方案1】:

    您可以尝试在元素上使用list 函数:

    >>> xml = """<item>
      <a1>value1</a1>
      <a2>value2</a2>
      <a3>value3</a3>
      <a4>
        <a11>value222</a11>
        <a22>value22</a22>
      </a4>
    </item>"""
    >>> root = ET.fromstring(xml)
    >>> list(root[0])
    []
    >>> list(root[3])
    [<Element 'a11' at 0x2321e10>, <Element 'a22' at 0x2321e48>]
    >>> len(list(root[3]))
    2
    >>> print "has children" if len(list(root[3])) else "no child"
    has children
    >>> print "has children" if len(list(root[2])) else "no child"
    no child
    >>> # Or simpler, without a call to list within len, it also works:
    >>> print "has children" if len(root[3]) else "no child"
    has children
    

    我修改了您的示例,因为 item 根上的 findall 函数调用不起作用(因为 findall 将搜索直接后代,而不是当前元素)。如果你想在你的工作程序中访问子孩子的文本,你可以这样做:

    for child in root.findall("item"):
      # if there are children, get their text content as well.
      if len(child): 
        for subchild in child:
          subchild.text
      # else just get the current child text.
      else:
        child.text
    

    不过,这非常适合递归。

    【讨论】:

    • 不起作用。你能用我的例子来迭代吗?
    • 它不起作用,因为您的迭代循环不会产生任何元素,因为没有名为“item”的元素
    • 如何获得“”和“”元素?
    • 它有效,检查这个 pythonfiddle:pythonfiddle.com/check-if-element-has-children-or-not 否则告诉我究竟是什么不起作用。您的示例不起作用,因此我对其进行了修改。让我修改我的答案,告诉你如何访问子孩子。
    【解决方案2】:

    我能找到的最简单的方法是直接使用元素的bool 值。这意味着您可以在条件语句中按原样使用a4

    a4 = Element('a4')
    if a4:
        print('Has kids')
    else:
        print('No kids yet')
    
    a4.append(Element('x'))
    if a4:
        print('Has kids now')
    else:
        print('Still no kids')
    

    运行此代码将打印

    No kids yet
    Has kids now
    

    一个元素的布尔值不会说明texttail 或属性。它只表示有没有孩子,这是原始问题所要问的。

    【讨论】:

      【解决方案3】:

      我个人建议您使用完全支持 xpath 表达式的 xml 解析器。 subset supported by xml.etree 不足以完成此类任务。

      例如在lxml我可以这样做:

      “给我&lt;item&gt;节点的所有子节点”:

      doc.xpath('//item/*/child::*') #equivalent to '//item/*/*', if you're being terse
      Out[18]: [<Element a11 at 0x7f60ec1c1348>, <Element a22 at 0x7f60ec1c1888>]
      

      或者,

      “把&lt;item&gt;自己没有孩子的所有孩子都给我”:

      doc.xpath('/item/*[count(child::*) = 0]')
      Out[20]: 
      [<Element a1 at 0x7f60ec1c1588>,
       <Element a2 at 0x7f60ec1c15c8>,
       <Element a3 at 0x7f60ec1c1608>]
      

      或者,

      “给我所有没有子元素的元素”:

      doc.xpath('//*[count(child::*) = 0]')
      Out[29]: 
      [<Element a1 at 0x7f60ec1c1588>,
       <Element a2 at 0x7f60ec1c15c8>,
       <Element a3 at 0x7f60ec1c1608>,
       <Element a11 at 0x7f60ec1c1348>,
       <Element a22 at 0x7f60ec1c1888>]
      
      # and if I only care about the text from those nodes...
      doc.xpath('//*[count(child::*) = 0]/text()')
      Out[30]: ['value1', 'value2', 'value3', 'value222', 'value22']
      

      【讨论】:

      • 建议 lxml 假设存在性能问题并且缺少 xpath 功能。它肯定比 ElementTree 好,但如果后者没有问题,我不会这样做,特别是考虑到 lxml 需要安装,而且它并不总是在公园里散步。
      • 性能是一回事,是的,但是完整的 xpath 支持意味着您可以在一个紧凑的地方完成所有选择节点的工作。 xpath 查询需要我几秒钟的时间来编写;编写 python 代码来遍历树并选择我想要的节点需要更长的时间并且更容易产生错误。除了性能之外,还有很多好处。
      【解决方案4】:

      可以用很简单的方法

      list(<element>)
      

      如果列表为空,则那里没有孩子。

      【讨论】:

        【解决方案5】:

        你可以使用iter方法

        import xml.etree.ElementTree as ET
        
        etree = ET.parse('file.xml')
        root = etree.getroot()
        a = []
        for child in root.iter():
            if child.text:
                if len(child.text.split()) > 0:
                    a.append(child.text)
        print(a)
        

        【讨论】:

          【解决方案6】:

          元素类有get children方法。所以你应该使用这样的东西来检查是否有孩子并通过 key=tag name 将结果存储在字典中:

          result = {}
          for child in root.findall("item"):
             if child.getchildren() == []:
                result[child.tag] = child.text
          

          【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-02-21
          • 1970-01-01
          • 2011-04-14
          • 1970-01-01
          • 2022-12-16
          • 2010-09-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多