I'm struggling with XSLT. I need to copy an entire xml file to a new xml file. The input and output should be identical except for the addition of some extra tags around certain elements.

Consider the two versions:

<?xml version="1.0"?>
<document>
<header>
  <general>
    <version>1.14.2</version>
    <form>/XX/ATL_ZI_D007_PURCHASE</form>
    <language>EN</language>
    <device>PRINTER</device>
  </general>
  <archive mode="1" mode-modify-enabled="yes"/>
</header>
<data xml:space="preserve">
  <window name="MAIN_WINDOW" type="main" page="FIRST" page-id="001">
    <table name="DATA" pattern="0001">
    <thead/>
    <tbody>
      <tr ltype="TABLE_POS">
        <tc cell="1" />
      </tr>
    </tbody>
    </table>
  </window>
</data>
</document>
<?xml version="1.0"?>
<document>
<header>
  <general>
    <version>1.14.2</version>
    <form>/XX/ATL_ZI_D007_PURCHASE</form>
    <language>EN</language>
    <device>PRINTER</device>
  </general>
  <archive mode="1" mode-modify-enabled="yes"/>
</header>
<data xml:space="preserve">
  <window name="MAIN_WINDOW" type="main" page="FIRST" page-id="001">
    <table name="DATA" pattern="0001">
    <thead/>
    <tbody>
      <extra>
        <tr ltype="TABLE_POS">
          <tc cell="1" />
        </tr>
      </extra>
    </tbody>
    </table>
  </window>
</data>
</document>

Notice the "extra" tags around the "tr" element. Essentially I want to copy the file, but re-write the "tr" element by surrounding it with additional tags. That's the simplified version.

In actuality, imagine there are multiple "tr" elements, and I wanted the "extra" tags around every group of three:

<table name="DATA" pattern="0001">
    <thead/>
    <tbody>
      <extra>
        <tr ltype="TABLE_POS">
          <tc cell="1" />
        </tr>
        <tr ltype="TABLE_POS">
           <tc cell="1" />
         </tr>
         <tr ltype="TABLE_POS">
           <tc cell="1" />
         </tr>
       </extra>
      <extra>
         <tr ltype="TABLE_POS">
           <tc cell="1" />
         </tr>
         <tr ltype="TABLE_POS">
            <tc cell="1" />
          </tr>
          <tr ltype="TABLE_POS">
            <tc cell="1" />
          </tr>
        </extra>
       <extra>
         <tr ltype="TABLE_POS">
           <tc cell="1" />
         </tr>
         <tr ltype="TABLE_POS">
            <tc cell="1" />
          </tr>
          <tr ltype="TABLE_POS">
            <tc cell="1" />
          </tr>
        </extra>
     </tbody>
    </table>

I appreciate any assistance or references.

If that's a bit too much to tackle, then an explanation of the basic technique to modify a single child element would at least get me started. If I had this for example:

<?xml version="1.0"?>
<sandwich>
  <bread type="rye" />
  <ingredient>Peanut Butter</ingredient>
  <ingredient>Jelly</ingredient>
</sandwich>

And I want to copy it, but wanted to transform the bread element to: <bread>Wheat</bread> , how would I do that?

Ok, figured out this much:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" />
 
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

 <xsl:template match="tr">
<extra>
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:apply-templates select="node()"/>
    </xsl:copy>
</extra>
 </xsl:template>

</xsl:stylesheet>

That's a huge step in the right direction, but of course it puts the "extra" tags around every "tr". I want to group every three "tr" elements. Anyone?

Am I confusing everyone? Or do we not have any XML pros as members? Let me restate as simply but as completely as possible.

Given the following XML input file:

<?xml version="1.0"?>
<document>
<table>
<tbody>
  <tr>1</tr>
  <tr>2</tr>
  <tr>3</tr>
  <tr>4</tr>
  <tr>5</tr>
  <tr>6</tr>
  <tr>7</tr>
  <tr>8</tr>
  <tr>9</tr>
  <tr>10</tr>
  <tr>11</tr>
</tbody>
</table>
</document>

I want to produce the following result file:

<?xml version="1.0"?>
<document>
<table>
<tbody>
  <extra>
    <tr>1</tr>
    <tr>2</tr>
    <tr>3</tr>
  </extra>
  <extra>
    <tr>4</tr>
    <tr>5</tr>
    <tr>6</tr>
  </extra>
  <extra>
     <tr>7</tr>
    <tr>8</tr>
    <tr>9</tr>
  </extra>
  <extra>
    <tr>10</tr>
    <tr>11</tr>
  </extra>
</tbody>
</table>
</document>

So far I have the following XSLT. It's overly complex, it's meant to provide multiple points to insert the necessary logic. It produces:

<?xml version="1.0"?>
<document>
<table>
<tbody>
  <extra>
  <tr>1</tr>
  <tr>2</tr>
  <tr>3</tr>
  <tr>4</tr>
  <tr>5</tr>
  <tr>6</tr>
  <tr>7</tr>
  <tr>8</tr>
  <tr>9</tr>
  <tr>10</tr>
  <tr>11</tr>
  </extra>
</tbody>
</table>
</document>

XSLT Program:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  
  <xsl:output method="xml" indent="yes" />

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

 <xsl:template match="tbody">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
     <!-- somehow I need to do this for every THREE "tr" elements -->
      <extra>
        <xsl:call-template name="trGroup" />
      </extra>
     <!--  -->
    </xsl:copy>
 </xsl:template>


<xsl:template name="trGroup">

    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:apply-templates select="node()"/>
    </xsl:copy>

</xsl:template>


</xsl:stylesheet>

I solved this with a combination of two recursive templates and creative use of the "copy-of" function.

sorry I didn't spot this in time, been rather busy with other things.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.