Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert the first HTML table row into a heading row for each table using XSLT

Tags:

html

xml

xslt

I have some html content inside my XML. Previously I could just use <xsl:copy-of select="customFields/customField[@name='mainContent']/html"/> to pull the content into the correct area. A new requirement is to convert the first <tr> inside each table's <tbody> into a set of thead/tr/th.

I am confused on how to convert, in fact not even shore where to start:

...

<customField name="mainContent" type="Html">
    <html>
        <h1>Page Heading</h1>
        <p>Gusto te minim tempor elit quam. Dolore vel accumsan parum option me. Demonstraverunt congue nisl soluta tincidunt seacula. Soluta saepius demonstraverunt praesent claritatem mutationem. Modo te ullamcorper vel augue veniam. Nunc investigationes dolor iriure typi in.</p>
        <p>Gusto te minim tempor elit quam. Dolore vel accumsan parum option me. Demonstraverunt congue nisl soluta tincidunt seacula. Soluta saepius demonstraverunt praesent claritatem mutationem. Modo te ullamcorper vel augue veniam. Nunc investigationes dolor iriure typi in.</p>
        <table cellspacing="0" cellpadding="0" summary="" border="0">
            <tbody>
                <tr>
                    <td>Heading 1</td>
                    <td>Heading 2</td>
                    <td>Heading 3</td>
                </tr>
                <tr>
                    <td>sample</td>
                    <td>sample</td>
                    <td>sample</td>
                </tr>
                <tr>
                    <td>sample</td>
                    <td>sample</td>
                    <td>sample</td>
                </tr>
                <tr>
                    <td>sample</td>
                    <td>sample</td>
                    <td>sample</td>
                </tr>
                <tr>
                    <td>sample</td>
                    <td>sample</td>
                    <td>sample</td>
                </tr>
            </tbody>
        </table>
    </html>
</customField>
...

into:

...
<customField name="mainContent" type="Html">
    <html>
        <h1>Page Heading</h1>
        <p>Gusto te minim tempor elit quam. Dolore vel accumsan parum option me. Demonstraverunt congue nisl soluta tincidunt seacula. Soluta saepius demonstraverunt praesent claritatem mutationem. Modo te ullamcorper vel augue veniam. Nunc investigationes dolor iriure typi in.</p>
        <p>Gusto te minim tempor elit quam. Dolore vel accumsan parum option me. Demonstraverunt congue nisl soluta tincidunt seacula. Soluta saepius demonstraverunt praesent claritatem mutationem. Modo te ullamcorper vel augue veniam. Nunc investigationes dolor iriure typi in.</p>
        <table cellspacing="0" cellpadding="0" summary="" border="0">
            <thead>
                <tr>
                    <th>Heading 1</th>
                    <th>Heading 2</th>
                    <th>Heading 3</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>sample</td>
                    <td>sample</td>
                    <td>sample</td>
                </tr>
                <tr>
                    <td>sample</td>
                    <td>sample</td>
                    <td>sample</td>
                </tr>
                <tr>
                    <td>sample</td>
                    <td>sample</td>
                    <td>sample</td>
                </tr>
                <tr>
                    <td>sample</td>
                    <td>sample</td>
                    <td>sample</td>
                </tr>
            </tbody>
        </table>
    </html>
</customField>
...
like image 897
ConfusedMuch Avatar asked Nov 14 '22 03:11

ConfusedMuch


1 Answers

I have some html content inside my XML. Previously I could just use <xsl:copy-of select="customFields/customField[@name='mainContent']/html"/> to pull the content into the correct area. A new requirement is to convert the first <tr> inside each table's <tbody> into a set of thead/tr/th.

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match="tbody/tr[1]">
  <thead>
    <tr>
      <xsl:apply-templates/>
    </tr>
  </thead>
 </xsl:template>

 <xsl:template match="tbody/tr[1]/td">
  <th><xsl:apply-templates/></th>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<customField name="mainContent" type="Html">
    <html>
        <h1>Page Heading</h1>
        <p>Gusto te minim tempor elit quam. Dolore vel accumsan parum option me. Demonstraverunt congue nisl soluta tincidunt seacula. Soluta saepius demonstraverunt praesent claritatem mutationem. Modo te ullamcorper vel augue veniam. Nunc investigationes dolor iriure typi in.</p>
        <p>Gusto te minim tempor elit quam. Dolore vel accumsan parum option me. Demonstraverunt congue nisl soluta tincidunt seacula. Soluta saepius demonstraverunt praesent claritatem mutationem. Modo te ullamcorper vel augue veniam. Nunc investigationes dolor iriure typi in.</p>
        <table cellspacing="0" cellpadding="0" summary="" border="0">
            <tbody>
                <tr>
                    <td>Heading 1</td>
                    <td>Heading 2</td>
                    <td>Heading 3</td>
                </tr>
                <tr>
                    <td>sample</td>
                    <td>sample</td>
                    <td>sample</td>
                </tr>
                <tr>
                    <td>sample</td>
                    <td>sample</td>
                    <td>sample</td>
                </tr>
                <tr>
                    <td>sample</td>
                    <td>sample</td>
                    <td>sample</td>
                </tr>
                <tr>
                    <td>sample</td>
                    <td>sample</td>
                    <td>sample</td>
                </tr>
            </tbody>
        </table>
    </html>
</customField>

produces exactly the wanted, correct result:

<customField name="mainContent" type="Html">
   <html>
      <h1>Page Heading</h1>
      <p>Gusto te minim tempor elit quam. Dolore vel accumsan parum option me. Demonstraverunt congue nisl soluta tincidunt seacula. Soluta saepius demonstraverunt praesent claritatem mutationem. Modo te ullamcorper vel augue veniam. Nunc investigationes dolor iriure typi in.</p>
      <p>Gusto te minim tempor elit quam. Dolore vel accumsan parum option me. Demonstraverunt congue nisl soluta tincidunt seacula. Soluta saepius demonstraverunt praesent claritatem mutationem. Modo te ullamcorper vel augue veniam. Nunc investigationes dolor iriure typi in.</p>
      <table cellspacing="0" cellpadding="0" summary="" border="0">
         <tbody>
            <thead>
               <tr>
                  <th>Heading 1</th>
                  <th>Heading 2</th>
                  <th>Heading 3</th>
               </tr>
            </thead>
            <tr>
               <td>sample</td>
               <td>sample</td>
               <td>sample</td>
            </tr>
            <tr>
               <td>sample</td>
               <td>sample</td>
               <td>sample</td>
            </tr>
            <tr>
               <td>sample</td>
               <td>sample</td>
               <td>sample</td>
            </tr>
            <tr>
               <td>sample</td>
               <td>sample</td>
               <td>sample</td>
            </tr>
         </tbody>
      </table>
   </html>
</customField>

Do note:

The "overriden identity rule" design pattern is used. This is the most fundamental and powerful XSLT design pattern.

UPDATE:

As noticed by Flynn1179, the OP's definition of the problem (above) is inconsistent with the output he provides as wanted result. In this output not only is the first tr inside of the tbody converted to thead/tr (and its td children to th), but the thead is moved outside of the tbody.

In case this is really what the OP wants, here is modified solution also for this case:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match="tbody/tr[1]">
  <thead>
   <tr>
    <xsl:apply-templates/>
   </tr>
  </thead>
  <tbody>
   <xsl:apply-templates 
        select="following-sibling::tr"/>
  </tbody>
 </xsl:template>

 <xsl:template match="tbody/tr[1]/td">
  <th>
   <xsl:apply-templates/>
  </th>
 </xsl:template>

 <xsl:template match="tbody">
  <xsl:apply-templates select="tr[1]"/>
 </xsl:template>
</xsl:stylesheet>

when applied on the same XML document, the result is:

<customField name="mainContent" type="Html">
   <html>
      <h1>Page Heading</h1>
      <p>Gusto te minim tempor elit quam. Dolore vel accumsan parum option me. Demonstraverunt congue nisl soluta tincidunt seacula. Soluta saepius demonstraverunt praesent claritatem mutationem. Modo te ullamcorper vel augue veniam. Nunc investigationes dolor iriure typi in.</p>
      <p>Gusto te minim tempor elit quam. Dolore vel accumsan parum option me. Demonstraverunt congue nisl soluta tincidunt seacula. Soluta saepius demonstraverunt praesent claritatem mutationem. Modo te ullamcorper vel augue veniam. Nunc investigationes dolor iriure typi in.</p>
      <table cellspacing="0" cellpadding="0" summary="" border="0">
         <thead>
            <tr>
               <th>Heading 1</th>
               <th>Heading 2</th>
               <th>Heading 3</th>
            </tr>
         </thead>
         <tbody>
            <tr>
               <td>sample</td>
               <td>sample</td>
               <td>sample</td>
            </tr>
            <tr>
               <td>sample</td>
               <td>sample</td>
               <td>sample</td>
            </tr>
            <tr>
               <td>sample</td>
               <td>sample</td>
               <td>sample</td>
            </tr>
            <tr>
               <td>sample</td>
               <td>sample</td>
               <td>sample</td>
            </tr>
         </tbody>
      </table>
   </html>
</customField>
like image 143
Dimitre Novatchev Avatar answered Nov 16 '22 15:11

Dimitre Novatchev