【问题标题】:How to force ElementTree to keep xmlns attribute within its original element?如何强制 ElementTree 将 xmlns 属性保留在其原始元素中?
【发布时间】:2021-02-10 00:30:53
【问题描述】:

我有一个输入 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。

【问题讨论】:

  • etree pulls all namespaces into the first element 因为它在内部不跟踪最初声明命名空间的元素。如果您不希望这样,则必须编写自己的序列化逻辑,或者改用 lxml。但在声明命名空间的位置应该没有任何区别。
  • 我正在使用 Python 修改 .NET 应用程序配置文件,该文件不得在根元素 (blogs.msdn.com/b/junfeng/archive/2008/03/24/…) 中包含命名空间声明。
  • 什么? WTF 是 mircrosoft 用来解析 xml 的???我想你最好的选择是使用lxml 而不是xml.etree,因为它似乎尊重 namsepace 声明的定位。
  • 是的,这也是我的第一反应……现在正在安装 lxml。
  • 是的,lxml 保留了 xmlns 属性的原始位置。

标签: python xml elementtree


【解决方案1】:

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

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

更好的选择是使用lxml 而不是xml.etree,因为它保留了声明命名空间前缀的位置。

【讨论】:

    【解决方案2】:

    根据@mata 的建议,我在这里给出一个带有代码和xml 文件的示例的答案。

    xml输入如图(原版和修改版)

    python 代码检查 NtnlCcy 名称,如果它是“EUR”,则将价格转换为 USD(乘以 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文件中为&lt;?xml version="1.0" encoding="UTF-8"?&gt;,修改后的xml文件中为&lt;?xml version='1.0' encoding='UTF-8'?&gt;。引号从双引号变为单引号。但我们认为这个微小的差异并不重要。

    将附加原始文件上下文以供您轻松测试:

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

    【讨论】:

      猜你喜欢
      • 2020-04-23
      • 1970-01-01
      • 1970-01-01
      • 2014-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-02
      • 2010-12-29
      相关资源
      最近更新 更多