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 May 2nd, 2007, 02:18 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

I think you can solve this by changing songs.xml to use an actual relative URI to reference the individual song files (that is, "a.xml" rather than "a"). If you do that, then you can write

<xsl:variable name="songs" select="document(/songs/song)"/>

<xsl:for-each select="$songs">
  <xsl:sort select="@title"/>
   etc

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
 
Old May 2nd, 2007, 08:27 AM
Authorized User
 
Join Date: Apr 2007
Posts: 38
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Ah, interesting...

Right now I am doing something like this:
Code:
<xsl:template name="getSongsRTF">
  <xsl:param name="album" select="." />
  <songs>
    <xsl:for-each select="$album//songs/song">
      <xsl:variable name="songFile" select="concat(title,'.xml') />
      <xsl:variable name="song"     select="document($songFile)/song" />
      <xsl:copy-of select="$song" />
    </xsl:for-each>
  </songs>
</xsl:template>

<xsl:variable name="songsRTF"><xsl:call-template name="getSongsRTF" /></xsl:variable>
<xsl:variable name="songs" select="msxsl:node-set($songsRTF)/songs" />
In the above example, I use "concat()" to show that I'm constructing the song's filename on the fly. However, in my real XSLT I use a named template which converts a human-readable song title (e.g, "Happy Birthday") into a filename ("happy-birthday.xml"). My songs' XML filenames actually depend on album title, song title, white space elimination, lowercasing, etc.

The bottom line is that $songFile is dynamically constructed by XSLT rather than being read directly from the album's XML file. Does this prevent me from using document() in a single variable assignment, as in the previous post? Or is there a way to dynamically construct XML filenames and then assign a bunch of XML files' contents to a single variable?
 
Old May 2nd, 2007, 01:08 PM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

In my solution I exploited the fact that document() can process a number of input URLs to create a set of document nodes. But those input URLs have to be the string-values of the nodes in a node-set, and you can't construct such a node-set without the node-set function.

If you can't change the source XML in the way I suggested then the only other solution is to recurse over the songs rather than iterating over them using xsl:for-each, and that means you have to do the sorting "by hand", so the solution becomes very complex. More complex than I would want to tackle unless someone is paying me handsomely...

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
 
Old May 2nd, 2007, 01:29 PM
Authorized User
 
Join Date: Apr 2007
Posts: 38
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Ah, so are these my options:

Saxon: (static xhtml generation)
a) refer to songs by filename instead of title (in album xml)
b) use exsl:node-set()
c) use multiple passes (one to generate songTitle->songFile map, one to generate xhtml)

Firefox: (previewing)
a) refer to songs by filename instead of title (in album xml)
b) wait until Firefox 3 (with exsl:node-set() support)
 
Old May 4th, 2007, 01:52 PM
Authorized User
 
Join Date: Apr 2007
Posts: 38
Thanks: 0
Thanked 0 Times in 0 Posts
Default

I have some good news...

I was able to eliminate all dependency on node-set() in my XSLT. If node-set is available to a parser, it will use it, but otherwise, I fall back on "brute force" templates which get the job done, although slowly and inelegantly.

The one page I wasn't able to get working 100% correctly is my song index page. It lets me sort songs by title, album, year, etc. The sorting works but some of the presentation and counting are dependent upon preceding::node, which seems locked into document order rather than the order specified by xsl:sort. preceding::node works best with node-set(), which I can't use for Firefox. So Firefox's previewing is imperfect for that page.

Aside from that one page, all the other pages preview fine in Firefox now, which is a great relief to me. It means I can eliminate my dependency on IE7 previewing, which is still buggy in Vista. Hooray!

If you are curious what the XML vs HTML versions look like, here are some links. Just try to disregard the subject matter (a really bad band that I chose as an example because it doesn't have many songs or albums).

http://tripalot.com/ipecac/albums/
http://tripalot.com/ipecac/xml/albums.xml

http://tripalot.com/ipecac/songs/
http://tripalot.com/ipecac/xml/songs.xml -- IMPERFECT





Similar Threads
Thread Thread Starter Forum Replies Last Post
XPath: set operation with a disjoint node set rich_unger XSLT 7 May 6th, 2008 09:24 AM
Expression must evaluate to a node-set. XMLUser XSLT 3 February 5th, 2008 01:27 PM
Converting String into Node-set dved XSLT 3 January 23rd, 2008 12:40 PM
Filtering out from a node set anothervbaddict XSLT 1 May 22nd, 2007 08:42 AM
node-set function Bernardo Pacheco XSLT 2 June 19th, 2006 10:45 AM





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