Subject: Re[2]: question with using Muenchian/xsl:key (Re: sort/group/count p robl em) From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx> Date: Sun, 12 Nov 2000 20:05:04 +0000 |
Xiaocun, > I also tried the normal (inefficient) way of using two XPath: > <xsl:for-each select="item[not(@itemid = preceding-sibling::item/@itemid)]"> > <td class="text" width="48%"><xsl:value-of select="@itemid"/></td> > <td class="text-right" width="6%"><xsl:value-of select="sum(item[@itemid = > current()/@itemid]/@units)"/></td> > </xsl:for-each> > > That also returned me a sum of 0, is there something wrong with my > calculation of sum? Yes. The calculation here is for the sum of the units attributes for the item elements whose itemid attribute is equal to the current node's itemid attribute *and that are children of the current node*. However, within the xsl:for-each, the current node is an 'item' element, a *sibling* of the other items that you're interested in. The correct XPath for the sum is: sum(../item[@itemid = current()/@itemid]/@units) As far as using keys are concerned, I'm not convinced that they are substantially better than the above method with the problem as you describe it now. Whether or not the Muenchian Method is worthwhile depends on what the payoff between memory (keys take up more memory) and speed (keys take less time) are for you, and on the number of items within one itemlist compared to the number of items throughout. If there are only a few items in each itemlist, and you're processing each itemlist in turn, then it's probably not worth using keys for this problem. However, if speed is more important and the itemlists are long, then the vital thing that you need to do is narrow down the list of items that the key gives you for a particular itemid in the context of a particular itemlist. There are two general ways of doing this. The first is, as David Carlisle suggested, to include information about the itemlist that you're currently looking at in the key value that you use to retrieve the items you're interested in. At present, the key that you have looks like: <xsl:key name="items" match="item" use="@itemid" /> The key value is the value of the itemid attribute on the particular item. You could include in that key value something about the itemlist that the item belongs to: its id, if it has one, or a name, or anything at all that distinguishes it from the other itemlists in the document. The most general thing you can use is its unique id as generated through the generate-id() function. You can include that in your key value by concatenating it with the @itemid value: <xsl:key name="itemlist-items" match="item" use="concat(generate-id(parent::itemlist), '::', @itemid)" /> Then, in order to get the uniquely itemid'd items within a particular itemlist, you can use the XPath: item[generate-id() = generate-id(key('itemlist-items', concat(generate-id(parent::itemlist), '::', @itemid)))] In other words, get the items whose unique id is the same as the unique id of the (first) item returned from the 'items' key with a key value equal to a concatenation of the unique id of the item's parent itemlist, '::', and the item's itemid attribute. You can also use: item[1 = count(. | key('itemlist-items', concat(generate-id(parent::itemlist), '::', @itemid))[1])] In other words, get the items such that there is only one node in the node set resulting from the union of that item and the first item returned from the 'items' key with a key value equal to a concatenation of the unique id of the item's parent itemlist, '::', and the item's itemid attribute. The second general solution is to have the key() return *all* the items (no matter what itemlist they belong to), but filter that list to only those items that are in the itemlist for the item you're looking at. To use this method you have to have a context in which it is possible to get at the common node set that you have in mind. For example, in your case, you need to be in a context where the current node is the itemlist that you're interested in, such as within a template matching that itemlist. Mike Brown suggested one way of doing this using the Kaysian Method for finding node set intersections, which is a general approach that is essential when all you know is the node set filter that you're interested in, not what all those nodes have in common. For example, if you had a global variable that held the node set that you were using as a filter, then Mike's approach would be perfect. In your case, though, you know that the node set filter involves the identity of the itemlist for the items. If you have the unique identity for the current itemlist within a variable: <xsl:variable name="itemlist-id" select="generate-id()" /> then you can filter the node set returned by the key by testing which of them have a parent itemlist that has the same unique id as the current itemlist: key('items', @itemid)[generate-id(parent::itemlist) = $itemlist-id] You can insert this filtered key result into either of the Muenchian XPaths: item[generate-id() = generate-id(key('items', @itemid)[generate-id(parent::itemlist) = $itemlist-id])] or: item[1 = count(. | key('items', @itemid)[generate-id(parent::itemlist) = $itemlist-id][1])] I hope that helps, Jeni --- Jeni Tennison http://www.jenitennison.com/ XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: question with using Muenchian/x, Mike Brown | Thread | RE: question with using Muenchian/x, Xiaocun Xu |
Re[2]: Aggregate, Jeni Tennison | Date | Re: xsl:exclude-result-prefixes, David Carlisle |
Month |