从XML-Python中获取xsi类型



我得到了以下"test.xml"文件:

<?xml version="1.0" encoding="UTF-8"?>
<test:myXML xmlns:test="http://com/my/namespace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Parent>
<Child1 xsi:type="sample-type">
<GrandChild1>123</GrandChild1>
<GrandChild2>BranchName</GrandChild2>
</Child1>
<Child2 xsi:type="sample-type2"></Child2>
</Parent>
</test:myXML>

我想为任何节点(在它存在的地方(检索"xsi:type"。例如,在上面的xml中,我想遍历每个节点并返回"sample-type"one_answers"sample-type2">

到目前为止,我得到了以下代码:

from lxml import etree
XMLDoc = etree.parse("test.xml")
rootXMLElement = XMLDoc.getroot()
tree = etree.parse("test.xml")
for Node in XMLDoc.xpath('//*'):
if "xsi:type" in Node.attrib:
#Do whatever

然而,这并不起作用,因为结果中的"xsi:type"似乎被命名空间声明中的xmlns:xsi所取代。举例来说,如果我使用以下代码打印每个节点属性:

from lxml import etree
XMLDoc = etree.parse("test.xml")
rootXMLElement = XMLDoc.getroot()
tree = etree.parse("test.xml")
for Node in XMLDoc.xpath('//*'):
print(Node.attrib)

结果是:

{}
{}
{'{http://www.w3.org/2001/XMLSchema-instance}type': 'sample-type'}
{}
{}
{'{http://www.w3.org/2001/XMLSchema-instance}type': 'sample-type2'}

正如您所看到的,在"xsi-type"属性存在的地方,它实际上用命名空间中的xsi来替换它。我该如何阻止这种情况的发生?我想搜索xsi类型,而不是从名称空间声明中输入字符串文字。

xsi是命名空间前缀,它不是命名空间。前缀唯一需要保持一致的地方是在声明它的XML元素中

前缀甚至不需要在同一XML文档中保持一致,您可以在同一文档中使用任意数量的不同前缀引用相同的命名空间。

,尤其是不必在XML文档和XML处理代码之间保持一致,并且您不应该(阅读:必须(编写任何假定前缀或依赖前缀的代码。

这就是为什么if "xsi:type" in Node.attrib:没有意义——它假设前缀必须是xsixsi可能通常用于http://www.w3.org/2001/XMLSchema-instance命名空间,但这只是一种约定,而不是保证。

XML文档可以写成

<test:myXML xmlns:test="http://com/my/namespace" xmlns:blah="http://www.w3.org/2001/XMLSchema-instance">
<Parent>
<Child1 blah:type="sample-type">
<GrandChild1>123</GrandChild1>
<GrandChild2>BranchName</GrandChild2>
</Child1>
<Child2 blah:type="sample-type2"></Child2>
</Parent>
</test:myXML>

这将是完全相同的东西

这就是为什么lxml在显示节点时或在其XPath方言中使用名称空间URI,而不是前缀——URI是重要的,前缀是短暂的。

您需要在程序中定义一个名称空间映射

nsmap = {
'xsi': 'http://www.w3.org/2001/XMLSchema-instance'
}

并在选择命名空间中的节点时使用该映射-明确地:

if f"{{{nsmap['xsi']}}}type" in node.attrib:
# ...

或通过XPath

type = node.xpath('@xsi:type', nsmap)

这使得您的程序独立于前缀——您可以自由使用任何您喜欢的前缀,XML文档可以自由使用它喜欢的任何前缀,并且代码将以任何一种方式工作。


极端的例子,但对概述想法有用:

<test:myXML xmlns:test="http://com/my/namespace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Parent xmlns:blah="http://www.w3.org/2001/XMLSchema-instance">
<Child1 foo:type="sample-type" xmlns:foo="http://www.w3.org/2001/XMLSchema-instance">
<GrandChild1>123</GrandChild1>
<GrandChild2>BranchName</GrandChild2>
</Child1>
<Child2 blah:type="sample-type2"></Child2>
</Parent>
</test:myXML>

这里,http://www.w3.org/2001/XMLSchema-instance得到3个前缀。xsiblahfoo,每一个都具有不同的范围。

解析后,您将使用哪一个来引用xsi?这有关系吗这重要吗?不,不应该。所需要匹配的只是名称空间URI,我们一点也不在乎XML文档对前缀的作用:

nsmap = {
's': 'http://www.w3.org/2001/XMLSchema-instance'
}
type = node.xpath('@s:type', namespaces=nsmap)

最新更新