从 XML - Python 获取 xsi 类型
Get xsi type from XML - Python
我有以下 "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 中,我想遍历每个节点和 return "sample-type" 和 "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:
没有意义的原因 - 它假定前缀必须是 xsi
。 xsi
可能常用于 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'
}
并在您 select 命名空间中的节点时使用该映射 - 明确地:
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 个前缀。 xsi
、blah
、foo
,每个都有不同的范围。
解析这个的时候,你会用哪一个来引用xsi
?这有关系吗? 应该重要吗?不,不应该。需要匹配的只是名称空间 URI,我们一点都不关心 XML 文档对前缀做了什么:
nsmap = {
's': 'http://www.w3.org/2001/XMLSchema-instance'
}
type = node.xpath('@s:type', namespaces=nsmap)
我有以下 "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 中,我想遍历每个节点和 return "sample-type" 和 "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:
没有意义的原因 - 它假定前缀必须是 xsi
。 xsi
可能常用于 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'
}
并在您 select 命名空间中的节点时使用该映射 - 明确地:
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 个前缀。 xsi
、blah
、foo
,每个都有不同的范围。
解析这个的时候,你会用哪一个来引用xsi
?这有关系吗? 应该重要吗?不,不应该。需要匹配的只是名称空间 URI,我们一点都不关心 XML 文档对前缀做了什么:
nsmap = {
's': 'http://www.w3.org/2001/XMLSchema-instance'
}
type = node.xpath('@s:type', namespaces=nsmap)