Tuesday, October 09, 2007

More XSL

Position

I was converting XML to XHTML, and ran into a problem. Position() no longer works as expected once I start creating new nodes in the document! If your root node contains four nodes, and for each node you create a div, you'd think the condition position()=last() would be satisfied for the last node-- but it stops working. Instead, you have to use count() and following-sibling and preceding-sibling to figure out where you are.

The position() returns the context position, so in *[position() = 1] it refers to the context of selecing all child element nodes, i.e. filters out all nodes whose context position is not 1., i.e. returns the child element; if you have following::*[1], it selects all the elements that follow the current node, then filters out all those whose context position is not 1, i.e. again selecting only the first element that follows the current node.

So, to get the position of the current node at the current level:
<xsl:value-of select="count(preceding-sibling::*)+1"/>


The above is necessary when doing xml->xhtml because the node tree gets wacky and position() can't be trusted. Check it out by printing
<xsl:value-of select="position()"/>/<xsl:value-of select="last()"/>/<xsl:value-of select="count(*)"/>


Following-sibling example:

As long as there are no further children <xsl:if test="following-sibling::*">

Precending-sibling works similarly.

Whitespace and Funny Characters
I also noticed that when I had plain text in my XSL, it would come out all crazy with lots of pound signs and ampersands. So, if you want to print out plain text in the transformed document, enclose it in:
<xsl:text>my text goes here</xsl:text>

In addition, I had to test whether the text() value of a node was empty, but it kept returning a bunch of whitespace! This is a common issue, and you can test for an empty value like so:

<xsl:if test="string-length(normalize-space(.))>0">
<div>Value:<input><xsl:attribute name="value"><xsl:value-of
select="."/></xsl:attribute></input>
</div>
</xsl:if>

Creating Tags with Attributes

I tried to create HTML input tags with their value set based on the source XML doc. But if you have a tag in your XSL you can't put other tags like value-of inside an attribute-- the parser barfs. You need to create an empty input tag and inside its body use xsl:attribute, like so:

<div>Value:
<input><xsl:attribute name="value">
<xsl:value-of select="."/></xsl:attribute>
</input>
</div>


And finally some useful links:
http://www.15seconds.com/issue/011129.htm
http://www.quirksmode.org/js/events_order.html

No comments:

Labels

Blog Archive

Contributors