Re: [xsl] xsltproc complains about xsl:sort

Subject: Re: [xsl] xsltproc complains about xsl:sort
From: "M. David Peterson" <m.david@xxxxxxxxxx>
Date: Mon, 02 Aug 2004 19:03:32 -0600
Hey Ed,

While I dont work with xsltproc I can give you a general feel for the requirement of using the xsl:sort element... and they are pretty straight forward... xsl:sort can only be a child of xsl:for-each and xsl:apply-templates. It must be an immediate child with no "older" siblings so to speak, only "younger". While I dont see any code that is in violation of these rules there are some snips that may contain some xsl:sort elements that are out of place... why XMLSpy lets you run the code while xsltproc calls foul with xsl:sort I can only speculate by the value of the error message that xsltproc has simply located a point in your stylesheet that can in no way ever be reached and as such is telling you this to help performance tune. Again, only a guess... if you could further point out what the contents of line 218 looks like it might give us more information to help you decipher things a bit more...

As for your "double vision". Again, Im not seeing an immediate culprit but you havent shown the templates that apply-templates can match to and I suspect this is where the code problem lays... Actually, I just realized you have an apply-templates in a for-each loop which will always cause some funky behavior.. remember that each pass through the for-each loop will only take the next child in the list created by your xpath statement... apply-templates to one child and/or its attribiutes and/or children is not something that will gain you much, unless of course the children are a bi-product of a local polygamist group and as such come by the dozens... still, the logic used should probably be reversed... apply-templates until you get down to the point where there is only one set of children left to process and only use a for-each loop for a case when you are iterating through them to create simple lists or to change the background color or border of a cell based on there position, etc... I hate to get real specific here because theres actually lots of reasons where a for-each loop makes sense in place of apply-templates. But my rule of thumb is to always use apply-templates if it works for the situation as the code that you produce becomes much more manageable in the end... from a simplistic stand point imagine apply-templates taking the contents of a basket of apples and oranges and putting them in there own matching basket... one basket that matches the apples and one that matches the oranges... each template can then process each one for juice according to the characteristics particular to the fruit. But if you later decide you dont want the apple basket to produce apple juice, you simply want apples but you still want the oranges basket to produce orange juice, from a coding stand point I am sure you can see why using seperate templates that are factories in and of themselves as opposed to a for-each loop that contains a <xsl:choose><xsl:when.../><xsl:otherwise.../></xsl:choose> block of code can be easier to manage, especially when you have a complex underlying process to extract the juice or make a pie... etc...

But I havent addressed your "double vision", have I... the most common culprit for double vision is the use of xsl:apply-templates and xsl:value-of. The problem comes when the first element in the matching node-set is a text node. XSLT doesnt like to deal with anything that doesnt start with an < bracket. As such when apply-templates is called and the first member of the child elements is a text node (see example below) apply-templates will scan the current node set until it finds the first < bracket and deposit whatever is before the angle bracket right where it found it.... so the following code will output the value of the current node and then apply-templates to the children of the current node in context, and as such dump that value of the that first text node right where it found it...

So this...

<xsl:template match="foo">
	<xsl:value-of select="."/>
	<xsl:apply-templates />
</xsl:template>

Will recursively match these foo elements:

<foo>
	This is the value of foo
	<foo>
		this is foo, the child of foo's child value
		<foo>
			etc......
		</foo>
	</foo>
</foo>

And produce these results (current processing instruction in parentheses)

(Match "foo"):

(Print value-of current element): This is the value of foo.

(Match children of current element to template): <!-- will dump each character that is not "<" to the output--> This is the value of foo
<!-- note: same exact value from the same exact node that you used xsl:value-of to output the value of to the output stream. xsl:value-of just makes a copy of what you are asking for and prints it to the output... its still exactly where it was found until it has been removed by a recursive processing element of some sort.-->
(Match "foo"): <!-- matches to the same template as the parent matched to thus continuing the recursive process -->
(Print...)


Im sure you get the idea... While I cant say for sure that this is your problem this tends to be the culprit in most cases of the double vision effect and as such I suspect this is probably what is happening in your case...

I hope any or all of this helps get you to where your going!

Best of luck!

<M:D/>

Ed_Owen@xxxxxxxxxxxxxxxxxxxx wrote:




I'm using XSLT to transform some XML output from Doxygen into WordML, Microsoft's XML schema for Word documents.

I've been using Altova's XMLSpy to create the XSLT and to do the actual
transform.

This works great, but I am seeing some weird things where certain elements
that appear in the source XML tree once are getting processed twice.

For a sanity check, I tried to do the transformation using xsltproc
instead. When I did that, I got the following run-time error for just about
every occurrence of <xsl:sort> in my XSLT:

      runtime error: file sce-rt2.xslt line 218 element sort
      xsl:sort : improper use this should not be reached

XMLSpy has no such trouble, and I'm fairly certain everything is
well-formed and happy. Here's the offending line 218 and surrounding from
my XSLT:

      <xsl:for-each select="sectiondef/memberdef">
            <xsl:sort select="name"/>
                  <w:tr>
                        <w:tblPrEx><w:tblCellMar><w:top w:w="0"
w:type="dxa"/><w:bottom w:w="0" w:type="dxa"/></w:tblCellMar></w:tblPrEx>
      [snip]
                        <xsl:value-of select="@id"/>
      [snip]
                        <w:t><xsl:value-of select="name"/></w:t>
                        <xsl:apply-templates select="briefdescription"/>
                  </w:tr>
      </xsl:for-each>

The xml file being transformed is rather large (1.5 MB), but not incredibly
so. With XMLSpy, the resulting XML file runs 6 MB+ (yay WordML).

I'm running Windows 2000. This happens with both xsltproc 1.1.7 and 1.1.8.

Any ideas or similar experiences would be appreciated. I've checked the
various archives and bug lists and don't see this documented (or I missed
it).

thanks,
Ed

Current Thread