Subject: Re: [xsl] How to properly use Key elements From: Wendell Piez <wapiez@xxxxxxxxxxxxxxx> Date: Wed, 16 Oct 2013 11:04:33 -0400 |
Ted, I'm responding to this since you addressed it to me, although you also seem to have this in hand thanks to Emmanuel and Mike. Mastering keys in XSLT is definitely worth the time and effort invested. On Tue, Oct 15, 2013 at 7:35 PM, G. T. Stresen-Reuter <tedmasterweb@xxxxxxxxx> wrote: > On Oct 14, 2013, at 2:58 PM, Wendell Piez <wapiez@xxxxxxxxxxxxxxx> wrote: > Indeed, were 2.0 an option, I'd definitely be using it! Unfortunately I'm stuck with a 1.0 implementation, but I could be mistaken. We're doing the transformations through PHP (5.3). I've just always assumed libxslt (or whatever it's called) was a 1.0-only implementation. Please: prove me wrong and save me this extra work! Sorry, I can't quite manage that today. What I offered was only the obligatory caution, in case you needed it, which you didn't. :-) ... >> b. use='tr[etc]' will use the values of (certain) 'tr' children of >> your matched 'td' elements as key values, but 'td' never has 'tr' >> children, so even if the key matched, you'd have empty string key >> values. > > So, to clarify, the USE attribute must be a child attribute or element of the MATCH attribute. Is this correct? Not quite. @use accepts any XPath expression, whose returned values are cast to strings (in XSLT 1.0) for purposes of the key lookup. But the XPath is evaluated relative to the node matched by the key. So your expression "tr[etc]" will be evaluated from the context of 'td' elements, since the key matches those. >> To devise a correct solution, I suggest >> >> 1. Considering whether you can't use XSLT 2.0 for-each-group. > > Can't. :-( Meh! I can see there's still a market for XSLT 1.0 experts (which is fortunate for me). >> 2. If not, consider whether doing this in two passes would simplify >> the problem. (In the first pass you would label the td elements with >> their information types, simplifying the declaration of the key for >> the second pass.) > > Ideal but in this particular case I'm doing this for a client and such an approach *might* imply a change to their base processing system. I do think, though, that I could probably create a variable (via exslt extensions) consisting of a fragment marked up as suggested and then operate on the fragment. Also meh. I suppose exslt is fair enough, but I also hate micropipelining in a language not really designed to support it. (Or designed to support it and then restricted formally from doing so, which may be closer to the case.) >> 3. If neither of these, please clarify the logic whereby you know >> which td is of which type. > > It may not have been clear in my sample markup so let me put it this way: we are processing HTML tables of data. Each table contains "sections". The start of each section is indicated by the presence of 4 TD elements in the first row. Other rows only have 2 or 3 TD elements. The first TD element in the first row has a ROWSPAN attribute running the length of the rows for that section. This TD element has a value that represents the group name (is what we'd like to group by). > > Given your clarification about how keys work, it sounds like I need something like this: > > <xsl:key > name="ports-by-ship" > match="tr" > use="tr[count(td) = 4]/td[position() = 1]" > /> I am guessing you need something like <xsl:key name="ports-by-ship" match="tr[count(td) = 4]/td[3]" use="../td[1]"/> <xsl:key name="ports-by-ship" match="tr[count(td) != 4]/td[1]" use="../preceding-sibling::tr[count(td)=4][1]/td[1]"/> Note the use of two declarations for the same key. This is permitted, and very useful in cases like this. Here, the first declaration catches the ports from the rows with four cells, the second catches the ports from the others. Untested! ... > but I have to think that this would only give me the first row of TD elements, and not all of those that follow. I suspect that I might need something like "following-sibling::td" in the MATCH attribute or maybeb& > > <xsl:key > name="ports-by-ship" > match="td" > use="td[ancestor::tr[count(td) = 4]][1]" > /> > > and even then I suspect I'll get ALL the ancestors instead of just the most recentb& ... yes ... the key to keys is to match the elements you wish to retrieve, and find the values you want to use for the retrieval relative to those elements. >> At a higher level, I think the essence of the problem here is that you >> aren't accounting for evaluation context properly in devising your >> XPaths. Some review of the design and functionality of keys (apart >> from how to do Muenchian grouping) would be effort well spent. Keys >> are extremely useful in XSLT 2.0 as well! though no longer so >> necessary for grouping. > > I've read and re-read everything I could find about keys but it's just one of those things that for me, takes a while to sink in, especially if I haven't seen it in a while. I fully understand their power and have used them successfully in the past, but I'm just a bit lost on this one. They take practice, but gradually things click into place. Plus the practice is good for XPath in general since it's all about relative path traversal. Good luck! Wendell _____oo_________o_o___ooooo____ooooooo_^
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] How to properly use Key e, G . T . Stresen-Reut | Thread | Re: [xsl] How to properly use Key e, G. T. Stresen-Reuter |
Re: [xsl] Using Saxon 2.0 with FOP,, Michael Kay | Date | Re: [xsl] Using Saxon 2.0 with FOP,, Jesper Tverskov |
Month |