[Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 67
  • Last Modified:

XSLT list item selection criteria not working

I have an XSLT stylesheet that generates three types of output: tables, paragraphs and lists. I am able to generate tables and paragraphs, but the list item selection criteria is not working.

Here is the XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
    
    <xsl:output indent="yes" method="xhtml"/>
    <xsl:strip-space elements="*"/>
     
    <xsl:template match="document">
        <html>
            <head/>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>
    
    
    <xsl:template match="par">
        
        <!-- if immediate preceding-sibling pardef does not have a @list attribute, create a closing tag for unordered list -->
        <xsl:if test="@id and preceding-sibling::pardef[1][not(@list)]">
            <xsl:text disable-output-escaping="yes">&lt;/ul&gt;</xsl:text>
        </xsl:if>
        
        <xsl:choose>
            <!-- if immediate preceding-sibling pardef has a @list attribute, grab @id and create an opening tag for unordered list -->
            <xsl:when test="preceding-sibling::pardef[1][@list = 'bullet']">
                <xsl:variable name="list_id" select="preceding-sibling::pardef[1][@id]" />
                <xsl:text disable-output-escaping="yes">&lt;ul&gt;</xsl:text>
                
                <!-- if par @id matches pardef @id, create a bullet point -->
                <xsl:for-each select="par[@id='$list_id']">
                    <li><xsl:apply-templates select="run"/></li>  
                </xsl:for-each>
            </xsl:when>
            
            <!-- if par does not have @id or does not match pardef @id, create a normal paragraph -->
            <xsl:when test="not(@id='$list_id')">
                <p><xsl:apply-templates select="run"/></p>    
            </xsl:when>     
            
        </xsl:choose>  
        
    </xsl:template>
    
    <xsl:template match="table">
        <table border="1">
            <xsl:for-each select="tablerow">
                <tr>
                    <xsl:for-each select="tablecell">
                        <td>
                            <xsl:apply-templates />
                        </td>
                    </xsl:for-each>
                </tr>
            </xsl:for-each>
        </table>      
    </xsl:template>
    
    <xsl:template match="run">
        <xsl:value-of select="text()" separator=""/>
    </xsl:template>
    
</xsl:stylesheet>

Open in new window


Here is the XML:

<?xml version="1.0" encoding="UTF-8"?>
<document>
    <item name="Some richtext">
        <richtext>
            <pardef/>
            <par def="20">
                <run>This is a </run>
                <run>paragraph.</run>
            </par>
            <table>
                <tablerow>
                    <tablecell>
                        <par def="43"><run>This is a table</run></par></tablecell>
                    <tablecell>
                        <par def="44"><run>This is some data</run></par></tablecell>
                </tablerow>
            </table>
            <pardef id="21" list="bullet"/>
            <par def="21">
                <run>This is a </run>
                <run>bullet point.</run>
            </par>
            <table>
                <tablerow>
                    <tablecell>
                        <par def="43"><run>This is another table</run></par></tablecell>
                    <tablecell>
                        <par def="44"><run>This is some data</run></par></tablecell>
                </tablerow>
            </table>
        </richtext>
    </item>
</document>

Open in new window


And here is the desired output:

    <html>
       <head></head>
      <body>
         <p>This is a paragraph.</p>
         <table border="1">
            <tr>
               <td>This is a table</td>
               <td>This is some data</td>
            </tr>
         </table>
         <ul>
            <li>This is a bullet point.</li>
         </ul>
         <table border="1">
               <tr>
                  <td>This is another table</td>
                  <td>This is some data</td>
               </tr>
         </table>
      </body>
   </html>

Open in new window

0
mariita
Asked:
mariita
  • 7
  • 5
1 Solution
 
Geert BormansCommented:
I think you are going through a lot of trouble in your stylesheet because your are not telling us a crucial bit of information
... I think you want

           <pardef id="21" list="bullet"/>
            <par def="21">
                <run>This is a </run>
                <run>bullet point.</run>
            </par>
            <par def="21">
                <run>This is a second </run>
                <run>bullet point.</run>
            </par>

To become 1 list with two list items?
Correct?

You are using XSLT2 so you have a lot of options to properly group the list items into lists

One advice.... NEVER EVER use disable output escaping for working around the requierment that an XSLT is wellformed
it is an attempt to do procedural programming in a declarative programming language and it is a headache for maintenance
0
 
mariitaAuthor Commented:
You're right... there should be one list with two bullet points. I've greatly simplified the various files, and that got lost in translation.
0
 
mariitaAuthor Commented:
Note: I am working with legacy XML from a Lotus Notes app. The XML is technically well-formed, but it has oddities, such as the closed <pardef list='bullet' /> tag to indicate the start of a list.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
Geert BormansCommented:
Don't worry, I have done my share of MS Word XML transformations.... it has similar constructs ;-)

Close to making an example working
0
 
Geert BormansCommented:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
     exclude-result-prefixes="xs"
    version="2.0">
    
    <xsl:output indent="yes" method="xhtml"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="document">
        <html>
            <head/>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>
    
    <xsl:template match="richtext">
        <xsl:for-each-group select="node()" group-starting-with="table | pardef">
            <xsl:choose>
                <xsl:when test="current-group()/self::table">
                    <xsl:apply-templates select="current-group()"/>
                </xsl:when>
                <xsl:when test="current-group()/self::pardef[not(@id)]">
                    <xsl:apply-templates select="current-group()/self::par" mode="p"/>
                </xsl:when>
                <xsl:when test="current-group()/self::pardef[@id][@list = 'bullet']">
                    <ul>
                        <xsl:apply-templates select="current-group()/self::par" mode="li"/>
                    </ul>
                </xsl:when>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:template>
    
    <xsl:template match="par" mode="p">
        <p>
            <xsl:apply-templates select="node()"/>
        </p>
    </xsl:template>
    
    <xsl:template match="par" mode="li">
        <li>
            <xsl:apply-templates select="node()"/>
        </li>
    </xsl:template>

    <xsl:template match="table">
        <table border="1">
            <xsl:apply-templates select="tablerow"/>
        </table>
    </xsl:template>

    <xsl:template match="tablerow">
        <tr>
            <xsl:apply-templates select="tablecell"/>
        </tr>
    </xsl:template>
    
    <xsl:template match="tablecell">
        <td>
            <xsl:apply-templates />
        </td>
    </xsl:template>
    
    
    <xsl:template match="run">
        <xsl:value-of select="text()" separator=""/>
    </xsl:template>
    
</xsl:stylesheet>

Open in new window


Ignoring the id of the list items, I believe they only play when you have nested lists
(we will tackle that at a next grouping level when we need to... it is hard stuff ;-)
The above stylesheet is definitely something to build on. If the XML is more complex than what you sent,
you will b every happy to have an extensible base... yours was a mess to build on

remember
- avoid for-each as you were doing in the table element as much as possible
- avoid disable-output-escaping AT ALL COST
0
 
mariitaAuthor Commented:
That worked with the simplified data, but not with the real data, which unfortunately I can't post. I may have oversimplified the XML snippet.

The IDs matter because each document can have multiple lists and each list has a unique ID. In addition, sometimes bullet points are interspersed with <par> elements that should be disregarded because they don't have the ID specific to the list.
0
 
Geert BormansCommented:
well, I can only comment on XML that I actually see
you have posted a required result and I think you have a solid base to work from

I guess, your task now is to either continue yourself
or make a realistic example based on the real data
it is not that hard to keep the structure and cut away the sensitive text
0
 
Geert BormansCommented:
about the ID, that is only a small change,
inside the list group you can call out for only those bullet items with the correct ID
as I said, complexity is not there but in the nested lists if they occur in your data

I am not going to change anything based on vague descriptions, I need hard xml data
0
 
mariitaAuthor Commented:
The real XML looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="AllTogether11.xslt"?>
<document>
    <item name="Some richtext">
        <richtext>
            <pardef/>
            <par def="20">
                <run>This is a </run>
                <run>paragraph.</run>
            </par>
            <table>
                <tablerow>
                    <tablecell>
                        <par def="43"><run>This is a table</run></par></tablecell>
                    <tablecell>
                        <par def="44"><run>This is some data</run></par></tablecell>
                </tablerow>
            </table>
            <pardef id="21" list="bullet"/>
            <par def="21">
                <run>This is a </run>
                <run>bullet point.</run>
            </par>
            <par />
            <par def="21">
                <run>This is another </run>
                <run>bullet point.</run>
            </par>
            <table>
                <tablerow>
                    <tablecell>
                        <par def="43"><run>This is another table</run></par></tablecell>
                    <tablecell>
                        <par def="44"><run>This is some data</run></par></tablecell>
                </tablerow>
            </table>
            <pardef id="65" list="bullet"/>
            <par def="65">
                <run>This is a </run>
                <run>bullet point.</run>
            </par>
            <par id="20"/>
            <par def="65">
                <run>This is another </run>
                <run>bullet point.</run>
            </par>    
        </richtext>
    </item>
</document>

Open in new window

0
 
Geert BormansCommented:
That is not too bad a difference

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
     exclude-result-prefixes="xs"
    version="2.0">
    
    <xsl:output indent="yes" method="xhtml"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="document">
        <html>
            <head/>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>
    
    <xsl:template match="richtext">
        <xsl:for-each-group select="node()" group-starting-with="table | pardef">
            <xsl:choose>
                <xsl:when test="current-group()/self::table">
                    <xsl:apply-templates select="current-group()"/>
                </xsl:when>
                <xsl:when test="current-group()/self::pardef[not(@id)]">
                    <xsl:apply-templates select="current-group()/self::par" mode="p"/>
                </xsl:when>
                <xsl:when test="current-group()/self::pardef[@id][@list = 'bullet']">
                    <xsl:variable name="this-id" select="current-group()/self::pardef/@id"/>
                    <ul>
                        <xsl:apply-templates select="current-group()/self::par[@def = $this-id]" mode="li"/>
                    </ul>
                </xsl:when>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:template>
    
    <xsl:template match="par" mode="p">
        <p>
            <xsl:apply-templates select="node()"/>
        </p>
    </xsl:template>
    
    <xsl:template match="par" mode="li">
        <li>
            <xsl:apply-templates select="node()"/>
        </li>
    </xsl:template>

    <xsl:template match="table">
        <table border="1">
            <xsl:apply-templates select="tablerow"/>
        </table>
    </xsl:template>

    <xsl:template match="tablerow">
        <tr>
            <xsl:apply-templates select="tablecell"/>
        </tr>
    </xsl:template>
    
    <xsl:template match="tablecell">
        <td>
            <xsl:apply-templates />
        </td>
    </xsl:template>
    
    
    <xsl:template match="run">
        <xsl:value-of select="text()" separator=""/>
    </xsl:template>
    
</xsl:stylesheet>

Open in new window

0
 
mariitaAuthor Commented:
Thanks! :)
0
 
Geert BormansCommented:
welcome,
let me know when you have issues building on the above
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

  • 7
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now