Subject: Re: [xsl] position() return's only even numbers for nested elements|
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Fri, 9 May 2003 18:17:12 +0100
Hi Michal, > please take a look at this xsl fragment, maybe you find a simple > explanation to strange behaviour of position() function for nested > elements. When an XSLT processor builds a tree from an XML document, all the text in the document is included in the tree. This includes "insignificant whitespace" that appears between element nodes (purely to make the document more readable). So when your document is converted to a tree, the tree actually looks like: uml +- text: "
" +- package +- text: "
" +- package +- text: "
" +- package | +- text: "
" | +- package | +- text: "
" | +- ... +- ... When you apply templates with just <xsl:apply-templates /> then the processor selects *all* the children of the current node: that includes all the whitespace. If you number the children, 1 is a text node (whitespace), 2 is a package element, 3 is another text node, 4 is a package element and so on. This is why you only get even numbers when you use <xsl:apply-templates />. When you apply templates with <xsl:apply-templates select="package" /> then the processor selects only the package elements. If you number the children, 1 is the first child package element, 2 is the second child package element and so on. This is why you get the correct numbering in this case. There are three solutions to your problem. First, you could always select the nodes that you actually want to process (the package elements), so that you get numbering amongst those nodes. Second, you could strip out the insignificant whitespace from the uml and package elements using the <xsl:strip-space> declaration. At the top level of your stylesheet, put: <xsl:strip-space elements="uml package" /> This tells the processor to strip out all the whitespace-only text nodes that are children of uml or package elements. Then, when you use <xsl:apply-templates> without a select attribute, it will still select all the children of the uml or package element, but the tree won't contain any whitespace so the only children selected will be package elements. Third, rather than using the position() function to get numbers for the package elements, you could use the <xsl:number> instruction: <xsl:attribute name="position"> <xsl:number /> </xsl:attribute> By default, the <xsl:number> element counts only those nodes that are of the same kind (and have the same name, if they're elements) as the node you're numbering, so it will ignore the text nodes in the tree. If you use this option, the numbering will always reflect the position of the elements in the source tree, so might not give you the numbering you expect if you sort the packages into some other order to process them. The second option is probably the best because as well as making your code easier, it also makes the tree smaller, which cuts down on the amount of memory the processor requires, which probably speeds up the processing (though probably unnoticeably unless your document is huge). Cheers, Jeni --- Jeni Tennison http://www.jenitennison.com/ XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list