Python 如何强制ElementTree将xmlns属性保留在其原始元素中?
我有一个输入XML文件: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 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>