我有一个输入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>
...和Python脚本:
import xml.etree.ElementTree as ET
file_xml = 'test.xml'
tree = ET.parse(file_xml)
root = tree.getroot()
print (root.tag)
print (root.attrib)
element_runtime = root.find('.//runtime')
print (element_runtime.tag)
print (element_runtime.attrib)
tree.write(file_xml, xml_declaration=True, encoding='utf-8', method="xml")
...提供以下输出:
>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,因此我必须调用tree.write
并保存已编辑的文件。但问题是ElementTree解析器将xmlns
属性从runtime
元素移动到根元素configuration
,这在我的情况下是不可取的。
我无法从根元素中删除xmlns
属性(将其从其属性的字典中删除),因为它未在其属性列表中列出(与runtime
列出的属性不同元件)。
为什么xmlns属性永远不会列在任何元素的属性列表中?
如何强制ElementTree将xmlns属性保留在其原始元素中?
我在Windows上使用Python 3.5.1。
答案 0 :(得分:2)
xml.etree.ElementTree
将所有名称空间拉入第一个元素,因为它内部没有跟踪最初声明名称空间的元素。
如果您不想要,那么您必须编写自己的序列化逻辑。
更好的选择是使用lxml
而不是xml.etree
,因为它会保留声明命名空间前缀的位置。
答案 1 :(得分:1)
按照@mata 的建议,我在这里给出了一个带有代码和 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 的整个结构保持不变,只是根据需要更改了一些 NtnlCcy 和价格节点。
我们不想要的唯一细微差别是第一行。在原始xml文件中,它是<?xml version="1.0" encoding="UTF-8"?>
,而在修改后的xml文件中,它是<?xml version='1.0' encoding='UTF-8'?>
。引号从双引号变为单引号。但我们认为这个微小的差异应该无关紧要。
将附加原始文件上下文以供您轻松测试:
<?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>