[xslt] Order of | in apply-templates significant?



I've been using libxslt for a while and banging on this issue 
frequently.

Using libxml 20422, libxslt 10018 and libexslt 709
xsltproc was compiled against libxml 20422, libxslt 10018 and libexslt 
709
libxslt 10018 was compiled against libxml 20422
libexslt 709 was compiled against libxml 20422

I'm getting "node already has children" when trying to append 
attributes to elements.

Here's a sample, a transform to lowercase element and attribute names:

source XML:
<?xml version="1.0"?>
<A THIS="that" THAT="this">text<B/></A>

Following XSLT fails with:
runtime error: file attr-node.xls line 12 element attribute
xsl:attribute : node already has children
runtime error: file attr-node.xls line 12 element attribute
xsl:attribute : node already has children

and outputs:
<?xml version="1.0"?>
<a>text<b/></a>

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

<xsl:template match="*">
   <xsl:element name="{translate(name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
'abcdefghijklmnopqrstuvwxyz')}">
   <xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>

<xsl:template match="@*">
   <xsl:attribute  name="{translate(name(), 
'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')}">
     <xsl:value-of select="."/>
   </xsl:attribute>
</xsl:template>

<xsl:template match="node()">
	<xsl:copy>
		<xsl:apply-templates select="node()|@*"/>
	</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Changing the first (element) template to reverse the select:

<xsl:template match="*">
   <xsl:element name="{translate(name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
'abcdefghijklmnopqrstuvwxyz')}">
   <xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>

and it works fine:
<?xml version="1.0"?>
<a this="that" that="this">text<b/></a>

Running the failing version (select="node()|@*"/> ) in verbose mode 
seems to confirm that libxslt grabs the nodes in order of the select 
and not in the order of the input tree where the attribute nodes should 
come before the text and children nodes:

xsltProcessOneNode: applying template '*' for A
xsltEvalXPathString: returns a
xsltEvalAttrValueTemplate: {translate(name(), 
'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')} returns a
xsltApplyTemplates: node: A
xsltApplyTemplates: select node()|@*
xsltApplyTemplates: list of 4 nodes
xsltProcessOneNode: no template found for text
xsltDefaultProcessOneNode: copy text text
xsltProcessOneNode: applying template '*' for B
xsltEvalXPathString: returns b
xsltEvalAttrValueTemplate: {translate(name(), 
'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')} returns b
xsltApplyTemplates: node: B
xsltApplyTemplates: select node()|@*
xsltApplyTemplates: list of 0 nodes
xsltProcessOneNode: applying template '@*' for attribute THIS
runtime error: file attr-node.xls line 12 element attribute
xsl:attribute : node already has children
xsltProcessOneNode: applying template '@*' for attribute THAT
runtime error: file attr-node.xls line 12 element attribute
xsl:attribute : node already has children

compare to working version (select="@*|node()"/>), see that attributes 
are now handled first:

xsltProcessOneNode: applying template '*' for A
xsltEvalXPathString: returns a
xsltEvalAttrValueTemplate: {translate(name(), 
'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')} returns a
xsltApplyTemplates: node: A
xsltApplyTemplates: select @*|node()
xsltApplyTemplates: list of 4 nodes
xsltProcessOneNode: applying template '@*' for attribute THIS
xsltEvalXPathString: returns this
xsltEvalAttrValueTemplate: {translate(name(), 
'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')} returns 
this
xsltValueOf: select .
xsltValueOf: result that
xsltProcessOneNode: applying template '@*' for attribute THAT
xsltEvalXPathString: returns that
xsltEvalAttrValueTemplate: {translate(name(), 
'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')} returns 
that
xsltValueOf: select .
xsltValueOf: result this
xsltProcessOneNode: no template found for text
xsltDefaultProcessOneNode: copy text text
xsltProcessOneNode: applying template '*' for B
xsltEvalXPathString: returns b
xsltEvalAttrValueTemplate: {translate(name(), 
'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')} returns b
xsltApplyTemplates: node: B
xsltApplyTemplates: select @*|node()
xsltApplyTemplates: list of 0 nodes

I've looked around on Google, bug list, list archives, etc. and could 
not find any report of this, though I'd join and check with the list 
before posting to bugzilla.

Francois Belanger
Sitepak





[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]