如何使用 XSLT 在 xml 文件中查找元素并将其放置在另一个标记中?

Posted

技术标签:

【中文标题】如何使用 XSLT 在 xml 文件中查找元素并将其放置在另一个标记中?【英文标题】:How to find an element in xml file and place that inside another tag using XSLT? 【发布时间】:2021-09-18 01:22:03 【问题描述】:

我有一个xml文件ab.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="integration" />
    </Parameters>
    <Children>
      <Group Name="Cam1">
        <Parameters>
           <Parameter Type="Integer" Name="maxA" />
           <Parameter Type="Integer" Name="MaxB"/>
           <Parameter Type="String" Name="MaxC" />
        </Parameters>
        <Children>
          <Group Name="Field1">
            <Parameters>
              <Parameter Type="Integer" Name="maxA" />
              <Parameter Type="Integer" Name="MaxB" Value="1600" />
              <Parameter Type="String" Name="MaxC" />
            </Parameters>
            <Children>
              <Test Name="Test1" Namespace="TestCases">
                <Parameters>
                  <Parameter Type="Device" Name="Device">
                    <Requirements>
                      <Requirement TypeId="a76" Source="User" />
                      <Requirement TypeId="2c9" Source="User" />
                    </Requirements>
                  </Parameter>
                </Parameters>
              </Test>
            </Children>
          </Group>
          <Group Name="Field3">
            <Parameters>
              <Parameter Type="Integer" Name="maxA" />
              <Parameter Type="Integer" Name="MaxB" />
              <Parameter Type="String" Name="MaxC" Value="51" />
            </Parameters>
            <Children>
              <Test Name="Test5" Namespace="TestCases">
                <Parameters>
                  <Parameter Type="Dev" Name="Dev">
                    <Requirements>
                      <Requirement TypeId="a76" Source="User" />
                      <Requirement TypeId="2c9" Source="User" />
                    </Requirements>
                  </Parameter>
                </Parameters>
              </Test>
            </Children>
          </Group>
        </Children>  
      </Group>
    </Children>
  </Group>
  <Models>
    <Model Name="DD1" />
  </Models>
</TestSuite>

我有这个 XSLT

<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="Group[@Name = 'TestRoot']/Children">
     <xsl:copy>
      <xsl:apply-templates select=".//Test"/>
     </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

这给了我这个结果:- output.xml

<?xml version="1.0" encoding="UTF-8"?>
<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="integration"/>
      </Parameters>
      <Children>
         <Test Name="Test1" Namespace="TestCases">
            <Parameters>
               <Parameter Type="Device" Name="Device">
                  <Requirements>
                     <Requirement TypeId="a76" Source="User"/>
                     <Requirement TypeId="2c9" Source="User"/>
                  </Requirements>
               </Parameter>
            </Parameters>
         </Test>
         <Test Name="Test5" Namespace="TestCases">
            <Parameters>
               <Parameter Type="Dev" Name="Dev">
                  <Requirements>
                     <Requirement TypeId="a76" Source="User"/>
                     <Requirement TypeId="2c9" Source="User"/>
                  </Requirements>
               </Parameter>
            </Parameters>
         </Test>
       </Children>
   </Group>
   <Models>
      <Model Name="DD1"/>
   </Models>
</TestSuite>

所以基本上 xslt 代码删除了在 TestRoot 组中定义的重复参数。因此,在 TestRoot Group 中定义的参数再次在其他组中定义,因此使用当前的 XSLT 代码,它基本上删除了所有子组及其参数,并将测试标签移动到子标签内。

点击Demo

但是如果你在 Field1 Group 中看到它的参数名称 MaxB 有一个 value 字段覆盖了 Group TestRoot 的上述参数。如果是这种情况,我想要的是复制该参数并将其粘贴到 Group Field1 下的测试标签中,对于 field3 Group 也是如此。

期望的输出:-

<?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="integration" />
    </Parameters>
    <Children>
      <Test Name="Test1" Namespace="TestCases">
        <Parameters>
           <Parameter Type="Integer" Name="MaxB" Value="1600" />
           <Parameter Type="Device" Name="Device">
             <Requirements>
               <Requirement TypeId="a76" Source="User" />
               <Requirement TypeId="2c9" Source="User" />
             </Requirements>
           </Parameter>
        </Parameters>
      </Test>
      <Test Name="Test5" Namespace="TestCases">
            <Parameters>
               <Parameter Type="String" Name="MaxC" Value="51" />
               <Parameter Type="Dev" Name="Dev">
                  <Requirements>
                     <Requirement TypeId="a76" Source="User"/>
                     <Requirement TypeId="2c9" Source="User"/>
                  </Requirements>
               </Parameter>
            </Parameters>
         </Test>
   </Children>
  </Group>
  <Models>
    <Model Name="DD1" />
  </Models>
</TestSuite>

如何使用 XSLT 实现所需的输出?提前致谢

【问题讨论】:

【参考方案1】:

我想你想添加一个模板

<xsl:template match="Test/Parameters">
    <xsl:copy>
        <xsl:apply-templates select="@* | ../../preceding-sibling::Parameters[1]/Parameter[@Value] | node()"/>
    </xsl:copy>
</xsl:template>

【讨论】:

【参考方案2】:

zykxPython,如果我理解正确,您想复制具有 @Value 属性的参数。在这种情况下,您可以添加与参数匹配的模板并添加这些参数。

<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="Group[@Name = 'TestRoot']/Children">
    <xsl:copy>
        <xsl:apply-templates select=".//Test"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="Parameters[ancestor::Children]">
    <xsl:copy>
        <xsl:if test="ancestor::Group[1]/Parameters/Parameter[@Value]">
            <xsl:copy-of select="ancestor::Group[1]/Parameters/Parameter[@Value]"/>
        </xsl:if>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>

样式表>

根据您的预期输出,您只需要匹配作为 Children 元素的祖先的参数。

如果它适合你,请告诉我。

谢谢, 瓦西尔

【讨论】:

以上是关于如何使用 XSLT 在 xml 文件中查找元素并将其放置在另一个标记中?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 XSLT 从 XML 中删除元素标记

使用 Python 或 XSLT 将复杂的 XML 转换为 CSV

如何使用带有样式表和 xsltproc 的 xslt 从 xml 中删除元素?

获取元素的值并使其成为 XSLT 中属性的值?

使用 XSLT 进行空前缀转换的 XML [重复]

XSLT - 在多个文件时选择唯一元素