【问题标题】:Parse all but a few nodes with certain attribute values解析除少数具有特定属性值的节点之外的所有节点
【发布时间】:2015-04-27 02:28:48
【问题描述】:

使用 elementtree,有没有一种简单的方法来解析整个 xml 文档,除了那些在具有某些特定属性值的节点上的文本。作为一个例子,我想解析文件,除了属性name="Liechtenstein"和属性month="08"

<data>
    <country name="Liechtenstein">
        <rank updated="yes">2</rank>
        <language>english</language>
        <currency>1.21$/kg</currency> 
        <gdppc month="06">141100</gdppc>
        <gdpnp month="10">2.304e+0150</gdpnp>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
    <country name="Singapore">
        <rank updated="yes">5</rank>
        <language>english</language>
        <currency>4.1$/kg</currency> 
        <gdppc month="05">59900</gdppc>
        <gdpnp month="08">5.2e-015</gdpnp>
        <neighbor name="Malaysia" direction="N"/>
    </country>
    <country name="Lahore">
        <rank updated="yes">8</rank>
        <language>Pertr</language>
        <currency>7.3$/kg</currency> 
        <gdppc month="010">34000</gdppc>
        <gdpnp month="099">3.4e+015</gdpnp>
        <neighbor name="Peru" direction="N"/>
    </country>
</data>

基于以上,我想返回以下5english4.1$/kg599008Pertr7.3$/kg340003.4e+015 .我觉得可以使用iterparse,但我不知道该怎么做。 感谢您的建议

【问题讨论】:

  • 你是在使用import xml.etree.ElementTree解析??
  • 是的 vivek,问题是我需要动态地执行此操作,并且 xml 嵌套很深。不需要的名称和属性可以位于任何层次结构中,而不是此处显示的特定顺序。有没有办法像在 xpath 中使用 elementtree 那样做//*[not(@08 or 09 or 10)]
  • 是的,只需在列表中添加忽略值,即 `["08", "09", "10"]`。但是你能剪切有效的测试用例,即stackoverflow上的输入和相应的输出,或者给我发电子邮件vivekbsable@gmail.com ??

标签: python xml xml-parsing elementtree


【解决方案1】:
  1. 使用xml.etree.ElementTree 模块解析XML 内容。
  2. 使用getiterator()方法只迭代country标签。
  3. 验证country 标签。
  4. 通过getchildren() 方法在选定的country 标签上迭代子代。
  5. 验证孩子的月份验证。
  6. 在 tmp 列表中添加值。
  7. 将 tmp 附加到主结果列表。

代码:

import xml.etree.ElementTree as PARSER
root = PARSER.fromstring(data)
result = []
for i in root.getiterator("country"):
    if  "name" in i.attrib and i.attrib["name"] not in ["Liechtenstein"]:
        tmp = []
        for j in i.getchildren():
            if "month" in j.attrib:
                if j.attrib["month"] not in ["08"]:
                    if j.text:
                        tmp.append(j.text)
            else:
                if j.text:
                    tmp.append(j.text)

        result.append(tmp)


print "result:-", result

输出:

:~/workspace/vivek$ python test3.py 
result:- [['5', 'english', '4.1$/kg', '59900'], ['8', 'Pertr', '7.3$/kg', '34000', '3.4e+015']]

lxml 模块

使用xpath()方法获取目标country标签。

代码:

import lxml.html as PARSER
root = PARSER.fromstring(data)
result = []
print "debug 1 list of country: ", root.xpath("//country[@name!='Liechtenstein']")
for i in root.xpath("//country[@name!='Liechtenstein']"):
        tmp = []
        for j in i.getchildren():
            if "month" in j.attrib:
                if j.attrib["month"] not in ["08"]:
                    if j.text:
                        tmp.append(j.text)
            else:
                if j.text:
                    tmp.append(j.text)

        result.append(tmp)


print "result:-", result

结果:

:~/workspace/vtestproject$ python test3.py 
debug 1 list of country:  [<Element country at 0xb724da04>, <Element country at 0xb7257cac>]
result:- [['5', 'english', '4.1$/kg', '59900'], ['8', 'Pertr', '7.3$/kg', '34000', '3.4e+015']]

【讨论】: