xsl-list
[Top] [All Lists]

Re: Flat XML: Problem getting children

2004-10-07 10:51:24
Jacqui Moore wrote:

I have an xml file that has the following structure:

<thesaurus>
<concept>
<descriptor>House</descriptor>
<NT>Rooms</NT>
<NT>Roofs</NT>
<SN>All About houses</SN>
</concept>
<concept>
<descriptor>Rooms</descriptor>
<BT>House</BT>
<NT>Lounge</NT>
<NT>Kitchen</NT>
<SN>We have rooms in houses</SN>
</concept>
<concept>
<descriptor> Lounge </descriptor>
<BT> Rooms </BT>
<SN>Lounges are nice places</SN>
</concept>
<concept>
<descriptor> Roofs </descriptor>
<BT>House</BT>
<NT>Kitchen</NT>
<SN>Roofs go on houses</SN>
</concept>
<concept>
<descriptor> Utensils </descriptor>
<BT>Kitchen</BT>
<SN>Utensils belong in the draw</SN>
</concept>
</thesaurus>
Hi Jacqui,

This might be simpler than it seems at first glance! It looks like a pretty flat XML file but with some indentation, it becomes clear that the information is already nicely grouped in <concept> elements. Which is good for you, because it means you don't need to
do any grouping yourself. You want to use the <NT> elements to look up other
<concept> elements, so you could start with a key on these elements by their descriptor:

<xsl:key name="concepts" match="concept" use="descriptor"/>

But some descriptor strings have trailing spaces, and <NT>Lounge</NT> will not match <descriptor> Lounge </descriptor>. That can be solved with normalize-space:

<xsl:key name="concepts" match="concept" use="normalize-space(descriptor)"/>

NT - the children categories
BT - the parent category
One of these is redundant, you can ignore the <BT> elements if you work from top to bottom: start with the first <concept> and recursively add nodes by their <NT> children.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
   <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:key name="concepts" match="concept" use="normalize-space(descriptor)"/>
   <xsl:template match="/thesaurus">
       <result>
           <xsl:apply-templates select="concept[1]"/>
       </result>
   </xsl:template>
   <xsl:template match="concept">
       <concept name="{normalize-space(descriptor)}">
           <xsl:apply-templates select="NT"/>
       </concept>
   </xsl:template>
   <xsl:template match="NT">
       <xsl:apply-templates select="key('concepts', normalize-space(.))"/>
   </xsl:template>
</xsl:stylesheet>

You forgot the kitchen in the sample input, but after adding one, this is the output:

<result>
  <concept name="House">
     <concept name="Rooms">
        <concept name="Lounge"/>
        <concept name="Kitchen">
           <concept name="Utensils"/>
        </concept>
     </concept>
     <concept name="Roofs">
        <concept name="Kitchen">
           <concept name="Utensils"/>
        </concept>
     </concept>
  </concept>
</result>

Cheers,
Anton

The objective is to create a expandable client side tree structure, and the
user will click on a category and the category information (SN) will be
displayed in the right frame.

- HOUSE
  - Rooms
      o Lounge
      o Kitchen
           § Utensils
  - Roofs
      o Kitchen
          § Utensils

I can get the top level categories:
<xsl:for-each select="thesaurus/concept[boolean(BT)=false]">

My problem is I do not know how to get the children and their children etc.
(loop until the concept has no NT element) . There is no limit to the number
of children levels and a child can appear in more than one parent. I think I
need to use a key but am not having ANY success.

Thanks in advance!!

Jacqui


<Prev in Thread] Current Thread [Next in Thread>