Subject: RE: [xsl] Different Colors for Alternating Rows From: "Schwartz, Rechell R, ALABS" <rrschwartz@xxxxxxx> Date: Mon, 30 Jun 2003 15:49:27 -0500 |
Kevin, Thanks for your help. I got the following error, when I tried your stylesheet. Does this mean my parser won't support extensions? What can I do about this? Rechell ####<Jun 30, 2003 1:05:03 PM EDT> <Info> <GUI> <maeder> <FM> <ExecuteThread: '7' for queue: 'default'> <> <> <0 00000> <data.jsp::XSL Transformation Exception:java.lang.NoSuchMethodException: For extension function, could n ot find method weblogic.apache.xerces.dom.DocumentFragmentImpl.node-set([ExpressionContext,] ).> ####<Jun 30, 2003 1:05:03 PM EDT> <Info> <GUI> <maeder> <FM> <ExecuteThread: '7' for queue: 'default'> <> <> <0 00000> <javax.xml.transform.TransformerException: java.lang.NoSuchMethodException: For extension function, coul d not find method weblogic.apache.xerces.dom.DocumentFragmentImpl.node-set([ExpressionContext,] ). at weblogic.apache.xalan.transformer.TransformerImpl.transformNode(TransformerImpl.java:1248) at weblogic.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:483) at weblogic.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1153) at jsp_servlet._maint.__data._jspService(__data.java:247) at weblogic.servlet.jsp.JspBase.service(JspBase.java:27) at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:265) at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:304) at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:200) at weblogic.servlet.internal.WebAppServletContext.invokeServlet(WebAppServletContext.java:2495) at weblogic.servlet.internal.ServletRequestImpl.execute(ServletRequestImpl.java:2204) at weblogic.kernel.ExecuteThread.execute(ExecuteThread.java:139) at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:120) --------- ; Line#: 27; Column#: 55 -----Original Message----- From: Kevin Jones [mailto:kjones@xxxxxxxxxxx] Sent: Saturday, June 28, 2003 5:20 AM To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx; Schwartz, Rechell R, ALABS Subject: Re: [xsl] Different Colors for Alternating Rows On Thursday 26 June 2003 16:07, Schwartz, Rechell R, ALABS wrote: > Before I throw in the towel on this one, I tried my own approach, which I > thought should work, but didn't. Hi Rechell, Looked like this was an interesting problem so I thought I would use it as a test bed of the various techniques I know for making this run quickly. To save you some time I can say that while the last solution posted looks interesting it performs badly on large data sets. Your last version looked like it was heading into the dead end of stack overflow although I didn't get the full intent of it. I have benchmarked the problem with five techniques on samples in the 1000-9000 entry range. The best performer is what is sometimes called forward calling, Jarno gave you a good example of that in an earlier post. Unfortunately you need a processor that supports tail recursion optimisation to avoid this creating the stack faults you have been getting. Saxon 7.5 does this very well in this case but I understand you can't change processor easily. The next best technique is divide and conquer (also known as DVC). While this performs well it can be a bit complex to get your head around. A simpler technique is what you might refer to as RTF indexing, this gives almost the same performance as DVC but is simpler to understand so I will explain how I implemented that. For reference, with 6000 entries this technique is roughly 75 times quicker than your original although it will use a bit more memory but there is no danger of it causing a stack overflow. This technique relies on creating a result tree fragment (a temporary XML fragment) that can the be indexed using the key() function. To create the tree your first want to add a global variable like so, <xsl:variable name="index"> <xsl:for-each select='/table/tr[td[not(a or @class)]]'> <entry key='{generate-id()}' even="{position() mod 2 = 1 }"/> </xsl:for-each> </xsl:variable> This creates a fragment in the variable that will look something like this, <entry key='NDJKDHKJK' even='false'/> <entry key='NDJKDGHJJ' even='true'/> <entry key='NDJKJHKKK' even='false'/> One for each tr element you need to colour. The key value is just a unique identifier for the tr node that has been represented as a string. Its exact format is processor dependent. For the second bit you need a key declaration that will index this. In my case I have <xsl:key name='lookup' match='entry' use='@key'/> This effectively says create an index of 'entry' nodes and use the string value of the '@key' attribute of those nodes as the key for retrieving the nodes. The final bit is to rewrite your template to make use of the key. <xsl:template match="table/tr[td[not(a) and not(@class)]]"> <xsl:variable name='tr' select='.'/> <xsl:for-each select='exslt:node-set($index)'> <xsl:call-template name='copytr'> <xsl:with-param name='node' select='$tr'/> <xsl:with-param name='inset' select='true()'/> <xsl:with-param name='even' select='key("lookup",generate-id($tr))/@even'/> </xsl:call-template> </xsl:for-each> </xsl:template> This may look quite different from what you started with but its really the same thing. I have taken the formating code out into a separate template 'copytr' to make it a bit clearer. Taking it line by line, The match is the same as before. When you use key() it returns results from the same document that the context node is in. We need results from the variable so I have added a for-each loop which selects the root node of that fragment. It is not really looping, as there is only one root element, but it does change the context so that we are now accessing nodes from the variable tree when using key(). To save having to swap the context back I have also saved the context node in the variable $tr before doing this. The exslt:node-set call is needed to get around a restriction in XSL 1.0 processors. Your processor will either support this function or something very similar to it. The only remaining code is the arguments to copytr. We pass the node that needs copying, a flag indicating is this is part of the set you want coloured and if this is an even or odd node. The interesting bit is of key() call used to determine if this is even or odd. If we use generate-id($tr) we get back the same string we use to index this node and we also know this is a unique string for that node. So the key call will return a nodeset containing the one and only 'entry' element that matches this identifier. It is then just a matter of checking the @even attribute to see if this should be considered an even or odd node. The complete solution is below. Kev <?xml version="1.0" encoding="iso-8859-1"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" extension-element-prefixes="exslt" version="1.0"> <xsl:output method="html" indent="yes"/> <xsl:key name='lookup' match='entry' use='@key'/> <xsl:variable name='index'> <xsl:for-each select='/table/tr[td[not(a or @class)]]'> <entry key="{generate-id()}" even="{position() mod 2 = 1}"/> </xsl:for-each> </xsl:variable> <xsl:template match="node()|@*" name="copy"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="table/tr[td[not(a) and not(@class)]]"> <xsl:variable name='tr' select='.'/> <xsl:for-each select='exslt:node-set($index)'> <xsl:call-template name='copytr'> <xsl:with-param name='node' select='$tr'/> <xsl:with-param name='inset' select='true()'/> <xsl:with-param name='even' select='key("lookup",generate-id($tr))/@even'/> </xsl:call-template> </xsl:for-each> </xsl:template> <xsl:template name='copytr'> <xsl:param name='node' select='.'/> <xsl:param name='inset'/> <xsl:param name='even'/> <xsl:for-each select='$node'> <xsl:copy> <xsl:choose> <xsl:when test="$inset"> <xsl:choose> <xsl:when test="$even=true()"> <td class="evenMedium" width="35%"> <xsl:apply-templates select="td[1]/node()|td[1]/@*"/> </td> <td class="evenMedium" width="65%"> <xsl:apply-templates select="td[2]/node()|td[2]/@*"/> </td> </xsl:when> <xsl:otherwise> <td class="oddMedium" width="35%"> <xsl:apply-templates select="td[1]/node()|td[1]/@*"/> </td> <td class="oddMedium" width="65%"> <xsl:apply-templates select="td[2]/node()|td[2]/@*"/> </td> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="node()|@*"/> </xsl:otherwise> </xsl:choose> </xsl:copy> </xsl:for-each> </xsl:template> </xsl:stylesheet> XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
RE: [xsl] Different Colors for Alte, Schwartz, Rechell R, | Thread | [xsl] background-image being enlarg, Aimee Rodgers |
Re: [xsl] translate function, David Carlisle | Date | [xsl] apply templates on a variable, Rob Rohan |
Month |