[Home] [By Thread] [By Date] [Recent Entries]
Hi Michael,
Though you didn't really requested it, I tried to take your example and make it generic. I.e.: a nesting level is demanded by the number in liX. This means that: <li1>test1</li1> <li3>test3</li3> will return <ul level="1">
<li tag="li1" pos="1">test1</li>
<ul level="2">
<ul level="3">
<li tag="li3" pos="1">test3</li>
</ul>
</ul>
</ul>Same for any higher level. It will also successfully unwind to lower levels. However, there are some mistakes in my approach (well, depending on your requirements), which makes the unwinding be not successful when the difference is more than -1 (the upwinding goes well though). The reason is simple: I am working on a current group and the function doing the up-winding does not know of the next group. It shouldn't be too hard to change it. All in all, I found applying the very simple rules to a general concept more challenging than I first thought (but it was late last night... ). I used the deep-equal() function to test my results with yours and with input only containing l1/l2 elements the output is correct. The solution is a bit wieldy, but I don't see how it can be more concise or easier. I know I tackled the problem before, but couldn't find the solution I had back then... But if you leave out the functions (which can go elsewhere) it becomes less awkward (you must add a ns decl. for these functions, any will do). I corrected a small errors on your side: I use local-name, where you use name(), which will fail when you add namespaces to your solution. Also, I followed your way of calculating "pos", but I think that the pos-values for your third example should be 1 and 2 for the last two nodes (because they are the first at their level). If you want that, change the 'ge' in my pos-calculation to 'eq'. <xsl:template match="levels" mode="new"> <xsl:copy> <xsl:for-each-group select="*" group-starting-with="p"> <!-- we have to work on a copy of the group, we want to loose the siblings we are not interested in --> <xsl:variable name="group"><xsl:copy-of select="current-group()" /></xsl:variable> <xsl:apply-templates select="$group/*[1]" mode="new" /> </xsl:for-each-group> </xsl:copy> </xsl:template> <xsl:template match="p" mode="new">
<xsl:copy />
<xsl:apply-templates select="following-sibling::*[1]" mode="new" />
</xsl:template><xsl:template match="*[fn:is-li(.)]" mode="new"> <xsl:variable name="current-level" select="fn:li-nr(preceding-sibling::*[1])" /> <ul level="1"> <!-- this level is always one!, see fn:create-levels for others --> <xsl:for-each-group select=". | following-sibling::*" group-adjacent="fn:li-nr(.)"> <xsl:apply-templates select="current-group()[fn:li-nr(.) eq $current-level]" mode="li" /> <xsl:copy-of select="fn:create-levels($current-level, current-group())" /> </xsl:for-each-group> </ul> </xsl:template> <xsl:template match="*[fn:is-li(.)]" mode="li"> <li tag="{name()}" pos="{count(. | preceding-sibling::*[fn:is-li(.)][fn:li-nr(.) ge fn:li-nr(current())])}"> <xsl:value-of select="." /> </li> </xsl:template> <!-- recursively create a higher level when level numbers skip a level --> <xsl:function name="fn:create-levels"> <xsl:param name="current-level" /> <xsl:param name="current-group" /> <xsl:if test="fn:li-nr($current-group[1]) gt $current-level"> <ul level="{$current-level + 1}"> <xsl:copy-of select="fn:create-levels($current-level + 1, $current-group)" /> <xsl:apply-templates select="$current-group[fn:li-nr(.) eq $current-level +1]" mode="li" /> </ul> </xsl:if> </xsl:function> <!-- true for a node of type <liX> where X is a number -->
<xsl:function name="fn:is-li">
<xsl:param name="node" />
<xsl:sequence select="starts-with(local-name($node), 'li')" />
</xsl:function><!-- returns the X as an integer from the node of type <liX> --> <xsl:function name="fn:li-nr"> <xsl:param name="node" /> <xsl:variable name="num" select="replace(local-name($node), '[a-zA-Z]', '')" /> <xsl:sequence select="if($num) then xs:integer($num) else 1" /> </xsl:function> Cheers and have fun with it! -- Abel Braaksma Michael M|ller-Hillebrand wrote: Hello,
|

Cart



