在 Python 中使用 ETree 保存 XML。它不保留命名空间,添加 ns0、ns1 并删除 xmlns 标签



我看到这里有类似的问题,但没有一个完全帮助到我。我还查看了有关名称空间的官方文档,但找不到任何真正有帮助的东西,可能是因为我对XML格式化太陌生了。我明白,也许我需要创建自己的名称空间字典?不管怎样,这是我的情况:

我从API调用中得到一个结果,它给了我一个XML,它作为字符串存储在我的Python应用程序中。

我想要完成的只是抓住这个XML,交换出一个小值(b:字符串值用户条件值/默认,但这是无关紧要的这个问题)然后将其保存为字符串,以便稍后在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)之前注册前缀和名称空间,以避免默认的名称空间前缀(如ns0ns1等)。

您可以使用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>保留为空。


例子/演示-

>>> 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>'

首先,欢迎来到StackOverflow网络!严格来说,@anand-s-kumar是正确的。但是,toString函数有一个小的误用,并且代码可能并不总是知道名称空间,标记或XML文件之间也是如此。此外,lxmlxml.etree库与Python 2之间的不一致。X和3。

该函数遍历传入的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)上进行了测试,所有这些文件都得到了修复。请注意,这并不是一个最优的解决方案,但它相对有效,对我来说工作得很好。

来源:想法和代码结构最初来自Jochen Kupperschmidt

最新更新