Home > Net >  Transform all child siblings into parent-like node
Transform all child siblings into parent-like node

Time:09-25

It is necessary to convert all child elements into a parent level node by making them the same hierarchy level and name. The resulting new elements must contain all the attributes of the child element and retain the attributes of the parent element.

Source XML

<?xml version="1.0" encoding="UTF-8"?>
<entry>

  <line id="001" att1="aaa" att2="bbb" att3="ccc"/>
  <line id="002" att1="ddd" att2="eee" att3="fff"/>
  <line id="003" att1="ggg" att2="hhh" att3="iii">

    <subline  x="name" z="lastname"/>
    <subline  x="name2" z="lastname2"/>
    <underline  a="bar" b="foo"/>
  </line>

</entry>

Desired output

<entry>

  <line id="001" att1="aaa" att2="bbb" att3="ccc"/> <!-- with or without empty x and z attributes' values-->
  <line id="002" att1="ddd" att2="eee" att3="fff"/> <!-- with or without empty x and z values-->
  <line id="003" att1="ggg" att2="hhh" att3="iii" x="name" z="lastname"/>
  <line id="003" att1="ggg" att2="hhh" att3="iii" x="name2" z="lastname2"/>
  <line id="003" att1="ggg" att2="hhh" att3="iii" a="bar" b="foo"/>

</entry>

Present XSLT code

The current code matches only the first child element. I would like to transform all the others

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
  <xsl:output method="xml" indent="yes"/>



  <xsl:template match="line">
    <line>
      <xsl:copy-of select="@*"/>
      <xsl:attribute name="x">
        <xsl:value-of select="subline/@x"/>
      </xsl:attribute>

      <xsl:attribute name="z">
        <xsl:value-of select="subline/@z"/>
      </xsl:attribute>

      <xsl:apply-templates select="node()"/>
    </line>
  </xsl:template>
  
  
    <!-- ===== delete child elements ====== -->
  <xsl:template match="subline"/>
  <xsl:template match="underline"/>


  <!-- ===== [identity] ====== -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  <!-- ==== [identity \ ] ====== -->


</xsl:stylesheet>

additional note (maybe useful): all attribute names are known in advance

CodePudding user response:

I would suggest to approach it like this:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0">

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="line[*]">
    <xsl:apply-templates/>
  </xsl:template>
  
  <xsl:template match="line/*">
    <line>
      <xsl:copy-of select="../@* | @*"/>
    </line>
  </xsl:template>

</xsl:stylesheet>
  • Related