[xsl] Re: Grouping flat HTML at multiple levels

Subject: [xsl] Re: Grouping flat HTML at multiple levels
From: Mark Peters <markpeters.work@xxxxxxxxx>
Date: Wed, 3 Oct 2012 08:39:53 -0400
To be specific, here's the part of the stylesheet that I'm having
difficulties with:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
version="2.0" xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/";>
<xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>

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

  <xsl:template match="body">
  <xsl:for-each-group select="*" group-starting-with="h1">
      <topic>
        <xsl:apply-templates select="current-group()[self::h1]" />

<!-- Grouping of unordered list items -->
        <xsl:for-each-group select="current-group() except ."
group-adjacent="@class='ListBullet'  or @class='ListBulletLast'">
        <xsl:choose>
          <xsl:when test="current-grouping-key()">
            <ul>
              <xsl:for-each-group select="current-group()"
group-adjacent="matches(@class, 'ListBullet')">
                <li>
                  <xsl:apply-templates/>
                </li>
              </xsl:for-each-group>
            </ul>
          </xsl:when>
        </xsl:choose>
      </xsl:for-each-group>

<!-- Grouping of ordered list items -->
      <xsl:for-each-group select="current-group() except ."
group-adjacent="@class='ListNumber'  or @class='ListNumberLast'">
        <xsl:choose>
          <xsl:when test="current-grouping-key()">
            <ol>
              <xsl:for-each-group select="current-group()"
group-adjacent="matches(@class, 'ListNumber')">
                <li>
                  <xsl:apply-templates/>
                </li>
              </xsl:for-each-group>
            </ol>
          </xsl:when>
        </xsl:choose>
      </xsl:for-each-group>

        <xsl:for-each-group select="current-group() except ."
group-starting-with="h2|h3">
          <xsl:choose>
            <xsl:when test="self::h2">
              <topic>
                <xsl:apply-templates select="current-group()[self::*]" />
              </topic>
            </xsl:when>
            <xsl:when test="self::h3">
              <topic>
                <xsl:apply-templates select="current-group()[self::*]" />
              </topic>
            </xsl:when>
            <xsl:otherwise>
              <xsl:apply-templates select="current-group()[self::*]" />
            </xsl:otherwise>
          </xsl:choose>
        </xsl:for-each-group>
      </topic>
    </xsl:for-each-group>
    </xsl:template>

  <xsl:template match="h1"><title><xsl:value-of
select="."/></title></xsl:template>
  <xsl:template match="h2"><title><xsl:value-of
select="."/></title></xsl:template>
  <xsl:template match="h3"><title><xsl:value-of
select="."/></title></xsl:template>

</xsl:stylesheet>

Thanks for any help you could offer.

Best,
Mark

On Tue, Oct 2, 2012 at 11:50 AM, Mark Peters <markpeters.work@xxxxxxxxx> wrote:
> Hi,
>
> My doc team is currently moving our help content from HTML to DITA
> XML. The HTML is a flat. Most text is stored in <p> nodes with CSS
> @class tags.
>
> So far, I've been able to group the <h1/>,< h2/>, and <h3/> elements
> in generic <topic/> nodes.
>
> Where I'm tripping up is the second layer of grouping inside each of
> the <h1/>,< h2/>, and <h3/> groups.
>
> Here's where I need help:
>
> Nest each group of <p class="ListNumber"> and <p
> class="ListNumberLast"> nodes as <li> within <ol>.
> Nest each group of <p class="ListBullet"> and <p
> class="ListBulletLast"> nodes as <li> within <ul>.
>
> I'll copy the rest of the <p/> nodes as they are.
>
>
> Here's an example of the input:
>
> <?xml version="1.0" encoding="UTF-8"?>
> <html>
>     <head>
>         <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
>         <meta name="generator" content="Adobe RoboHelp 9"/>
>         <title>Configuring Profile Headers</title>
>         <link rel="StyleSheet" href="../css/opus_help.css" type="text/css"/>
>     </head>
>     <body>
>         <h1>
>             <a name="Configuring_Profile_
> Headers" id="Configuring_Profile_Headers" shape="rect"/>Configuring
> Profile Headers</h1>
>         <p>You can control the content and appearance of a profile
> header using the Profile Header Editor.</p>
>         <p>In the Profile Header Editor, you can:</p>
>         <p class="ListBullet">
>             <a href="#Adding__Deleting__and_Repositioning_Fields"
> shape="rect">Add, delete and reposition fields</a>
>         </p>
>         <p class="ListBullet">
>             <a href="#Formatting_Field_Labels_and_Cells"
> shape="rect">Format field labels and cells</a>
>         </p>
>         <p class="ListBullet">
>             <a href="#Adding_Conditions_to_Fields" shape="rect">Add
> conditions to profile header fields</a>
>         </p>
>         <p class="ListBullet">
>             <a href="#Adding_Symbols_to_Fields" shape="rect">Add symbols</a>
>         </p>
>         <p class="ListBulletLast">
>             <a href="#Previewing_the_Profile_Header"
> shape="rect">Preview changes</a>
>         </p>
>         <p class="To">To open the profile header in the Profile Header
> Editor:</p>
>         <p class="ListNumber">In the Profile Header page, click to
> select the profile header you want to edit.</p>
>         <p class="ListNumberLast">Click <span style="font-weight:
> bold;">Edit</span>. The profile header opens in the Profile Header
> Editor.</p>
>         <p class="To">To close the Profile Editor:</p>
>         <p class="ListBulletLast">Click  <span class="ListBold">File
> &gt; Close</span>.</p>
>         <h2>
>             <a name="Adding__Deleting__and_Repositioning_Fields"
> id="Adding__Deleting__and_Repositioning_Fields" shape="rect"/>Adding,
> Deleting, and Repositioning Fields</h2>
>         <p class="To">To add a field to a profile header:</p>
>         <p class="ListNumber">Find the field in the Domain Fields
> panel that you want to add to the profile header.</p>
>         <p class="ListNumber">Click and hold the field and drag it
> into the profile header template.</p>
>         <p class="ListNumber">Release the field to add it to the
> profile header.</p>
>         <p class="ListNumberLast">Repeat until all needed fields are
> added to the profile header.</p>
>         <p class="To">To remove a field from a profile header:</p>
>         <p class="ListNumber">In the profile header template, click to
> select the field you want to remove from the profile header.</p>
>         <p class="ListNumberLast">Click the <span style="font-weight:
> bold;">delete</span> button <img src="../Images/Editor Icons -
> Delete.jpg" alt="" style="border: none;" width="22" height="22"
> border="0"/> in the upper right corner of the profile header template.
> The field is removed from the profile header template.</p>
>         <p class="To">To position a field in a profile header:</p>
>         <p class="ListNumber">In the profile header template, click
> and hold the field.</p>
>         <p class="ListNumber">Drag it into the new position. The
> position for the field is indicated by a vertical line.</p>
>         <p class="ListNumberLast">Release the field.</p>
>         <h3>
>             <a name="Styles" id="Styles" shape="rect"/>Styles</h3>
>         <p>Selecting a field style allows you to highlight or
> emphasize a field in a profile. You can set a default style and change
> the style based on one or more conditions. See Conditional  Field
> Styles for more information.</p>
>         <p>To set a default style for a cell:</p>
>         <p class="ListNumber">Click the cell you want to set a style for.</p>
>         <p class="ListNumberLast">Use the Default Style drop-down menu
> to select a style.</p>
>     </body>
> </html>
>
> Here's approximately where I want to go:
>
> <topic>
>     <title>Configuring Profile Headers</title>
>     <body>
>         <p>You can control the content and appearance of a profile
> header using the Profile Header Editor.</p>
>         <p>In the Profile Header Editor, you can:</p>
>         <ul>
>             <li>
>                 <a href="#Adding__Deleting__and_Repositioning_Fields"
> shape="rect">Add, delete and reposition fields</a>
>             </li>
>             <li>
>                 <a href="#Formatting_Field_Labels_and_Cells"
> shape="rect">Format field labels and cells</a>
>             </li>
>             <li>
>                 <a href="#Adding_Conditions_to_Fields"
> shape="rect">Add conditions to profile header fields</a>
>             </li>
>             <li>
>                 <a href="#Adding_Symbols_to_Fields" shape="rect">Add symbols</a>
>             </li>
>             <li>
>                 <a href="#Previewing_the_Profile_Header"
> shape="rect">Preview changes</a>
>             </li>
>         </ul>
>         <p>To open the profile header in the Profile Header Editor:</p>
>         <ol>
>             <li>In the Profile Header page, click to select the
> profile header you want to edit.</li>
>             <li>Click <span style="font-weight: bold;">Edit</span>.
> The profile header opens in the Profile Header Editor.</li>
>         </ol>
>         <p>To close the Profile Editor:</p>
>         <ul>
>             <li>Click  <span class="ListBold">File &gt; Close</span>.</li>
>         </ul>
>     </body>
>     <topic>
>         <title>Adding, Deleting, and Repositioning Fields</title>
>         <body>
>             <p>To add a field to a profile header:</p>
>             <ol>
>                 <li>Find the field in the Domain Fields panel that you
> want to add to the profile header.</li>
>                 <li>Click and hold the field and drag it into the
> profile header template.</li>
>                 <li>Release the field to add it to the profile header.</li>
>                 <li>Repeat until all needed fields are added to the
> profile header.</li>
>             </ol>
>             <p>To remove a field from a profile header:</p>
>             <ol>
>                 <li>In the profile header template, click to select
> the field you want to remove from the profile header.</li>
>                 <li>Click the <span style="font-weight:
> bold;">delete</span> button <img src="../Images/Editor Icons -
> Delete.jpg" alt="" style="border: none;" width="22" height="22"
> border="0"/> in the upper right corner of the profile header template.
> The field is removed from the profile header template.</li>
>             </ol>
>             <p>To position a field in a profile header:</p>
>             <ol>
>                 <li>In the profile header template, click and hold the
> field.</li>
>                 <li>Drag it into the new position. The position for
> the field is indicated by a vertical line.</li>
>                 <li>Release the field.</li>
>             </ol>
>         </body>
>         <topic>
>             <title>Styles</title>
>             <body>
>                 <p>Selecting a field style allows you to highlight or
> emphasize a field in a profile. You can set a default style and change
> the style based on one or more conditions. See Conditional  Field
> Styles for more information.</p>
>                 <p>To set a default style for a cell:</p>
>                 <ol>
>                     <li>Click the cell you want to set a style for.</li>
>                     <li>Use the Default Style drop-down menu to select
> a style.</li>
>                 </ol>
>             </body>
>         </topic>
>     </topic>
> </topic>
>
> Here's my current stylesheet:
>
> <?xml version="1.0"?>
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
> version="2.0" xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/";>
> <xsl:output method="xml" indent="yes"/>
>     <xsl:strip-space elements="*"/>
>
>     <xsl:template match="@* | node()">
>     <xsl:copy>
>       <xsl:apply-templates select="@* , node()"/>
>     </xsl:copy>
>   </xsl:template>
>
>   <xsl:template match="body">
>   <xsl:for-each-group select="*" group-starting-with="h1">
>       <topic>
>         <xsl:apply-templates select="current-group()[self::h1]" />
>         <xsl:for-each-group select="current-group() except ."
> group-adjacent="@class='ListBullet'  or @class='ListBulletLast'">
>         <xsl:choose>
>           <xsl:when test="current-grouping-key()">
>             <ul>
>               <xsl:for-each-group select="current-group()"
> group-adjacent="matches(@class, 'ListBullet')">
>                 <li>
>                   <xsl:apply-templates/>
>                 </li>
>               </xsl:for-each-group>
>             </ul>
>           </xsl:when>
>         </xsl:choose>
>       </xsl:for-each-group>
>       <xsl:for-each-group select="current-group() except ."
> group-adjacent="@class='ListNumber'  or @class='ListNumberLast'">
>         <xsl:choose>
>           <xsl:when test="current-grouping-key()">
>             <ol>
>               <xsl:for-each-group select="current-group()"
> group-adjacent="matches(@class, 'ListNumber')">
>                 <li>
>                   <xsl:apply-templates/>
>                 </li>
>               </xsl:for-each-group>
>             </ol>
>           </xsl:when>
>         </xsl:choose>
>       </xsl:for-each-group>
>         <xsl:for-each-group select="current-group() except ."
> group-starting-with="h2|h3">
>           <xsl:choose>
>             <xsl:when test="self::h2">
>               <topic>
>                 <xsl:apply-templates select="current-group()[self::*]" />
>               </topic>
>             </xsl:when>
>             <xsl:when test="self::h3">
>               <topic>
>                 <xsl:apply-templates select="current-group()[self::*]" />
>               </topic>
>             </xsl:when>
>             <xsl:otherwise>
>               <xsl:apply-templates select="current-group()[self::*]" />
>             </xsl:otherwise>
>           </xsl:choose>
>         </xsl:for-each-group>
>       </topic>
>     </xsl:for-each-group>
>     </xsl:template>
>
>   <xsl:template match="h1"><title><xsl:value-of
> select="."/></title></xsl:template>
>   <xsl:template match="h2"><title><xsl:value-of
> select="."/></title></xsl:template>
>   <xsl:template match="h3"><title><xsl:value-of
> select="."/></title></xsl:template>
>
> </xsl:stylesheet>
>
>
> And here's the output so far:
>
> <html>
>     <head>
>         <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
>         <meta name="generator" content="Adobe RoboHelp 9"/>
>         <title>Configuring Profile Headers</title>
>         <link rel="StyleSheet" href="../css/opus_help.css" type="text/css"/>
>     </head>
>     <topic xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/";>
>         <title>Configuring Profile Headers</title>
>         <ul>
>             <li>
>                 <a href="#Adding__Deleting__and_Repositioning_Fields"
> shape="rect">Add, delete and reposition fields</a>
>             </li>
>         </ul>
>         <ul>
>             <li>Click  <span class="ListBold">File &gt; Close</span>.</li>
>         </ul>
>         <ol>
>             <li>In the Profile Header page, click to select the
> profile header you want to edit.</li>
>         </ol>
>         <ol>
>             <li>Find the field in the Domain Fields panel that you
> want to add to the profile header.</li>
>         </ol>
>         <ol>
>             <li>In the profile header template, click to select the
> field you want to remove from the profile header.</li>
>         </ol>
>         <ol>
>             <li>In the profile header template, click and hold the field.</li>
>         </ol>
>         <ol>
>             <li>Click the cell you want to set a style for.</li>
>         </ol>
>         <p>You can control the content and appearance of a profile
> header using the Profile Header Editor.</p>
>         <p>In the Profile Header Editor, you can:</p>
>         <p class="ListBullet">
>             <a href="#Adding__Deleting__and_Repositioning_Fields"
> shape="rect">Add, delete and reposition fields</a>
>         </p>
>         <p class="ListBullet">
>             <a href="#Formatting_Field_Labels_and_Cells"
> shape="rect">Format field labels and cells</a>
>         </p>
>         <p class="ListBullet">
>             <a href="#Adding_Conditions_to_Fields" shape="rect">Add
> conditions to profile header fields</a>
>         </p>
>         <p class="ListBullet">
>             <a href="#Adding_Symbols_to_Fields" shape="rect">Add symbols</a>
>         </p>
>         <p class="ListBulletLast">
>             <a href="#Previewing_the_Profile_Header"
> shape="rect">Preview changes</a>
>         </p>
>         <p class="To">To open the profile header in the Profile Header
> Editor:</p>
>         <p class="ListNumber">In the Profile Header page, click to
> select the profile header you want to edit.</p>
>         <p class="ListNumberLast">Click <span style="font-weight:
> bold;">Edit</span>. The profile header opens in the Profile Header
> Editor.</p>
>         <p class="To">To close the Profile Editor:</p>
>         <p class="ListBulletLast">Click  <span class="ListBold">File
> &gt; Close</span>.</p>
>         <topic>
>             <title>Adding, Deleting, and Repositioning Fields</title>
>             <p class="To">To add a field to a profile header:</p>
>             <p class="ListNumber">Find the field in the Domain Fields
> panel that you want to add to the profile header.</p>
>             <p class="ListNumber">Click and hold the field and drag it
> into the profile header template.</p>
>             <p class="ListNumber">Release the field to add it to the
> profile header.</p>
>             <p class="ListNumberLast">Repeat until all needed fields
> are added to the profile header.</p>
>             <p class="To">To remove a field from a profile header:</p>
>             <p class="ListNumber">In the profile header template,
> click to select the field you want to remove from the profile
> header.</p>
>             <p class="ListNumberLast">Click the <span
> style="font-weight: bold;">delete</span> button <img
> src="../Images/Editor Icons - Delete.jpg" alt="" style="border: none;"
> width="22" height="22" border="0"/> in the upper right corner of the
> profile header template. The field is removed from the profile header
> template.</p>
>             <p class="To">To position a field in a profile header:</p>
>             <p class="ListNumber">In the profile header template,
> click and hold the field.</p>
>             <p class="ListNumber">Drag it into the new position. The
> position for the field is indicated by a vertical line.</p>
>             <p class="ListNumberLast">Release the field.</p>
>         </topic>
>         <topic>
>             <title>Styles</title>
>             <p>Selecting a field style allows you to highlight or
> emphasize a field in a profile. You can set a default style and change
> the style based on one or more conditions. See Conditional  Field
> Styles for more information.</p>
>             <p>To set a default style for a cell:</p>
>             <p class="ListNumber">Click the cell you want to set a
> style for.</p>
>             <p class="ListNumberLast">Use the Default Style drop-down
> menu to select a style.</p>
>         </topic>
>     </topic>
> </html>
>
> As you can see, the current stylesheet groups unordered list items
> first (and nests each list item in its own <ul/> node), then groups
> ordered list items (and nests each list item in its own <ul/> node),
> and then displays the rest of the content.
>
> I've tried approaching this challenge a variety of ways, without success.
>
> Thanks in advance for any help you can offer.
>
> Best,
> Mark



-- 
Senior technical writer
Saba Software, Inc.

Current Thread