Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old January 28th, 2004, 11:45 AM
Authorized User
 
Join Date: Nov 2003
Posts: 16
Thanks: 0
Thanked 0 Times in 0 Posts
Default OpenOffice List Dilemma

I am all the way back to the drawing board on this one and figured it was time to ask for some professional help. This issue deals with transforming the way OpenOffice stores unordered/ordered lists in XML to my company's way of storing lists in XML. The problem is really only seen when in OpenOffice you change the list type of nested lists

This is an example of a mixed-type list:
1. The first numbered item in the list
   * Unordered (bulleted) nested list item
   * Another unordered nested list item
      1. Just to make things interesting
2. The second numbered item in the list
   a) Alphabetic nested list item
      * Unordered nested list item
   b) Alphabetic nested list item
   c) Just for fun
3. The third numbered item in the list
   a) This is an alphabetic nested list item

This seems easy enough to imagine how it would be stored in XML, however, OpenOffice does something that I can't figure out, and consider strange. OpenOffice will break up the above list into separate lists based on style. Nesting is achieved by creating empty list items. Below is the actual XML that is produced by the example list: (Notice that a new root list is created for each nested list item)

<text:ordered-list text:style-name="Dog_OrderedList">
   <text:list-item>
      <text:p text:style-name="P3">The first numbered item in the list</text:p>
   </text:list-item>
</text:ordered-list>
<text:unordered-list text:style-name="Dog_UnorderedList">
   <text:list-item>
      <text:unordered-list>
         <text:list-item>
            <text:p text:style-name="P4">Unordered (bulleted) nested list item</text:p>
         </text:list-item>
         <text:list-item>
            <text:p text:style-name="P4">Another unordered nested list item</text:p>
         </text:list-item>
      </text:unordered-list>
   </text:list-item>
</text:unordered-list>
<text:ordered-list text:style-name="Dog_OrderedList">
   <text:list-item>
      <text:ordered-list>
         <text:list-item>
            <text:ordered-list>
               <text:list-item>
                  <text:p text:style-name="P3">Just to make things interesting</text:p>
               </text:list-item>
            </text:ordered-list>
         </text:list-item>
      </text:ordered-list>
   </text:list-item>
   <text:list-item>
      <text:p text:style-name="P3">The second numbered item in the list</text:p>
   </text:list-item>
</text:ordered-list>
<text:ordered-list text:style-name="Dog_OrderedListLowerAlpha">
   <text:list-item>
      <text:ordered-list>
         <text:list-item>
            <text:p text:style-name="P5">Alphabetic nested list item</text:p>
         </text:list-item>
      </text:ordered-list>
   </text:list-item>
</text:ordered-list>
<text:unordered-list text:style-name="Dog_UnorderedList">
   <text:list-item>
      <text:unordered-list>
         <text:list-item>
            <text:unordered-list>
               <text:list-item>
                  <text:p text:style-name="P4">Unordered nested list item</text:p>
               </text:list-item>
            </text:unordered-list>
         </text:list-item>
      </text:unordered-list>
   </text:list-item>
</text:unordered-list>
<text:ordered-list text:style-name="Dog_OrderedListLowerAlpha">
   <text:list-item>
      <text:ordered-list>
         <text:list-item>
            <text:p text:style-name="P5">Alphabetic nested list item</text:p>
         </text:list-item>
         <text:list-item>
            <text:p text:style-name="P5">Just for fun</text:p>
         </text:list-item>
      </text:ordered-list>
   </text:list-item>
</text:ordered-list>
<text:ordered-list text:style-name="Dog_OrderedList">
   <text:list-item>
      <text:p text:style-name="P3">The third numbered item in the list</text:p>
   </text:list-item>
</text:ordered-list>
<text:ordered-list text:style-name="Dog_OrderedListLowerAlpha">
   <text:list-item>
      <text:ordered-list>
         <text:list-item>
            <text:p text:style-name="P5">This is an alphabetic nested list item</text:p>
         </text:list-item>
      </text:ordered-list>
   </text:list-item>
</text:ordered-list>

Now here is where I am having trouble with the transformation. My company's XML schema defines lists (at least I think) in a more logic way. Below is what I need to transform the OpenOffice XML into:

<Dog_List>
   <Dog_OrderedList>
      <Dog_ListItem>
         The first numbered item in the list
         <Dog_UnorderedList>
            <Dog_ListItem>Unordered (bulleted) nested list item</Dog_ListItem>
            <Dog_ListItem>
               Another unordered nested list item
               <Dog_OrderedList>
                  <Dog_ListItem>Just to make things interesting</Dog_ListItem>
               </Dog_OrderedList
            </Dog_ListItem>
         </Dog_UnorderedList>
      </Dog_ListItem>
      <Dog_ListItem>
         The second numbered item in the list
         <Dog_OrderedList type="loweralpha">
            <Dog_ListItem>
               Alphabetic nested list item
               <Dog_UnorderedList>
                  <Dog_ListItem>Unordered nested list item</Dog_ListItem>
               </Dog_UnorderedList>
            </Dog_ListItem>
            <Dog_ListItem>Alphabetic nested list item</Dog_ListItem>
            <Dog_ListItem>Just for fun</Dog_ListItem>
         </Dog_OrderedList>
      </Dog_ListItem>
      <Dog_ListItem>
         The third numbered item in the list
         <Dog_OrderedList type="loweralpha">
            <Dog_ListItem>This is an alphabetic nested list item</Dog_ListItem>
         </Dog_OrderedList>
      </Dog_ListItem>
   </Dog_OrderedList>
</Dog_List>



I have come very close, but have failed to make a perfect transformation. Does anyone have any idea or method that they could recommend? I really appreciate any help or advice that could be offered!!

Aaron

 
Old January 29th, 2004, 11:42 AM
Authorized User
 
Join Date: Nov 2003
Posts: 16
Thanks: 0
Thanked 0 Times in 0 Posts
Default

I found the solution. Not sure if this is the most elegant, or if anyone cares, but here are the templates I used to accomplish this transformation:
Code:
<xsl:template match="node()[contains(name(), 'ordered-list') and not(contains(name(preceding-sibling::node()[1]), 'ordered-list'))]">

   <xsl:variable name="level" select="count(ancestor::node()[contains(name(), 'ordered-list')])+1"/>

   <xsl:choose>
      <xsl:when test="not(parent::text:list-item[1])">
         <Dog_List>
            <xsl:choose>
               <xsl:when test="name() = 'text:unordered-list'">
                  <Dog_UnorderedList><xsl:apply-templates/></Dog_UnorderedList>
               </xsl:when>
               <xsl:when test="name() = 'text:ordered-list' and (@text:style-name = 'Dog_SimpleList' or @text:style-name = //text:list-style[text:list-level-style-number[@text:level = $level and @style:num-format = '']]/@style:name)">
                  <Dog_SimpleList><xsl:apply-templates/></Dog_SimpleList>
               </xsl:when>
               <xsl:otherwise>
                  <Dog_OrderedList>
                     <xsl:if test="contains(@text:style-name, 'LowerAlpha') or @text:style-name = //text:list-style[text:list-level-style-number[@text:level = $level and @style:num-format = 'a']]/@style:name">
                        <Dog_OrderedListType>alpha</Dog_OrderedListType>
                     </xsl:if>
                     <xsl:if test="contains(@text:style-name, 'UpperAlpha') or @text:style-name = //text:list-style[text:list-level-style-number[@text:level = $level and @style:num-format = 'A']]/@style:name">
                        <Dog_OrderedListType>ucase</Dog_OrderedListType>
                     </xsl:if>
                     <xsl:apply-templates/>
                  </Dog_OrderedList>
               </xsl:otherwise>
            </xsl:choose>
         </Dog_List>
      </xsl:when>
      <xsl:otherwise>
         <xsl:choose>
            <xsl:when test="name() = 'text:unordered-list'">
               <Dog_UnorderedList><xsl:apply-templates/></Dog_UnorderedList>
            </xsl:when>
            <xsl:when test="name() = 'text:ordered-list' and (@text:style-name = 'Dog_SimpleList' or @text:style-name = //text:list-style[text:list-level-style-number[@text:level = $level and @style:num-format = '']]/@style:name)">
               <Dog_SimpleList><xsl:apply-templates/></Dog_SimpleList>
            </xsl:when>
            <xsl:otherwise>
               <Dog_OrderedList>
                  <xsl:if test="contains(@text:style-name, 'LowerAlpha') or @text:style-name = //text:list-style[text:list-level-style-number[@text:level = $level and @style:num-format = 'a']]/@style:name">
                     <Dog_OrderedListType>alpha</Dog_OrderedListType>
                  </xsl:if>
                  <xsl:if test="contains(@text:style-name, 'UpperAlpha') or @text:style-name = //text:list-style[text:list-level-style-number[@text:level = $level and @style:num-format = 'A']]/@style:name">
                     <Dog_OrderedListType>ucase</Dog_OrderedListType>
                  </xsl:if>
                  <xsl:apply-templates/>
               </Dog_OrderedList>
            </xsl:otherwise>
         </xsl:choose>
      </xsl:otherwise>
   </xsl:choose>
</xsl:template>

<xsl:template match="text:list-item[not(ancestor::text:list-item[not(node())])]">
   <xsl:choose>
      <xsl:when test="text:p">

         <xsl:variable name="ancestorList" select="ancestor::node()[contains(name(), 'ordered-list') and not(ancestor::text:ordered-list or ancestor::text:unordered-list)]"/>


         <xsl:variable name="level" select="count(ancestor::text:ordered-list | ancestor::text:unordered-list)"/>

         <xsl:choose>

            <xsl:when test="not(following-sibling::text:list-item) and (text:p or text:a)">
               <Dog_ListItem>
                  <xsl:apply-templates/>
                  <!-- If there is another list following my ancestor and it has an empty list item at
                     the same level as me, it means that this list was created to house a child of mine -->
                  <xsl:apply-templates select="$ancestorList/following-sibling::node()[contains(name(), 'ordered-list')][1]/descendant::text:list-item[count(ancestor::node()[contains(name(), 'ordered-list')]) = $level and not(text:p)]/node()"/>
               </Dog_ListItem>

               <!-- Ok, if I am a sibling of someone above me, I will go ahead and
                     let him parse the rest of siblings below me, otherwise I will parse
                     them -->
               <xsl:if test="not($ancestorList/preceding-sibling::node()[contains(name(), 'ordered-list') and generate-id(following-sibling::node()[not(contains(name(), 'ordered-list'))]) = generate-id($ancestorList/following-sibling::node()[not(contains(name(), 'ordered-list'))])]/descendant::text:list-item[count(ancestor::text:ordered-list | ancestor::text:unordered-list) = $level and text:p and not(ancestor::text:list-item[text:p])])">

                  <xsl:for-each select="$ancestorList/following-sibling::node()[contains(name(), 'ordered-list') and generate-id(following-sibling::node()[not(contains(name(), 'ordered-list'))]) = generate-id($ancestorList/following-sibling::node()[not(contains(name(), 'ordered-list'))])]/descendant::text:list-item[count(ancestor::text:ordered-list | ancestor::text:unordered-list) = $level and text:p and not(ancestor::text:list-item[text:p])]">
                     <xsl:variable name="currentAncestor" select="ancestor::node()[contains(name(), 'ordered-list') and not(ancestor::text:ordered-list or ancestor::text:unordered-list)]"/>

                     <xsl:if test="not($currentAncestor/preceding-sibling::node()[preceding-sibling::node()[generate-id() = generate-id($ancestorList)]]/descendant::text:list-item[count(ancestor::text:ordered-list | ancestor::text:unordered-list) &lt; $level and text:p])">
                        <xsl:apply-templates select="."/>
                     </xsl:if>
                  </xsl:for-each>
               </xsl:if>
            </xsl:when>
            <xsl:otherwise>
               <Dog_ListItem><xsl:apply-templates/></Dog_ListItem>
            </xsl:otherwise>
         </xsl:choose>
      </xsl:when>
      <xsl:otherwise/>
   </xsl:choose>
</xsl:template>






Similar Threads
Thread Thread Starter Forum Replies Last Post
[ASK] Combine PHP with OpenOffice.org swl Pro PHP 0 June 19th, 2007 03:02 AM
Runat server dilemma ? rsearing ASP.NET 2.0 Basics 1 November 24th, 2006 04:10 AM
bookmark a PDF file with Acrobat Reader/OpenOffice crmpicco Need help with your homework? 0 February 27th, 2006 01:13 PM
'exists' dilemma defiant SQL Server 2000 4 June 27th, 2003 07:26 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.