【问题标题】:How to move a specific xml tag to a new xml file using python?如何使用 python 将特定的 xml 标签移动到新的 xml 文件?
【发布时间】:2021-09-16 06:03:26
【问题描述】:

我有多个类似于以下的 xml 文件:- 名称 = 更新的 input.xml

<?xml version="1.0"?>
<TestSuite Name="A123">
 <Group Name="TestRoot" ExecutionPolicy="AnyDeviceAnyOrder">
  <Parameters>
      <Parameter Type="Integer" Name="maxA" Value="1" />
      <Parameter Type="Integer" Name="MaxB" Value="120" />
      <Parameter Type="String" Name="MaxC" Value="master" />
  </Parameters> 
  <Children>
          <Test Name="TestCam" Namespace="TestCase">
              <Parameters>
                    <Parameter Type="Integer" Name="maxTooth" />
              </Parameters>
          </Test>
  </Children>
  <Group Name="TestMain" ExecutionPolicy="AnyDeviceAnyOrder">
  <Parameters>
      <Parameter Type="Integer" Name="maxA" Value="1" />
      <Parameter Type="Integer" Name="MaxB" Value="120" />
      <Parameter Type="String" Name="MaxC" Value="master" />
  </Parameters> 
      <Group Name="TestMain1" ExecutionPolicy="AnyDeviceAnyOrder">
          <Parameters>
              <Parameter Type="Integer" Name="maxA" Value="1" />
              <Parameter Type="Integer" Name="MaxB" Value="120" />
              <Parameter Type="String" Name="MaxC" Value="master" />
          </Parameters> 
          <Children>
              <Test Name="TestDriver1" Namespace="TestCase">
                  <Parameters>
                        <Parameter Type="Integer" Name="maxP" />
                  </Parameters>
              </Test>
          </Children>
      </Group>
  <Children>
          <Test Name="TestDriver" Namespace="TestCase">
              <Parameters>
                    <Parameter Type="Integer" Name="maxP" />
              </Parameters>
          </Test>
          <Test Name="TestField" Namespace="TestCase">
              <Parameters>
                    <Parameter Type="Integer" Name="maxP" />
                       <Requirements>
                         <Requirement TypeId = "Abcdef" Source = "User1" >
                         <Requirement TypeId = "ghijk" Source = "User1" >
                       </Requirements>
              </Parameters>
          </Test>
  </Children>      
  </Group>      
 </Group>
 <Models>
     <Model Name= "NewPhone"> 
 </Models>
</TestSuite>

我有一个 python 代码,它正在创建一个新的 xml 文件,其中只有一些标签,如下所示 file1_sorted.xml:-

<?xml version="1.0"?>
<TestSuite Name="DM123">
  <Group Name="TestRoot" ExecutionPolicy="AnyDeviceAnyOrder">
  <Parameters>
      <Parameter Type="Integer" Name="maxA" Value="1" />
      <Parameter Type="Integer" Name="MaxB" Value="120" />
      <Parameter Type="String" Name="MaxC" Value="master" />
  </Parameters>     
  </Group>
  <Models>
      <Model Name= "NewPhone"> 
  </Models>
</TestSuite>

所以基本上它删除了子标签。代码如下:-

import os
import xml.etree.ElementTree as ET

def removeChild(fn):
    tree = ET.parse(fn + '.xml')
    root = tree.getroot()
    for grp in root.findall('Group'):
        ch = grp.find('Children')
        grp.remove(ch)
    with open(fn + '_sorted.xml', 'w') as f:
        tree.write(f, encoding='unicode')

path = r"C:\Users\xml_files"

for filename in os.listdir(path):
    if filename.endswith(".xml"):
        fname = os.path.splitext(filename)[0]
        print(fname)
        removeChild(fname)

现在我要做的是将 Test 标记移动到子标记内,但没有重复的参数。正如您在文件 input.xml 中看到的,有一个子组 TestMain,其中包含与父组 TestRoot 相同的参数。我想删除子组及其参数,而不是测试标签。

像这样的 output.xml:-

<?xml version="1.0"?>
<TestSuite Name="DM123">
  <Group Name="TestRoot" ExecutionPolicy="AnyDeviceAnyOrder">
  <Parameters>
      <Parameter Type="Integer" Name="maxA" Value="1" />
      <Parameter Type="Integer" Name="MaxB" Value="120" />
      <Parameter Type="String" Name="MaxC" Value="master" />
  </Parameters>
  <Children>
      <Test Name="TestCam" Namespace="TestCase">
              <Parameters>
                    <Parameter Type="Integer" Name="maxTooth" />
              </Parameters>
      </Test>
      <Test Name="TestDriver" Namespace="TestCase">
              <Parameters>
                    <Parameter Type="Integer" Name="maxP" />
              </Parameters>
          </Test>
      <Test Name="TestField" Namespace="TestCase">
              <Parameters>
                    <Parameter Type="Integer" Name="maxP" />
                       <Requirements>
                         <Requirement TypeId = "Abcdef" Source = "User1" >
                         <Requirement TypeId = "ghijk" Source = "User1" >
                       </Requirements>
              </Parameters>
      </Test>
  </Children>     
  </Group>
  <Models>
      <Model Name= "NewPhone"> 
  </Models>
</TestSuite>

我怎样才能实现这个期望的 output.xml?提前致谢

【问题讨论】:

  • 对于多步 XML 更改,请考虑 XSLT,您可以使用 Python 的第三方模块 lxml 运行它。见demo
  • 我没听懂。
  • 免费到pip install!或者,您可以使用您系统上可能已有的外部XSLT processors:Windows 的System.Xml.Xsl 或Unix 的(Mac/Linux)xsltproc
  • 但是我如何在 python 脚本中使用它呢?
  • 使用Python的subprocess.Popen调用外部程序。

标签: python xml parsing xml-parsing elementtree


【解决方案1】:

对于广泛的 XML 转换,例如跨不同级别组合节点,请考虑 XSLT,这是一种专用于转换 XML 文件的语言。 Python 的lxmletree 的扩展第三方版本)支持 XPath 1.0 和 XSLT 1.0。

XSLT (下面另存为.xsl文件,特殊的.xml文件)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
  </xsl:template>
    
  <xsl:template match="TestSuite/Group">
     <xsl:copy>
       <xsl:apply-templates select="Parameters"/>
       <xsl:apply-templates select="Children"/>
     </xsl:copy>
  </xsl:template>
    
  <xsl:template match="TestSuite/Group/Children">
     <xsl:copy>
       <xsl:apply-templates select="*"/>
       <xsl:apply-templates select="following-sibling::Group/Children/*"/>
     </xsl:copy>
  </xsl:template>
    
</xsl:stylesheet>

Online Demo

Python (使用第三方lxml

import os
import lxml.etree as ET

# LOAD XSLT SCRIPT
xsl = ET.parse(r"C:\Path\To\Script.xsl")

# CONFIGURE TRANSFORMER
transformer = ET.XSLT(xsl)

# ITERATIVELY TRANSFORM AND SAVE RESULT
path = r"C:\Users\xml_files"
for filename in os.listdir(path):
    if filename.endswith(".xml"):
        doc = ET.parse(os.path.join(path, filename))
        xsl_result = transformer(doc)

        new_file = os.path.join(path, filename.replace(".xml", "_new.xml"))
        with open(new_file, 'wb') as f:
            f.write(xsl_result)

【讨论】:

  • 您好,感谢您的详细回答。最后一件事:所以我通过在组标签 TestMain 中添加一个子组来更新 input.xml,即 TestMain1。我怎样才能从该子组中获取该测试标签?
  • IIUC - 遵循与 XSLT 中的 Children 相同的方法,在第二个模板中添加了 apply-templates 行,并为子组使用了全新的模板。请务必在所有 select 值中调整 XPath。使用在线演示进行测试。
猜你喜欢
  • 2021-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-28
  • 1970-01-01
  • 2016-06-10
相关资源
最近更新 更多