[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: Ryan Graham <Ryan.Graham@xxxxxxxxxxxxx>
Date: Fri, 11 Jun 2004 12:59:04 -0700
starts with xsl
Thank you so much for the guidance -- you filled the knowledge gap on this
one!  I created a modified version based on what you posted below.  It
integrates seamlessly into my existing stylesheet and provides the correct
output :)

<xsl:template match="para[not(starts-with(., '* '))]">
	<para>
		<xsl:apply-templates/>
	</para>
</xsl:template>
	
<xsl:template match="para[starts-with(., '* ') and
not(preceding-sibling::para[1][starts-with(.,'* ')])]">
	<xsl:variable name="followingParagraph"
select="following-sibling::para[not(starts-with(., '* '))][1]"/>
	<itemizedlist mark="bullet">
		<xsl:apply-templates select=". |
following-sibling::para[starts-with(.,'* ') and not(preceding-sibling::para
= $followingParagraph)]" mode="list"/>
	</itemizedlist>
</xsl:template>
	
<xsl:template match="para[starts-with(.,'* ') and
preceding-sibling::para[1][starts-with(.,'* ')]] "/>
	
<xsl:template match="para" mode="list">
	<listitem>
		<xsl:apply-templates select="text() | *"/>
	</listitem>
</xsl:template>
	
<xsl:template match="text()[starts-with(., '* ')]">
	<xsl:value-of select="substring-after(., '* ')"/>
</xsl:template>

Thanks again!
-Ryan

-----Original Message-----
From: M. David Peterson [mailto:m.david@xxxxxxxxxx] 
Sent: Thursday, June 10, 2004 9:34 PM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: RE:  Building a hierarchy based on siblings


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>
--+--


--+------------------------------------------------------------------
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.