从XML-Python获取xsi类型

从XML-Python获取xsi类型,python,xml,lxml,Python,Xml,Lxml,我有以下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>1

我有以下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似乎被命名空间声明中的xmlns:xsi替换了。如图所示,如果我使用以下代码打印每个节点属性:

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
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类型属性存在的地方,它实际上用名称空间中的xsi替换它。 我怎样才能阻止这种事情发生?我希望搜索xsi类型,而不是从名称空间声明中输入字符串文字。

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

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

尤其是XML文档和XML处理代码之间不必保持一致,您应该阅读:不得编写任何采用前缀或依赖前缀的代码

这就是为什么如果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>
并在选择命名空间中的节点时使用该映射-明确地:

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>
xsi是名称空间前缀,而不是名称空间。前缀唯一需要保持一致的地方是在声明它的XML元素中

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

尤其是XML文档和XML处理代码之间不必保持一致,您应该阅读:不得编写任何采用前缀或依赖前缀的代码

这就是为什么如果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>
并在选择命名空间中的节点时使用该映射-明确地:

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>

我一直在寻找这个问题的答案,我也想出了一些类似的东西。我发现这些资源可能是很好的补充答案:抱歉,如果我误解了什么,但是我必须在nsmap中明确指定“xsi”吗?如果是这样,这如何使程序独立于前缀?有没有一种方法不必显式地定义它?检查这个@Adam@Adam您不必在nsmap中说“xsi”:“w3.org/2001/XMLSchema instance”。你可以说‘foobar’:‘w3.org/2001/XMLSchema instance’,但什么都不会改变,这就是我试图表达的全部观点。前缀是一个方便的特性,它们需要在各自的作用域中保持一致,但不能跨作用域。Python程序就是一个作用域。如果每次引用“w3.org/2001/XMLSchema实例”名称空间时都使用foobar,那没关系——不管名称空间在XML中是如何缩写的。@Adam在我的文章底部看到了扩展示例。我一直在寻找这个问题的答案,我也想出了类似的方法。我发现这些资源可能是很好的补充答案:抱歉,如果我误解了什么,但是我必须在nsmap中明确指定“xsi”吗?如果是这样,这如何使程序独立于前缀?有没有一种方法不必显式地定义它?检查这个@Adam@Adam您不必在nsmap中说“xsi”:“w3.org/2001/XMLSchema instance”。你可以说‘foobar’:‘w3.org/2001/XMLSchema instance’,但什么都不会改变,这就是我试图表达的全部观点。前缀是一个方便的特性,它们需要在各自的作用域中保持一致,但不能跨作用域。Python程序就是一个作用域。如果每次要引用“w3.org/2001/XMLSchema实例”命名空间时都使用foobar,那么不管该命名空间在XML中如何缩写,都可以使用foobar。@Adam请参阅我文章底部的扩展示例。