Python:ElementTree,获取元素的名称空间字符串
此XML文件名为Python:ElementTree,获取元素的名称空间字符串,python,elementtree,Python,Elementtree,此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.xs
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>
我还没有找到一种方法,可以调用该方法仅从
元素
获取名称空间,而不用解析元素的str(一个元素)
。似乎有更好的方法。我不确定使用xml.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.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'}
名称空间应位于“实际”标记的正前方:
要了解有关名称空间的更多信息,请查看。这是一项完美的任务
不使用正则表达式:
>>> 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'
>>根目录
>>>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)
对每个事件的响应==“开始ns”在遍历
ET.iterparse(...)
你注册了“启动ns”
在回答“默认名称空间是什么?”问题时,有必要澄清两点:
(1) XML规范指出,默认名称空间在整个树中不一定是全局的,而是可以在根目录下的任何元素处重新声明默认名称空间,并向下继承,直到满足另一个默认名称空间重新声明
(2) ElementTree模块可以(事实上)处理类似XML的文档,这些文档没有根默认名称空间,-if-它们在文档中的任何地方都没有名称空间使用。(*可能有不太严格的条件,例如,即“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>
A.xml:
结合上面的一些答案,我认为最短的代码是
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')]
我在Windows中使用Python 2.7.2获得了未解析导入:etree
。xpath
在使用xml.etree
时不能作为方法使用,如果我使用find()
(支持xpath表达式)则名称空间-uri(.)“
语句仍然不起作用。这正是我所寻找的,这是我见过的最好的解决方案。我通常使用xmlstarlet,但现在可以切换。对于lxml
获取名称空间的更简单方法是tree.getroot().nsmap
@Jona:我假设使用None
是一种处理默认名称空间的方法,即声明为不带前缀的名称空间。当然比解析str(the_元素)更容易
。但我想解析元素.tag更容易一些。因为我只对名称空间感兴趣。你认为呢?我认为@RikPoggi的答案似乎是最好的(事实上,我投了更高的票)。事实上,获得名称空间应该和重新搜索('\{(.*\}),元素.tag.group(1)一样简单
。根据我的回答,您似乎可以使用元素.attrib.values()[0].split()[0]
,但事实上,它看起来并不那么简单,也不能保证将来不会获得任何其他属性。你知道在这种情况下如何使用find方法吗?它在这里不起作用……在与这个问题斗争了一段时间后,这是我找到的最佳解决方案。我不敢相信API没有让你提出问题的方法同时,它在执行“rootElement.keys()时不返回属性“xmlns”“。当然有一个很好的理由,但我现在找不到它。在常规exp之前添加r
请使这个答案完美。@Jiu非常感谢你。我不敢相信我错过了。要获得没有大括号的名称空间,请包括:re.match(r'\{(.*}',element.tag)。组(1)一个类似的答案root.tag[1:root.tag.index('}])”
这个答案是最简单的。谢谢这是不准确的,因为xmlns可能不是根的第一个属性。事实上,我目前正在尝试解析一个TCX文件,而xmlns根本没有显示为根的属性。您提供的链接已失效,您可能需要对其进行编辑,以指向此信息的其他源。
theroot = tree.getroot()
theroot.attrib[theroot.keys()[0]]
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
[('android', 'http://schemas.android.com/apk/res/android'), ('tools', 'http://schemas.android.com/tools')]