[英]Python: ElementTree, get the namespace string of an Element
此 XML 文件名为example.xml
:
<?xml version="1.0"?>
<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/maven-v4_0_0.xsd">
<modelVersion>14.0.0</modelVersion>
<groupId>.com.foobar.flubber</groupId>
<artifactId>uberportalconf</artifactId>
<version>13-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Environment for UberPortalConf</name>
<description>This is the description</description>
<properties>
<birduberportal.version>11</birduberportal.version>
<promotiondevice.version>9</promotiondevice.version>
<foobarportal.version>6</foobarportal.version>
<eventuberdevice.version>2</eventuberdevice.version>
</properties>
<!-- A lot more here, but as it is irrelevant for the problem I have removed it -->
</project>
如果我加载 example.xml 并使用 ElementTree 解析它,我可以看到它的命名空间是http://maven.apache.org/POM/4.0.0
。
>>> from xml.etree import ElementTree
>>> tree = ElementTree.parse('example.xml')
>>> print tree.getroot()
<Element '{http://maven.apache.org/POM/4.0.0}project' at 0x26ee0f0>
我还没有找到一种方法来调用只从Element
获取命名空间而不求助于解析Element
的str(an_element)
。 似乎必须有更好的方法。
命名空间应该在“实际”标签之前的Element.tag
:
>>> root = tree.getroot()
>>> root.tag
'{http://maven.apache.org/POM/4.0.0}project'
要了解有关命名空间的更多信息,请查看ElementTree:使用命名空间和限定名称。
这是正则表达式的完美任务。
import re
def namespace(element):
m = re.match(r'\{.*\}', element.tag)
return m.group(0) if m else ''
我不确定这是否可以用xml.etree
,但这里是你如何用lxml.etree
做到这lxml.etree
:
>>> from lxml import etree
>>> tree = etree.parse('example.xml')
>>> tree.xpath('namespace-uri(.)')
'http://maven.apache.org/POM/4.0.0'
不使用正则表达式:
>>> root
<Element '{http://www.google.com/schemas/sitemap/0.84}urlset' at 0x2f7cc10>
>>> root.tag.split('}')[0].strip('{')
'http://www.google.com/schemas/sitemap/0.84'
lxml.xtree
库的元素有一个名为nsmap
的字典,它显示了当前标记范围内使用的所有命名空间。
>>> item = tree.getroot().iter().next()
>>> item.nsmap
{'md': 'urn:oasis:names:tc:SAML:2.0:metadata'}
简短的回答是:
ElementTree._namspace_map[ElementTree._namspace_map.values().index('')]
但前提是你一直在打电话
ElementTree.register_namespace(prefix,uri)
响应在迭代结果时收到的每个事件==“start-ns”
ET.iterparse(...)
你注册了“start-ns”
回答“什么是默认命名空间?”的问题,有必要澄清两点:
(1) XML 规范说默认命名空间不一定在整个树中是全局的,而是可以在根下的任何元素重新声明默认命名空间,并向下继承,直到遇到另一个默认命名空间重新声明。
(2) ElementTree 模块可以(事实上)处理没有根默认名称空间的类 XML 文档,如果它们在文档中的任何地方都没有名称空间使用。 (* 可能有不那么严格的条件,例如,“if”而不一定是“iff”)。
可能也值得考虑“你想要它做什么?” 考虑到 XML 文件在语义上可以是等效的,但在语法上却非常不同。 例如,以下三个文件在语义上是等价的,但 A.xml 有一个默认命名空间声明,B.xml 有三个,而 C.xml 没有。
A.xml:
<a xlmns="http://A" xlmns:nsB0="http://B0" xlmns:nsB1="http://B1">
<nsB0:b/>
<nsB1:b/>
</a>
B.xml:
<a xlmns="http://A">
<b xlmns="http://B0"/>
<b xlmns="http://B1"/>
</a>
C.xml:
<{http://A}a>
<{http://B0}b/>
<{http://B1}b/>
</a>
文件 C.xml 是呈现给 ElementTree 搜索功能的规范扩展句法表示。
如果您事先确定不会有命名空间冲突,则可以在解析时修改元素标签,如下所述: Python ElementTree 模块:如何在使用“查找”方法时忽略 XML 文件的命名空间以定位匹配元素, “找到所有”
我认为查看属性会更容易:
>>> root.attrib
{'{http://www.w3.org/2001/XMLSchema-instance}schemaLocation':
'http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd'}
结合上面的一些答案,我认为最短的代码是
theroot = tree.getroot()
theroot.attrib[theroot.keys()[0]]
这是我在 ElementTree 3.9+ 上的解决方案,
def get_element_namespaces(filename, element):
namespace = []
for key, value in ET.iterparse(filename, events=['start', 'start-ns']):
print(key, value)
if key == 'start-ns':
namespace.append(value)
else:
if ET.tostring(element) == ET.tostring(value):
return namespace
namespace = []
return namespaces
这将返回一个 [prefix:URL] 元组数组,如下所示:
[('android', 'http://schemas.android.com/apk/res/android'), ('tools', 'http://schemas.android.com/tools')]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.