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

Re: Newbie needs help with sorting a filtered list

Subject: Re: Newbie needs help with sorting a filtered list
From: "James A. Robinson" <jim.robinson@xxxxxxxxxxxx>
Date: Sun, 28 Jan 2007 21:41:37 -0800
Re:  Newbie needs help with sorting a filtered list
> I'm hitting a wall over something that's probably stupid and 
> obvious.  Please be patient with me!

It's not stupid to ask questions if you don't understand something.

> This gives me the correct items, but not in alphabetical order:
> 
> <xsl:param name="param1"/>
> <xsl:param name="param2"/>
> 
> <xsl:template match="catalog/entry">
>    <xsl:if test="category[@type=$param1] and category[@subcat=$param2]">
>      <xsl:for-each select="word">
>        <xsl:sort/>
>        <xsl:apply-templates/><br/>
>      </xsl:for-each>
>    </xsl:if>
> </xsl:template>

I think the problem you're having is regarding the way the xml document
is being handled like a tree, and how the context available to you at
each point in the tree changes as the processor executes your program.

So you've got a template which matches every catalog/entry, when the
template is activated it then tests to see if it has a sub element named
category with the appropriate type and subcat attributes, and you tell
it to select "every" word element. But you only have one word element
per catalog/entry.

So you are asking the XSLT engine to sort a list containing one item.
First the template encounters

  <catalog>
    <entry>
      <word>orange</word>

then it encounters

  <catalog>
    <entry>
      <word>spinach</spinach>

And so forth.  While your logic properly identifies that, due to the
categories, you want'orange' and not 'spinach', each time you encounter
a word you don't have any context to select and sort the other words.
>From the point of view of the program it sees

  select 'orange'
  sort it (since it is only 1 item it just returns itself)
  apply-templates

  select 'apple'
  sort it (since it is only 1 item it just returns itself)
  apply-templlates
 
  select 'banana'
  sort it (since it is only 1 item it just returns itself)
  apply-templates

> This one gives me an alphabetized list, but of all the items, not 
> just the ones that match the params:
> 
> <xsl:template match="catalog">
>    <xsl:if test="entry/category[@type=$param1] and 
> entry/category[@subcat=$param2]">
>      <xsl:for-each select="entry/word">
>        <xsl:sort/>
>        <xsl:apply-templates/><br/>
>      </xsl:for-each>
>    </xsl:if>
> </xsl:template>

Here you are matching an item at a higher level, at the catalog level. So
now you have access to all the word elements.  But your test isn't
looping through each entry to check for its category:

 <xsl:template match="catalog">
  <xsl:if test="entry/category[@type=$param1]
                and  entry/category[@subcat=$param2]">

is simply checking to see if *an* entry/category with the parameters
you specify exist.  Since it does, the logic inside is executed, and then

  <xsl:for-each select="entry/word">

select *every* word.  In other words

  if an entry/catalog matching @type=$param1 and @subcat=$param2
  exists in my list
  then
    select all entry/word items in my list.
    sort the list of all word elements.
    apply-templates to the list of all word elements.
 
> What am I doing wrong, and why do these two versions, which to my 
> rank amateur brain look like they should be the same, return such 
> different results?

Because you are specifying a template which matches at a different
point in the tree, your logic will need to be changed to identify
what it is you want to process.

You haven't shown how you are calling the templates, whether you
are letting the processor walk through the entire document or
whether you are driving it somehow.  Here's one way you could
structure the program, assuming you can tell program to match
on catalog:

  <xsl:template match="catalog">
    <xsl:apply-templates select="entry[category[@type=$param1 and @subcat=$param2]]">
      <xsl:sort select="word"/>
    </xsl:apply-templates>
  </xsl:template>
  
  <xsl:template match="entry">
    <xsl:apply-templates select="word"/><br/>
  </xsl:template>

This assumes that 'catalog' will be matched and that it will be the
only template which in turns selects catalog/entry items. It says
"starting at catalog, I want to process all entry elements which have
a child category element which in turn has type and subcat attributes
equal to..."  That gives you access to all the 'entry' elements which
match your type and subcat.  you can then sort on the word.

A match on 'entry', simply serves to apply templates to the word and
emits the <br/> tag.

There are other ways you could structure this, but the important thing
to remember is that you need sort things from a context which has all
of the words you want available to it.


Jim

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
James A. Robinson                       jim.robinson@xxxxxxxxxxxx
Stanford University HighWire Press      http://highwire.stanford.edu/
+1 650 7237294 (Work)                   +1 650 7259335 (Fax)

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.