Python 如何强制ElementTree将xmlns属性保留在其原始元素中?

Python 如何强制ElementTree将xmlns属性保留在其原始元素中?,python,xml,elementtree,Python,Xml,Elementtree,我有一个输入XML文件: <?xml version='1.0' encoding='utf-8'?> <configuration> <runtime name="test" version="1.2" xmlns:ns0="urn:schemas-microsoft-com:asm.v1"> <ns0:assemblyBinding> <ns0:dependentAssembly /> </ns

我有一个输入XML文件:

<?xml version='1.0' encoding='utf-8'?>
<configuration>
  <runtime name="test" version="1.2" xmlns:ns0="urn:schemas-microsoft-com:asm.v1">
    <ns0:assemblyBinding>
      <ns0:dependentAssembly />
    </ns0:assemblyBinding>
  </runtime>
</configuration>
…这将提供以下输出:

>test.py
configuration
{}
runtime
{'name': 'test', 'version': '1.2'}
…并具有将XML修改为以下内容的不良副作用:

<?xml version='1.0' encoding='utf-8'?>
<configuration xmlns:ns0="urn:schemas-microsoft-com:asm.v1">
  <runtime name="test" version="1.2">
    <ns0:assemblyBinding>
      <ns0:dependentAssembly />
    </ns0:assemblyBinding>
  </runtime>
</configuration> 

我的原始脚本修改了XML,所以我必须调用
树。编写
并保存编辑过的文件。但问题是ElementTree解析器将
xmlns
属性从
runtime
元素移动到根元素
configuration
,这在我的例子中是不可取的

我无法从根元素中删除
xmlns
属性(将其从属性字典中删除),因为它没有列在属性列表中(与为
runtime
元素列出的属性不同)

为什么xmlns属性从未在任何元素的属性列表中列出?

如何强制ElementTree将xmlns属性保留在其原始元素中?


我在Windows上使用Python 3.5.1。

xml.etree.ElementTree
将所有名称空间拉入第一个元素,因为它内部不跟踪名称空间最初声明的元素

如果您不想这样做,您必须编写自己的序列化逻辑


更好的替代方法是使用而不是
xml.etree
,因为它保留了声明名称空间前缀的位置。

根据@mata建议,这里我给出了一个附有代码和xml文件的示例

xml输入如图所示(原始和修改)

python代码检查NtnlCcy名称,如果是“EUR”,则将价格转换为美元(乘以EURUSD:=1.2),并将NtnlCcy名称更改为“USD”

python代码如下所示:

from lxml import etree
pathToXMLfile = r"C:\Xiang\codes\Python\afmreports\test_original.xml"
tree = etree.parse(pathToXMLfile)
root = tree.getroot()
EURUSD = 1.2

for Rchild in root: 
    print ("Root child: ", Rchild.tag, ". \n")

    if Rchild.tag.endswith("Pyld"):
        for PyldChild in Rchild: 
            print ("Pyld Child: ", PyldChild.tag, ". \n")
        Doc = Rchild.find('{001.003}Document')
        FinInstrNodes = Doc.findall('{001.003}FinInstr')
    
        for FinInstrNode in FinInstrNodes:
            FinCcyNode = FinInstrNode.find('{001.003}NtnlCcy')
            FinPriceNode = FinInstrNode.find('{001.003}Price')
        
            FinCcyNodeText = ""
            if FinCcyNode is not None: 
                CcyNodeText = FinCcyNode.text
            if CcyNodeText == "EUR":
                PriceText = FinPriceNode.text
                Price = float(PriceText)
                FinPriceNode.text = str(Price * EURUSD) 
                FinCcyNode.text = "USD"

tree.write(r"C:\Xiang\codes\Python\afmreports\test_modified.xml", encoding="utf-8", xml_declaration=True) 
print("\n the program runs to the end! \n")  
当我们比较原始xml文件和修改后的xml文件时,名称空间保持不变,xml的整个结构保持不变,只有一些NtnlCcy和Price节点根据需要进行了更改

我们不想要的唯一细微差别是第一行。在原始xml文件中,它是
,而在修改后的xml文件中,它是
。报价符号由双引号变为单引号。但我们认为这一微小的差异不重要

原始文件上下文将附加在您的简易测试中:

<?xml version="1.0" encoding="UTF-8"?>
<BizData xmlns="001.001">
<Hdr>
    <AppHdr xmlns="001.002">
        <Fr>
            <Id>XXX01</Id>
        </Fr>
        <To>
            <Id>XXX02</Id>
        </To>
        <CreDt>2019-10-25T15:38:30</CreDt>
    </AppHdr>
</Hdr>
<Pyld>
    <Document xmlns="001.003">
        <FinInstr>
            <Id>NLENX240</Id>
            <FullNm>AO.AAI</FullNm>
            <NtnlCcy>EUR</NtnlCcy>
            <Price>9</Price>
        </FinInstr>
        <FinInstr>
            <Id>NLENX681</Id>
            <FullNm>AO.ABN</FullNm>
            <NtnlCcy>USD</NtnlCcy>
            <Price>10</Price>
        </FinInstr>
        <FinInstr>
            <Id>NLENX320</Id>
            <FullNm>AO.ING</FullNm>
            <NtnlCcy>EUR</NtnlCcy>
            <Price>11</Price>
        </FinInstr>
    </Document>
</Pyld>

XXX01
XXX02
2019-10-25T15:38:30
NLENX240
奥艾
欧元
9
NLENX681
澳大利亚银行
美元
10
NLENX320
奥宁
欧元
11

etree
,因为它内部不跟踪最初声明名称空间的元素。如果您不想这样做,您必须编写自己的序列化逻辑,或者改用lxml。但是声明名称空间的位置应该没有什么区别。我正在使用Python修改.NET应用程序配置文件,该文件不能在根元素()中包含名称空间声明。什么?mircrosoft使用WTF解析xml???我想您最好的选择是使用而不是
xml.etree
,因为它似乎尊重namsepace声明的定位。是的,这也是我的第一反应……现在安装lxml。是的,
lxml
保留
xmlns
属性的原始位置。
<?xml version="1.0" encoding="UTF-8"?>
<BizData xmlns="001.001">
<Hdr>
    <AppHdr xmlns="001.002">
        <Fr>
            <Id>XXX01</Id>
        </Fr>
        <To>
            <Id>XXX02</Id>
        </To>
        <CreDt>2019-10-25T15:38:30</CreDt>
    </AppHdr>
</Hdr>
<Pyld>
    <Document xmlns="001.003">
        <FinInstr>
            <Id>NLENX240</Id>
            <FullNm>AO.AAI</FullNm>
            <NtnlCcy>EUR</NtnlCcy>
            <Price>9</Price>
        </FinInstr>
        <FinInstr>
            <Id>NLENX681</Id>
            <FullNm>AO.ABN</FullNm>
            <NtnlCcy>USD</NtnlCcy>
            <Price>10</Price>
        </FinInstr>
        <FinInstr>
            <Id>NLENX320</Id>
            <FullNm>AO.ING</FullNm>
            <NtnlCcy>EUR</NtnlCcy>
            <Price>11</Price>
        </FinInstr>
    </Document>
</Pyld>