简体   繁体   中英

How to find an element in xml file and place that inside another tag using XSLT?

I have a xml file 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>

I have this 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>

Which is giving me this result:- 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>

So basically the xslt code removes the duplicated parameters which are defined in TestRoot Group. So the parameters defined in TestRoot Group are again defined in other groups so using the current XSLT code it basically removes all the sub groups and its parameters and moves the test tag inside the children tag.

Click for Demo

But if you see in the Field1 Group in its parameter name MaxB has a value field which is overwriting the above parameters of Group TestRoot. What i want is if this is the case than i want to copy that parameter and paste it inside the test tag which is under Group Field1 and similarly for field3 Group.

Desired output:-

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

How can i achieve the desired output as shown using XSLT? Thanks in advance

I think you want to add a template

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

If I understood you correctly you want to copy parameters that have @Value attributes. In this case you can add template that match Parameters and add these parameters.

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

</xsl:stylesheet>

and based on your expected output you need to match only parameters that are ancestors of the Children element.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM