在 Python 中使用 ETree 保存 XML。它不保留名称空间,不添加 ns0、ns1 和删除 xmlns 标记
Saving XML using ETree in Python. It's not retaining namespaces, and adding ns0, ns1 and removing xmlns tags
我看到这里也有类似的问题,但对我没有任何帮助。
我还查看了有关命名空间的官方文档,但找不到任何真正对我有帮助的东西,也许我对 XML 格式化太陌生了。
我知道也许我需要创建自己的命名空间字典?不管怎样,这是我的情况:
我从 API 调用中得到一个结果,它给了我一个 XML 作为字符串存储在我的 Python 应用程序中。
我想要完成的只是抓住这个 XML,换出一个小值(b:string value user ConditionValue/Default 但这与这个问题无关)
然后将其保存为字符串,稍后在 Rest POST 调用中发送。
来源 XML 如下所示:
<Context xmlns="http://Test.the.Sdk/2010/07" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<xmlns i:nil="true" xmlns="http://schema.test.org/2004/07/Test.Soa.Vocab" xmlns:a="http://schema.test.org/2004/07/System.Xml.Serialize"/>
<Conditions xmlns:a="http://schema.test.org/2004/07/Test.Soa.Vocab">
<a:Condition>
<a:xmlns i:nil="true" xmlns:b="http://schema.test.org/2004/07/System.Xml.Serialize"/>
<Identifier>a23aacaf-9b6b-424f-92bb-5ab71505e3bc</Identifier>
<Name>Code</Name>
<ParameterSelections/>
<ParameterSetCollections/>
<Parameters/>
<Summary i:nil="true"/>
<Instance>25486d6c-36ba-4ab2-9fa6-0dbafbcf0389</Instance>
<ConditionValue>
<ComplexValue i:nil="true"/>
<Text i:nil="true" xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
<Default>
<ComplexValue i:nil="true"/>
<Text xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<b:string>NULLCODE</b:string>
</Text>
</Default>
</ConditionValue>
<TypeCode>String</TypeCode>
</a:Condition>
<a:Condition>
<a:xmlns i:nil="true" xmlns:b="http://schema.test.org/2004/07/System.Xml.Serialize"/>
<Identifier>0af860f6-5611-4a23-96dc-eb3863975529</Identifier>
<Name>Content Type</Name>
<ParameterSelections/>
<ParameterSetCollections/>
<Parameters/>
<Summary i:nil="true"/>
<Instance>6364ec20-306a-4cab-aabc-8ec65c0903c9</Instance>
<ConditionValue>
<ComplexValue i:nil="true"/>
<Text i:nil="true" xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
<Default>
<ComplexValue i:nil="true"/>
<Text xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<b:string>Standard</b:string>
</Text>
</Default>
</ConditionValue>
<TypeCode>String</TypeCode>
</a:Condition>
</Conditions>
我的工作是换出其中一个值,保留源的整个结构,并在稍后的应用程序中使用它来提交 POST。
我遇到的问题是,当它保存到字符串或文件时,它完全弄乱了名称空间:
<ns0:Context xmlns:ns0="http://Test.the.Sdk/2010/07" xmlns:ns1="http://schema.test.org/2004/07/Test.Soa.Vocab" xmlns:ns3="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns1:xmlns xsi:nil="true" />
<ns0:Conditions>
<ns1:Condition>
<ns1:xmlns xsi:nil="true" />
<ns0:Identifier>a23aacaf-9b6b-424f-92bb-5ab71505e3bc</ns0:Identifier>
<ns0:Name>Code</ns0:Name>
<ns0:ParameterSelections />
<ns0:ParameterSetCollections />
<ns0:Parameters />
<ns0:Summary xsi:nil="true" />
<ns0:Instance>25486d6c-36ba-4ab2-9fa6-0dbafbcf0389</ns0:Instance>
<ns0:ConditionValue>
<ns0:ComplexValue xsi:nil="true" />
<ns0:Text xsi:nil="true" />
<ns0:Default>
<ns0:ComplexValue xsi:nil="true" />
<ns0:Text>
<ns3:string>NULLCODE</ns3:string>
</ns0:Text>
</ns0:Default>
</ns0:ConditionValue>
<ns0:TypeCode>String</ns0:TypeCode>
</ns1:Condition>
<ns1:Condition>
<ns1:xmlns xsi:nil="true" />
<ns0:Identifier>0af860f6-5611-4a23-96dc-eb3863975529</ns0:Identifier>
<ns0:Name>Content Type</ns0:Name>
<ns0:ParameterSelections />
<ns0:ParameterSetCollections />
<ns0:Parameters />
<ns0:Summary xsi:nil="true" />
<ns0:Instance>6364ec20-306a-4cab-aabc-8ec65c0903c9</ns0:Instance>
<ns0:ConditionValue>
<ns0:ComplexValue xsi:nil="true" />
<ns0:Text xsi:nil="true" />
<ns0:Default>
<ns0:ComplexValue xsi:nil="true" />
<ns0:Text>
<ns3:string>Standard</ns3:string>
</ns0:Text>
</ns0:Default>
</ns0:ConditionValue>
<ns0:TypeCode>String</ns0:TypeCode>
</ns1:Condition>
</ns0:Conditions>
我已将代码缩小到最基本的形式,但我仍然得到相同的结果,所以这与我正常操作文件的方式无关:
import xml.etree.ElementTree as ET
import requests
get_context_xml = 'http://localhost/testapi/returnxml' #returns first XML example above.
source_context_xml = requests.get(get_context_xml)
Tree = ET.fromstring(source_context_xml)
#Ensure the original namespaces are intact.
for Conditions in Tree.iter('{http://schema.test.org/2004/07/Test.Soa.Vocab}Condition'):
print "success"
with open('/home/memyself/output.xml','w') as f:
f.write(ET.tostring(Tree))
在执行 fromstring()
(阅读 xml)之前,您需要 register 前缀和命名空间以避免默认命名空间前缀(如 ns0
和 ns1
等).
您可以为此使用 ET.register_namespace()
函数,示例 -
ET.register_namespace('<prefix>','http://Test.the.Sdk/2010/07')
ET.register_namespace('a','http://schema.test.org/2004/07/Test.Soa.Vocab')
如果不需要前缀,可以将 <prefix>
留空。
Example/Demo -
>>> r = ET.fromstring('<a xmlns="blah">a</a>')
>>> ET.tostring(r)
b'<ns0:a xmlns:ns0="blah">a</ns0:a>'
>>> ET.register_namespace('','blah')
>>> r = ET.fromstring('<a xmlns="blah">a</a>')
>>> ET.tostring(r)
b'<a xmlns="blah">a</a>'
首先,welcome to the Whosebug network! Technically @anand-s-kumar 是正确的。然而,toString
函数有一个小的误用,事实上名称空间可能并不总是被代码所知,或者在标签或 XML 文件之间是相同的。此外,lxml
和 xml.etree
库与 Python 2.x 和 3.x 之间的不一致使得处理起来很困难。
此函数遍历传入的 XML 树 tree
中的所有子元素,然后编辑 XML 标记以删除命名空间。请注意,这样做可能会丢失一些 数据 。
def remove_namespaces(tree):
for el in tree.getiterator():
match = re.match("^(?:\{.*?\})?(.*)$", el.tag)
if match:
el.tag = match.group(1)
我自己刚刚 运行 解决了这个问题,并想出了一个快速的解决方案。我在大约 81,000 个 XML 个存在此问题的文件(平均每个文件大约 150 MB)上对此进行了测试,并且所有文件都已修复。请注意,这并不是一个最佳解决方案,但它相对有效并且对我来说效果很好。
CREDIT: 想法和代码结构最初来自 Jochen Kupperschmidt.
我看到这里也有类似的问题,但对我没有任何帮助。 我还查看了有关命名空间的官方文档,但找不到任何真正对我有帮助的东西,也许我对 XML 格式化太陌生了。 我知道也许我需要创建自己的命名空间字典?不管怎样,这是我的情况:
我从 API 调用中得到一个结果,它给了我一个 XML 作为字符串存储在我的 Python 应用程序中。
我想要完成的只是抓住这个 XML,换出一个小值(b:string value user ConditionValue/Default 但这与这个问题无关) 然后将其保存为字符串,稍后在 Rest POST 调用中发送。
来源 XML 如下所示:
<Context xmlns="http://Test.the.Sdk/2010/07" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<xmlns i:nil="true" xmlns="http://schema.test.org/2004/07/Test.Soa.Vocab" xmlns:a="http://schema.test.org/2004/07/System.Xml.Serialize"/>
<Conditions xmlns:a="http://schema.test.org/2004/07/Test.Soa.Vocab">
<a:Condition>
<a:xmlns i:nil="true" xmlns:b="http://schema.test.org/2004/07/System.Xml.Serialize"/>
<Identifier>a23aacaf-9b6b-424f-92bb-5ab71505e3bc</Identifier>
<Name>Code</Name>
<ParameterSelections/>
<ParameterSetCollections/>
<Parameters/>
<Summary i:nil="true"/>
<Instance>25486d6c-36ba-4ab2-9fa6-0dbafbcf0389</Instance>
<ConditionValue>
<ComplexValue i:nil="true"/>
<Text i:nil="true" xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
<Default>
<ComplexValue i:nil="true"/>
<Text xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<b:string>NULLCODE</b:string>
</Text>
</Default>
</ConditionValue>
<TypeCode>String</TypeCode>
</a:Condition>
<a:Condition>
<a:xmlns i:nil="true" xmlns:b="http://schema.test.org/2004/07/System.Xml.Serialize"/>
<Identifier>0af860f6-5611-4a23-96dc-eb3863975529</Identifier>
<Name>Content Type</Name>
<ParameterSelections/>
<ParameterSetCollections/>
<Parameters/>
<Summary i:nil="true"/>
<Instance>6364ec20-306a-4cab-aabc-8ec65c0903c9</Instance>
<ConditionValue>
<ComplexValue i:nil="true"/>
<Text i:nil="true" xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
<Default>
<ComplexValue i:nil="true"/>
<Text xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<b:string>Standard</b:string>
</Text>
</Default>
</ConditionValue>
<TypeCode>String</TypeCode>
</a:Condition>
</Conditions>
我的工作是换出其中一个值,保留源的整个结构,并在稍后的应用程序中使用它来提交 POST。
我遇到的问题是,当它保存到字符串或文件时,它完全弄乱了名称空间:
<ns0:Context xmlns:ns0="http://Test.the.Sdk/2010/07" xmlns:ns1="http://schema.test.org/2004/07/Test.Soa.Vocab" xmlns:ns3="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns1:xmlns xsi:nil="true" />
<ns0:Conditions>
<ns1:Condition>
<ns1:xmlns xsi:nil="true" />
<ns0:Identifier>a23aacaf-9b6b-424f-92bb-5ab71505e3bc</ns0:Identifier>
<ns0:Name>Code</ns0:Name>
<ns0:ParameterSelections />
<ns0:ParameterSetCollections />
<ns0:Parameters />
<ns0:Summary xsi:nil="true" />
<ns0:Instance>25486d6c-36ba-4ab2-9fa6-0dbafbcf0389</ns0:Instance>
<ns0:ConditionValue>
<ns0:ComplexValue xsi:nil="true" />
<ns0:Text xsi:nil="true" />
<ns0:Default>
<ns0:ComplexValue xsi:nil="true" />
<ns0:Text>
<ns3:string>NULLCODE</ns3:string>
</ns0:Text>
</ns0:Default>
</ns0:ConditionValue>
<ns0:TypeCode>String</ns0:TypeCode>
</ns1:Condition>
<ns1:Condition>
<ns1:xmlns xsi:nil="true" />
<ns0:Identifier>0af860f6-5611-4a23-96dc-eb3863975529</ns0:Identifier>
<ns0:Name>Content Type</ns0:Name>
<ns0:ParameterSelections />
<ns0:ParameterSetCollections />
<ns0:Parameters />
<ns0:Summary xsi:nil="true" />
<ns0:Instance>6364ec20-306a-4cab-aabc-8ec65c0903c9</ns0:Instance>
<ns0:ConditionValue>
<ns0:ComplexValue xsi:nil="true" />
<ns0:Text xsi:nil="true" />
<ns0:Default>
<ns0:ComplexValue xsi:nil="true" />
<ns0:Text>
<ns3:string>Standard</ns3:string>
</ns0:Text>
</ns0:Default>
</ns0:ConditionValue>
<ns0:TypeCode>String</ns0:TypeCode>
</ns1:Condition>
</ns0:Conditions>
我已将代码缩小到最基本的形式,但我仍然得到相同的结果,所以这与我正常操作文件的方式无关:
import xml.etree.ElementTree as ET
import requests
get_context_xml = 'http://localhost/testapi/returnxml' #returns first XML example above.
source_context_xml = requests.get(get_context_xml)
Tree = ET.fromstring(source_context_xml)
#Ensure the original namespaces are intact.
for Conditions in Tree.iter('{http://schema.test.org/2004/07/Test.Soa.Vocab}Condition'):
print "success"
with open('/home/memyself/output.xml','w') as f:
f.write(ET.tostring(Tree))
在执行 fromstring()
(阅读 xml)之前,您需要 register 前缀和命名空间以避免默认命名空间前缀(如 ns0
和 ns1
等).
您可以为此使用 ET.register_namespace()
函数,示例 -
ET.register_namespace('<prefix>','http://Test.the.Sdk/2010/07')
ET.register_namespace('a','http://schema.test.org/2004/07/Test.Soa.Vocab')
如果不需要前缀,可以将 <prefix>
留空。
Example/Demo -
>>> r = ET.fromstring('<a xmlns="blah">a</a>')
>>> ET.tostring(r)
b'<ns0:a xmlns:ns0="blah">a</ns0:a>'
>>> ET.register_namespace('','blah')
>>> r = ET.fromstring('<a xmlns="blah">a</a>')
>>> ET.tostring(r)
b'<a xmlns="blah">a</a>'
首先,welcome to the Whosebug network! Technically @anand-s-kumar 是正确的。然而,toString
函数有一个小的误用,事实上名称空间可能并不总是被代码所知,或者在标签或 XML 文件之间是相同的。此外,lxml
和 xml.etree
库与 Python 2.x 和 3.x 之间的不一致使得处理起来很困难。
此函数遍历传入的 XML 树 tree
中的所有子元素,然后编辑 XML 标记以删除命名空间。请注意,这样做可能会丢失一些 数据 。
def remove_namespaces(tree):
for el in tree.getiterator():
match = re.match("^(?:\{.*?\})?(.*)$", el.tag)
if match:
el.tag = match.group(1)
我自己刚刚 运行 解决了这个问题,并想出了一个快速的解决方案。我在大约 81,000 个 XML 个存在此问题的文件(平均每个文件大约 150 MB)上对此进行了测试,并且所有文件都已修复。请注意,这并不是一个最佳解决方案,但它相对有效并且对我来说效果很好。
CREDIT: 想法和代码结构最初来自 Jochen Kupperschmidt.