Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old October 29th, 2010, 10:23 AM
Authorized User
 
Join Date: Sep 2004
Posts: 67
Thanks: 1
Thanked 0 Times in 0 Posts
Default Filtering results

Okay, I have a problem I've been trying to solve myself for a while now and it's starting to do my head in... Any help is greatly appreciated.

I have some XML structured like this:

Code:
<Item>
  <Id>5326</Id>  
  <Title>Some title text</Title> 
  <Teaser>Some teaser text</Teaser> 
  <SubGenre>Europe</SubGenre> 
  <Image>9052740.jpg</Image> 
</Item>
Now I have many Items, all of which contain a different SubGenre. What I'm trying to do in XSL is filter based on SubGenre (so that I can pull in just the Item's which contain SubGenre='Europe', for example) and then loop through all of those using xsl:for-each however, so far I just cannot get it to work.

Code:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/> 
<xsl:template match="/">
  <xsl:if test="Item[SubGenre='Europe']">
  <div class="Genre">
    <div class="GenreHdr"><img src="europe.gif" alt="Europe" width="90" height="10"/></div>
    <div class="GenreC1">
      <ul>
      <xsl:for-each select=".[position() &lt; 16]">
        <li>Some text here</li>
      </xsl:for-each>
      </ul>
    </div>
  </div>
  </xsl:if>
</xsl:template>
</xsl:stylesheet>
Any suggestions are greatly appreciated!
-
 
Old October 29th, 2010, 10:37 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Code:
<xsl:template match="/">
  <xsl:for-each select="//Item[SubGenre = 'Europe']">
    ...
  </xsl:for-each>
</xsl:template>
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old October 29th, 2010, 10:44 AM
Authorized User
 
Join Date: Sep 2004
Posts: 67
Thanks: 1
Thanked 0 Times in 0 Posts
Default

Quote:
Originally Posted by Martin Honnen View Post
Code:
<xsl:template match="/">
  <xsl:for-each select="//Item[SubGenre = 'Europe']">
    ...
  </xsl:for-each>
</xsl:template>
Thanks, Martin. Is there a way to first test for 'Europe' before going into a for-each? The reason I want to test for it first is so that if no 'Europe' match is found the div container isn't rendered.

I also want to jump into the for-each after the header div so that the title gif isn't looped over and over.

Is that possible? Cheers!
 
Old October 29th, 2010, 10:48 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Consider to post a sample of the XML input and the corresponding output you want to create, currently I don't understand what your problem is. Of course you can use xsl:if test="//Item[SubGenre = 'Europe']".
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old October 29th, 2010, 11:03 AM
Authorized User
 
Join Date: Sep 2004
Posts: 67
Thanks: 1
Thanked 0 Times in 0 Posts
Default

I don't appear to get any output. I get the following error message:

Code:
General Exception Error: Abbreviated step '.' cannot be followed by a predicate. Use the full form 'self::node()[predicate]' instead. . -->[<-- position() < 16]
So I changed my for-each to...

Code:
<xsl:for-each select="self::node()[position() &lt; 16]">
But all that renders is the div's, but they're empty. Perhaps it's got something to do with not being in the right context node? I'm not sure.

I also tried nested xsl:for-each, rather than xsl:if first followed by xsl:for-each second.
 
Old October 29th, 2010, 11:32 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

>Abbreviated step '.' cannot be followed by a predicate. Use the full form 'self::node()[predicate]' instead. . -->[<-- position() < 16]

You can write .[position() &lt; 16] in XSLT 2.0 but not in XSLT 1.0. But even in 2.0, it doesn't do what you seem to be imagining. "." selects the context item, X[] selects a subset of X, so X[position()<16] selects the first 16 items of X, and if X is a single item like ".", then it selects that item alone. Which is not much use to you.

If you're trying to output the first 15 matches, then do <xsl:for-each select="//Item[SubGenre='XYZ'][position() &lt; 16 ]">...</xsl:for-each>
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
 
Old October 29th, 2010, 11:35 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

As I said, consider to post a sample of the XML input and the corresponding output you want to create, then we can suggest a solution with XSLT.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old October 29th, 2010, 11:42 AM
Authorized User
 
Join Date: Sep 2004
Posts: 67
Thanks: 1
Thanked 0 Times in 0 Posts
Default

Quote:
Originally Posted by mhkay View Post
>Abbreviated step '.' cannot be followed by a predicate. Use the full form 'self::node()[predicate]' instead. . -->[<-- position() < 16]

You can write .[position() &lt; 16] in XSLT 2.0 but not in XSLT 1.0. But even in 2.0, it doesn't do what you seem to be imagining. "." selects the context item, X[] selects a subset of X, so X[position()<16] selects the first 16 items of X, and if X is a single item like ".", then it selects that item alone. Which is not much use to you.

If you're trying to output the first 15 matches, then do <xsl:for-each select="//Item[SubGenre='XYZ'][position() &lt; 16 ]">...</xsl:for-each>
Thanks! That worked.

Can I push my luck and ask whether there is a way to first check for existance of a particular sub-genre before the xsl:for-each block?

Issue I have is that if XYZ doesn't exist for example, the HTML within the for-each block isn't rendered as one would expect, but the title gif image above it still is. I can't put the gif inside the for-each block otherwise it'll loop, but I'd like to be able to check that there is at least one record match before XSL outputs the gif otherwise the result shown to user is a blank container. (Hope that makes sense!)
 
Old October 29th, 2010, 09:09 PM
Authorized User
 
Join Date: Sep 2004
Posts: 67
Thanks: 1
Thanked 0 Times in 0 Posts
Default

Quote:
Originally Posted by Martin Honnen View Post
As I said, consider to post a sample of the XML input and the corresponding output you want to create, then we can suggest a solution with XSLT.
Hi Martin,

Hopefully I can explain this correctly... Here is the XML input...

Code:
<?xml version="1.0" encoding="utf-8" ?> 
<Items>
  <Item>
    <Id>5326</Id>  
    <Title>Some title text</Title> 
    <Teaser>Some teaser text</Teaser> 
    <SubGenre>Europe</SubGenre> 
    <Image>9052740.jpg</Image> 
  </Item>
  <Item>
    <Id>5327</Id>  
    <Title>Some title text</Title> 
    <Teaser>Some teaser text</Teaser> 
    <SubGenre>Asia</SubGenre> 
    <Image>9052741.jpg</Image> 
  </Item>
  <Item>
    <Id>5328</Id>  
    <Title>Some title text</Title> 
    <Teaser>Some teaser text</Teaser> 
    <SubGenre>Americas</SubGenre> 
    <Image>9052742.jpg</Image> 
  </Item>
  <Item>
    <Id>5329</Id>  
    <Title>Some title text</Title> 
    <Teaser>Some teaser text</Teaser> 
    <SubGenre>Europe</SubGenre> 
    <Image>9052743.jpg</Image> 
  </Item>
</Items>
Now what I want to be able to do is query all Item where SubGenre corresponds to 'Europe' and output as follows. I have included red comments (not actually in my XSL document) to help you see what I'm trying to achieve.

Code:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/> 
<xsl:template match="/">
  <!-- Check to see if SubGenre matching Europe exists before rendering div container -->
  <xsl:if test="Items/Item[SubGenre = 'Europe']">
  <div class="Genre">
    <div class="GenreHdr"><img src="europe.gif" alt="Europe" width="42" height="16"/></div>
    <div class="GenreC1">
      <ul>
      <!-- Loop through each SubGenre matching Europe where position less than 4 -->
      <xsl:for-each select="Items/Item[SubGenre = 'Europe'][position() &lt; 4]">
        <li><xsl:value-of select="Title" /> - <xsl:value-of select="Teaser" disable-output-escaping="yes" /></li>
      </xsl:for-each>
      </ul>
    </div>
  </div>
  </xsl:if>
</xsl:template>
</xsl:stylesheet>
The issue I have is that if I don't test for SubGenre containing Europe before getting to the for-each, the output will still render the div containers and just omits the <li>XX</li> part within the for-each if there is no SubGenre containing 'Europe'

Code:
  <div class="Genre">
    <div class="GenreHdr"><img src="europe.gif" alt="Europe" width="42" height="16"/></div>
    <div class="GenreC1">
      <ul>
 
      </ul>
    </div>
  </div>
If there are no SubGenre containing Europe I would not want XSL to output the div's either as this displays a gif header to the user with no associated data to display, but I can't put the div / img tags within the for-each otherwise XSL renders the title gif over and over for each SubGenre matching 'Europe'.

Hope that makes sense?

Last edited by spinout; October 29th, 2010 at 09:19 PM..
 
Old October 30th, 2010, 07:23 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Does the latest XSLT sample you posted not achieve what you want? The xsl:if test="Items/Item[SubGenre = 'Europe']" looks fine for the input sample you posted.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog





Similar Threads
Thread Thread Starter Forum Replies Last Post
How to use OR during filtering..... raaj81 Reporting Services 0 July 30th, 2008 05:34 AM
Help with filtering xml jconroy XSLT 6 April 6th, 2008 11:33 PM
Edit Query Results in Results Grid druid2112 SQL Server 2005 1 June 28th, 2007 08:49 AM
filtering results? chris davies Classic ASP Basics 2 July 4th, 2006 09:41 AM
Filtering FSO results nancy Classic ASP Components 3 October 3rd, 2005 10:15 PM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.