使用ElementTree解析XML时使用命名空间

时间:2014-07-31 22:47:38

标签: python xml lxml elementtree celementtree

这是Modify a XML using ElementTree

的问题

我现在在我的XML中使用了命名空间,并尝试在Parsing XML with namespace in Python via 'ElementTree'处理解答案并获得以下内容。

XML文件。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <grandParent>
  <parent>
   <child>Sam/Astronaut</child>
  </parent>
 </grandParent>
</project>

查看Parsing XML with namespace in Python via 'ElementTree'后的我的python代码

import xml.etree.ElementTree as ET

spaces='xmlns':'http://maven.apache.org/POM/4.0.0','schemaLocation':'http://maven.apache.org/xsd/maven-4.0.0.xsd'}

tree = ET.parse("test.xml")
a=tree.find('parent')          
for b in a.findall('child', namespaces=spaces):
 if b.text.strip()=='Jay/Doctor':
    print "child exists"
    break
else:
    ET.SubElement(a,'child').text="Jay/Doctor"

tree.write("test.xml")

我收到错误:  AttributeError:&#39; NoneType&#39;对象没有属性&#39; findall&#39;

1 个答案:

答案 0 :(得分:2)

这一行有两个问题:

a=tree.find('parent')          

首先,<parent>不是根元素的直接子元素。 <parent>是根元素的孙子。父路径看起来像/project/grandparent/parent。要搜索<parent>,请尝试使用XPath表达式*/parent或可能//parent

其次,<parent>存在于默认命名空间中,因此您只能使用其简单名称来.find()它。您需要添加命名空间。

以下是对tree.find()的两个同等有效的调用,每个调用都应找到<parent>节点:

a=tree.find('*/{http://maven.apache.org/POM/4.0.0}parent')
a=tree.find('*/xmlns:parent', namespaces=spaces)

接下来,对findall()的调用需要名称空间限定符:

for b in a.findall('xmlns:child', namespaces=spaces) 

第四,创建新子元素的调用需要命名空间限定符。可能有一种方法可以使用快捷方式名称,但我找不到它。我不得不使用长名称。

ET.SubElement(a,'{http://maven.apache.org/POM/4.0.0}child').text="Jay/Doctor"

最后,除非您提供默认命名空间,否则您的XML输出看起来很难看:

tree.write('test.xml', default_namespace=spaces['xmlns'])

与XML方面无关,您错误地复制了上一个问题的答案。 else的{​​{1}}与for对齐,而不与if

对齐
for ...
  if ...
else ...