XSLT-explorer
XSLT-explorer

Reputation: 97

Transform all child siblings into parent-like node

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

Upvotes: 0

Views: 204

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167401

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>

Upvotes: 1

Related Questions