XSLT 2.0 Idea: third argument for key()
Hello everyone, In brief: I'd like to suggest having a third argument for key(), a node set, such that the key only retrieves nodes with the relevant key value that are within this node set. In detail: There are two related limitations on using key() as it stands. The first is the way it interacts with document() [nodes are only retrieved by key() within the document that the current node is in]. The second is in restricting the nodes retrieved by key() to a certain subset of the document. As an example of the first, say you want to sort values in an arbitrary order based on some data defined within your stylesheet: <foo:order> <item>first</item> <item>second</item> <item>third</item> <item>fourth</item> </foo:order> <key name="order" match="foo:order/item" use="." /> It is difficult to use the position of these nodes in order to sort elements within the source because the only way it could plausibly be expressed is: <ol> <xsl:for-each select="runner"> <xsl:sort select="count(key('order', @rank)/preceding-sibling::item)" data-type="number" /> <li><xsl:value-of select="name" /></li> </xsl:for-each> </ol> and in this, the current node when key() is called is always the node in the source ('runner' element), and therefore the key() only retrieves nodes from the source, never from the stylesheet. [David Carlisle's pointed out that you can get around this using an extension element like saxon:function that allows you to define extension functions in XSLT to retrieve the required value.] With a third argument on key, you could do: <xsl:variable name="items" select="document('')/foo:order/item" /> <ol> <xsl:for-each select="runner"> <xsl:sort select="count(key('order', @rank, $items)/preceding-sibling::item)" data-type="number" /> <li><xsl:value-of select="name" /></li> </xsl:for-each> </ol> Here's an example of the second area in which this would be useful, restricting nodes to a known node set: say I had a document with a massive dataset like: <athletes> <country id="GRB"> <athlete event="100 metres">...</athlete> <athlete event="200 metres">...</athlete> <!-- another 400 athletes --> </country> <country id="ROI"> <athlete event="100 metres">...</athlete> <athlete event="800 metres">...</athlete> <!-- another 400 athletes --> </country> ... </athletes> I want to put the details of the athletes in a table, with columns being countries and rows being events, so I use a key to index on the event, and access the data for the table using: key('athletes', @event)[generate-id(parent::country) = generate-id(current()/parent::country)] or something similar. It would be a lot cleaner to do: key('athletes', @event, parent::country/child::athlete) [or key('athletes', @event, ../*) for brevity] (i.e. search for only the athletes that are children of the parent::country of the current node). A third argument on key() could not only enable you to expand the search to other documents, but also to restrict it within the current one - to choose which nodes to take into consideration. Any thoughts? Objections? Implementation issues? Jeni Jeni Tennison http://www.jenitennison.com/ XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
PURCHASE STYLUS STUDIO ONLINE TODAY!
Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!
Download The World's Best XML IDE!
Accelerate XML development with our award-winning XML IDE - Download a free trial today!
Subscribe in XML format