How do I split info into sections via XSLT?
February 23, 2007 3:29 PM   Subscribe

I need to take an XML list and split it into sections/subsections by keying off a child element. Samples and

I need to change my source XML into an XML output that will: (1) split out sections per children elements; (2) split out child sections per titles (e.g., alphabetically); and (3) title the child sections per alphabet (e.g, A, B, C...). Actually, it'll be easier to explain with these examples:

Example Source XML:


AAA
AAA definition
< !--where cat1, cat2, etc. specify which termdef go in which output section. some termdefs will be in multiple sections -->



ABB
ABB definition




BBB
BBB definition




BCC
BCC definition




Example Output XML:



Cat1 Defs

A Defs

AAA
AAA definition


ABB
ABB definition





Cat2 Defs

A Defs

ABB
ABB definition



B Defs

BBB
BBB definition





Cat3 Defs

A Defs

AAA
AAA definition



B Defs

BBB
BBB definition


BCC
BCC definition





Any ideas? I've been looking at this too long...
posted by sfkiddo to Computers & Internet (5 answers total)
 
I'm not sure I understand the question, but if you know PERL, you might be able to do this with the XML::Simple module, or just parse it by hand using regex.
posted by nakedsushi at 4:01 PM on February 23, 2007


Arg: no wonder you didn't understand the question, my characters didn't escape for the code. Trying again. BTW, I'm using XSLT.

I need to change my source XML into an XML output that will: (1) split out sections per children elements; (2) split out child sections per titles (e.g., alphabetically); and (3) title the child sections per alphabet (e.g, A, B, C...). Actually, it'll be easier to explain with these examples:

Example Source XML:
<document>
<termdef>
<term>AAA</term>
<def>AAA definition</def>
<cat1/> <!--Where cat1, cat2, etc. specify which termdef go in which output section. Some termdefs will be in multiple sections -->
<cat3/>
</termdef>
<termdef>
<term>ABB</term>
<def>ABB definition</def>
<cat1/>
<cat2/>
</termdef>
<termdef>
<term>BBB</term>
<def>BBB definition</def>
<cat2/>
<cat3/>
</termdef>
<termdef>
<term>BCC</term>
<def>BCC definition</def>
<cat3/>
</termdef>
</document>

Example Output XML:

<document>
<section>
<title>Cat1 Defs</title>
<subsection>
<title>A Defs</title>
<termdef>
<term>AAA</term>
<def>AAA definition</def>
</termdef>
<termdef>
<term>ABB</term>
<def>ABB definition</def>
</termdef>
</subsection>
</section>

<section>
<title>Cat2 Defs</title>
<subsection>
<title>A Defs</title>
<termdef>
<term>ABB</term>
<def>ABB definition</def>
</termdef>
</subsection>
<subsection>
<title>B Defs</title>
<termdef>
<term>BBB</term>
<def>BBB definition</def>
</termdef>
</subsection>
<section>

<section>
<title>Cat3 Defs</title>
<subsection>
<title>A Defs</title>
<termdef>
<term>AAA</term>
<def>AAA definition</def>
</termdef>
</subsection>
<subsection>
<title>B Defs</title>
<termdef>
<term>BBB</term>
<def>BBB definition</def>
</termdef>
<termdef>
<term>BCC</term>
<def>BCC definition</def>
</termdef>
</subsection>
</section>
</document> ]]>
posted by sfkiddo at 4:06 PM on February 23, 2007


You can do this with Muenchian Grouping.
posted by philscience at 7:25 PM on February 23, 2007


This should work:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml" indent="yes"/>

  <xsl:key name="categories" match="/document/termdef/*[name() != 'term' and name() != 'def']" use="name()"/>
  <xsl:key name="definitions-by-initial" match="/document/termdef" use="substring(term, 1, 1)"/>

  <xsl:template match="/">
    <document>
      <xsl:for-each select="document/termdef/*[name() != 'term' and name() != 'def'][generate-id() = generate-id(key('categories', name())[1])]">
        <xsl:sort select="name()" data-type="text" order="ascending"/>
        <section>
          <title><xsl:value-of select="concat(name(), ' Defs')"/></title>
          <xsl:variable name="category" select="self::*"/>
          <xsl:for-each select="/document/termdef[child::*[name() = name($category)]][generate-id() = generate-id(key('definitions-by-initial', substring(term, 1, 1))[child::*[name() = name($category)]][1])]">
            <xsl:sort select="term" data-type="text" order="ascending"/>
            <subsection>
              <title><xsl:value-of select="concat(substring(term, 1, 1), ' Defs')"/></title>
              <xsl:apply-templates select="key('definitions-by-initial', substring(term, 1, 1))[child::*[name() = name($category)]]"/>
            </subsection>
          </xsl:for-each>
        </section>
      </xsl:for-each>
    </document>
  </xsl:template>

  <xsl:template match="termdef">
    <xsl:copy>
      <xsl:copy-of select="term|def"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
posted by kyten at 9:48 PM on February 23, 2007


Thanks, kyten! I'll give that a try today.
posted by sfkiddo at 11:24 AM on February 24, 2007


« Older Wasn't "pointer finger" good enough?   |   Are there Baby Ruths on Dagobah? Newer »
This thread is closed to new comments.