Re: [xsl] Separate same level elements on a criteria

Subject: Re: [xsl] Separate same level elements on a criteria
From: Abel Braaksma <abel.online@xxxxxxxxx>
Date: Fri, 19 Jan 2007 23:29:28 +0100
Hi Spencer,

You did not specify your version of XSLT. However, since you mention group by (which is something in SQL, but not an instruction in XSLT, but for-each-group is quite similar) I assumed XSLT 2. Here's how to do your document in XSLT 2. Note that I removed the xsl:for-each instruction, I think you do better with template matching. Also, I inversed the logic: removing all heads matching 'TOC' (throw-away template). Since you started out with modes, I used modes too to keep it simple.

The output is: first list items, then the content nodes, this is the output on your input:

<ul>
  <li>Title</li>
  <li>Heading 1</li>
  <li>Heading 2</li>
</ul>
<h1>Head of document: Title</h1>
<p>text/para: (title) This is a paragraph</p>
<p>text/para:  (titlebodl)This is a paragraph</p>
<p>a section: (title, toc)1. Title</p>
<p>a section: (title, toc)2. Title</p>
<h2>head: Heading 1</h2>
<p>text/para: (head1)This is a paragraph</p>
<p>text/para: (head1)This is a paragraph</p>
<h2>head: Heading 2</h2>
<p>text/para: (head2)This is a paragraph</p>
<p>text/para: (head2)This is a chart</p>


And here is the XSLT 2 stylesheet:


<xsl:output indent="yes" />
<xsl:template match="root">
<ul>
<xsl:apply-templates select="*" mode="toc"/>
</ul>
<xsl:for-each-group select="*"
group-starting-with="head[not(contains(., 'TOC'))] | head_document">
<xsl:apply-templates select="current-group()" />
</xsl:for-each-group>
</xsl:template>
<xsl:template match="head[contains(., 'TOC')]" mode="#all"/>
<xsl:template match="*" mode="toc" />
<xsl:template match="head_document | head" mode="toc">
<li><xsl:value-of select="." /></li>
</xsl:template>
<xsl:template match="head_document">
<h1>Head of document: <xsl:value-of select="." /></h1>
</xsl:template>
<xsl:template match="head">
<h2>head: <xsl:value-of select="." /></h2>
</xsl:template>
<xsl:template match="section">
<p>a section: <xsl:value-of select="." /></p>
</xsl:template>
<xsl:template match="*">
<p>text/para: <xsl:value-of select="." /></p>
</xsl:template>
</xsl:stylesheet>




Cheers,
-- Abel Braaksma
  http://www.nuntia.nl


Spencer Tickner wrote:
Hi Group,

I'm wondering if anyone has a slick way of solving this problem. I
have an xml document like:

<root>
    <head_document>Title</head_document>
    <para>This is a paragraph</para>
    <bold_para>This is a paragraph</bold_para>
    <head>TOC</head>
    <section>1. Title</section>
    <section>2. Title</section>
    <head>Heading 1</head>
    <paragraph_indent>This is a paragraph</paragraph_indent>
    <paragraph_outdent>This is a paragraph</paragraph_outdent>
    <head>Heading 2</head>
    <paragraph>This is a paragraph</paragraph>
    <chart>This is a chart</chart>
</root>

Basically I'm making a bunch of html documents from this xml document
and a table of contents. Table of contents is easy (I need to grab the
<head_document> element and skip the <head>TOC</head> element):

<xsl:template match="root" mode="toc">
<ul>
<xsl:for-each select="head_document|head[not(contains(., 'TOC'))]">
<li>Do Something</li>
</xsl:for-each>
</ul>
</xsl:template>


Ok, so that all works great, I now have to do something similar to above but apply-templates to all the elements that belong with the heads I want. ie: <head_document> down to <head>, skip <head>TOC</head>, next <head> element down to the next <head> element, repeat.

Any ideas on how to do this would be very helpful. I thought group-by
would probably be the answer but so far my research hasn't turned up
anything.

Thanks,

Spencer

Current Thread