[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

RE: Building a hierarchy based on siblings

Subject: RE: Building a hierarchy based on siblings
From: "M. David Peterson" <m.david@xxxxxxxxxx>
Date: Thu, 10 Jun 2004 22:33:41 -0600
sibling hierarchy
Hey Ryan,

Kind of an interesting situation that has several possible solutions.
But from your comments it seems that getting a good grasp of how to
properly use recursion to build nested output is something you are in
seek of.  So I gave you an example that uses as much recursion as
possible to help you in your quest :)

I was going to try and comment it a bit but I actually just realized the
time and I need to head out for a bit so I can attend a buddy of mines
bachelor party.  But I don?t plan on drinking too much so when I return
Ill look to see if you had any questions.  Otherwise, enjoy!  I hope you
find this helpful in better understanding how you can use recursion in
multiple ways in XSLT.

Best of luck!

<M:D/>

Heres the XSLT:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
  <xsl:element name="sect1">
    <xsl:apply-templates select="sect1/para[not(starts-with(.,'* '))]"
mode="normal"/>
  </xsl:element>
</xsl:template>
<xsl:template match="para" mode="normal"><!-- no pun intended.  I like
X-Files but not so much I name my attribute values to match the shows
focus ;) -->
<xsl:variable name="followingParagraph"
select="following-sibling::para[not(starts-with(., '*'))][1]"/>
  <xsl:copy-of select="."/>
  <xsl:if test="following-sibling::para[1][starts-with(., '* ')]">
    <xsl:element name="itemizedlist">
      <xsl:apply-templates
select="following-sibling::para[starts-with(.,'* ') and
not(preceding-sibling::para = $followingParagraph)]" mode="buildList"/>
    </xsl:element>
  </xsl:if>
</xsl:template>
<xsl:template match="para" mode="buildList">
  <xsl:element name="listitem">
    <xsl:element name="para">
      <xsl:apply-templates select="text() | *"/>
    </xsl:element>
  </xsl:element>
</xsl:template>
<xsl:template match="text()[starts-with(., '* ')]">
  <xsl:value-of select="substring-after(., '* ')"/>
</xsl:template>
<xsl:template match="text() | *">
  <xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>

Heres the transformed result of the XML you gave as an example:

<?xml version="1.0" encoding="UTF-8"?>
<sect1>
  <para>First Paragraph</para>
  <itemizedlist>
    <listitem>
      <para>First list item</para>
    </listitem>
    <listitem>
      <para>Second list item</para>
    </listitem>
    <listitem>
      <para>Third list item <emphasis>emphasized text</emphasis>
      </para>
    </listitem>
  </itemizedlist>
  <para>Second Paragraph</para>
  <para>Third paragraph</para>
  <itemizedlist>
    <listitem>
      <para>First list item #2</para>
    </listitem>
    <listitem>
      <para>Second list item #2</para>
    </listitem>
  </itemizedlist>
  <para>Another paragraph</para>
</sect1>

Enjoy!  I'm off to get a little loopy 8$ but will return before to long
so don?t hesitate to ask questions...  Worst case Ill get back to you in
the morning.

-----Original Message-----
From: Ryan Graham [mailto:Ryan.Graham@xxxxxxxxxxxxx] 
Sent: Thursday, June 10, 2004 7:35 PM
To: 'xsl-list@xxxxxxxxxxxxxxxxxxxxxx'
Subject:  Building a hierarchy based on siblings

Hi all,

I am having some trouble getting the correct template matches written to
build a hierarchy.

I have similar to the following input XML:

<sect1>
	<para>First Paragraph</para>
	<para>* First list item</para>
	<para>* Second list item</para>
	<para>* Third list item <emphasis>emphasized
text</emphasis></para>
	<para>Second Paragraph</para>
	<para>Third paragraph</para>
	<!-- Start new list-->
	<para>* First list item #2</para>
	<para>* Second list item #2</para>
	<para>Another paragraph</para>
</sect1>

I would like to put all para nodes that begin with "* " into a list
structure and cut off the first two characters when processed, to get
the
following output:

<para>First Paragraph</para>
<itemizedlist>
	<listitem>
		<para>First list item</para>
	</listitem>
	<listitem>	
		<para>Second list item</para>
	</listitem>
	<listitem>
		<para>Third list item <emphasis>emphasized
text</emphasis></para>
	<listitem>
</itemizedlist>
<para>Second Paragraph</para>
<para>Third paragraph</para>
<itemizedlist>
	<listitem>
		<para>First list item #2</para>
	</listitem>
	<listitem>	
		<para>Second list item #2</para>
	</listitem>
</itemizedlist>
<para>Another paragraph</para>

I was using this to get the <listitems> built:

<xsl:template match="para">
  <xsl:choose>
    <xsl:when test="substring(node()[1], 0, 3) = '* '>
      <itemizedlist>
	  <listitem>
	  <xsl:value-of select="substring(node()[1], 3)"/>
	  <xsl:apply-templates select="node()[position() > 1]"/>
	  </listitem>
	</itemizedlist>
    </xsl:when>
    <xsl:otherwise>
      <para>
	  <xsl:apply-templates/>
	</para>
    </xsl:otherwise>
</xsl:template>

But with this match, every <para> that starts with "* " becomes its own
itemizedlist with one listitem.  Is there an efficient way to do this
using
a recursive template, without creating duplicate output?

I appreciate any and all suggestions!

Thanks,
Ryan

--+------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe@xxxxxxxxxxxxxxxxxxxxxx>
--+--


Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.