By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
425,749 Members | 1,615 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 425,749 IT Pros & Developers. It's quick & easy.

xmlTransform transform <xsl:number> - possible Bug

P: n/a
Hi Group,

I think I have found a problem with the <xsl:element> when being
transformed by the .NET xmlTransform class. When using XmlSpy for
development and debugging, the <xsl:number> subsitutes the position of the
node correctly as I expected. This is fine with MSXML 3.0 & MSXML 4.0 plus
the XmlSpy internal engine.

I have been able to reproduce using a simpler Xml and Xsl to demonstrate;
XML
===
<?xml version="1.0" encoding="UTF-8"?>
<html>
<head><title>Tester</title></head>
<body>
<h4 class="no">Table 1</h4>
<table><tbody><tr><td>Some Data</td></tr></tbody></table>
<h4 class="yes">Table 2</h4>
<table><tbody><tr><td>Some Data</td></tr><tr><td>Some Data
2</td></tr><tr><td>Some Data 3</td></tr></tbody>
</table>
<h4 class="yes">Table 3</h4>
<table><tbody><tr><td>Some Data</td></tr><tr><td>Some Data
2</td></tr><tr><td>Some Data 3</td></tr></tbody></table>
<h4 class="yes">Table 4</h4>
<table><tbody><tr><td>Some Data</td></tr><tr><td>Some Data
2</td></tr></tbody></table>
</body>
</html>

My XSL needs to return all rows that are in a table that has @class = 'yes'
and set an id attribute to the absolute position in the document - in
relation to all tables with @class = 'yes'.

XSL that achieves this
===============
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<xsl:element name="TableMatch">
<xsl:apply-templates select="//h4[@class='yes']" />
</xsl:element>
</xsl:template>
<xsl:template match="h4">
<xsl:element name="Table">
<xsl:for-each select="following-sibling::table[1]/tbody/tr">
<xsl:element name="row">
<xsl:attribute name="id">
<xsl:number level="any" from="//h4[@class='yes'][1]" />
</xsl:attribute>
<xsl:value-of select="td" />
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

This produces Output
==============
<?xml version="1.0" encoding="UTF-16"?>
<TableMatch>
<Table>
<row id="1">Some Data</row>
<row id="2">Some Data 2</row>
<row id="3">Some Data 3</row>
</Table>
<Table>
<row id="4">Some Data</row>
<row id="5">Some Data 2</row>
<row id="6">Some Data 3</row>
</Table>
<Table>
<row id="7">Some Data</row>
<row id="8">Some Data 2</row>
</Table>
</TableMatch>

Which is great! Now when I try the transformation using the following code
(C#);

public static void Main()
{
doc = new XPathDocument(inputFile); // Create New
XPath Document to open File
XPathNavigator navi = doc.CreateNavigator(); // Create
XPathNavigator to navigate through document

writer = new XmlTextWriter("xlsnumberOutput.xml" , Encoding.UTF8); //
Create new xmlTextWriter

// Now need to transform into Xml format
XslTransform transform = new XslTransform();
transform.Transform(doc, null, writer, new XmlUrlResolver());

// Kill Writer
writer.Flush();
writer.Close();
}

The <xsl:number> element is returning a blank string i.e. nothing and the
output is as follows;

<TableMatch>
<Table>
<row id="">Some Data</row>
<row id="">Some Data 2</row>
<row id="">Some Data 3</row>
</Table>
<Table>
<row id="">Some Data</row>
<row id="">Some Data 2</row>
<row id="">Some Data 3</row>
</Table>
<Table>
<row id="">Some Data</row>
<row id="">Some Data 2</row>
</Table>
</TableMatch>

@id is blank! The reason I want the @id in this way is because I want to
generate a unique identity across *all* matching rows. The .NET transform
has some problem achieving this.

Can anyone advise what the problem is here or some way of working around
this?

TIA (if you got this far :p)

b0yce
Nov 12 '05 #1
Share this Question
Share on Google+
3 Replies


P: n/a
<snip>

Can anyone advise what the problem is here or some way of working around
this?

TIA (if you got this far :p)

b0yce


Forgot to mention (pressed Send too early :) ) that I have narrowed it down
to the <xsl:number> from="" parameter.

Changing
<xsl:number level="any" from="//h4[@class='yes'][1]"/>
to
<xsl:number level="any" from="body"/>

now produces;
<?xml version="1.0" encoding="UTF-16"?>
<TableMatch>
<Table>
<row id="2">Some Data</row>
<row id="3">Some Data 2</row>
<row id="4">Some Data 3</row>
</Table>
<Table>
<row id="5">Some Data</row>
<row id="6">Some Data 2</row>
<row id="7">Some Data 3</row>
</Table>
<Table>
<row id="8">Some Data</row>
<row id="9">Some Data 2</row>
</Table>
</TableMatch>

in by all engines. Starting from 2 is not ideal since there could be n
number of tables @class='no' beforehand.

So it could be that in .NET XslTransform <xsl:number> doesn't like "//"
document root references?

Nov 12 '05 #2

P: n/a
Another time while playing around to get this to work, I changed the *from*
parameter again from "body" to "//h4[@class='yes']" (without the 1 indexer)
and it works, but the number is in relation to the ordinal position from the
current table and not the first table in the document - which is what I am
after. :(

So <xsl:number from="..."> works ok in MSXML 3.0 & 4.0 and in XML .NET. But
in the XML .NET it doesn't work when the @from parameter contains ordinal
position indexer. Seems strange.

???

b0yce

Forgot to mention (pressed Send too early :) ) that I have narrowed it down to the <xsl:number> from="" parameter.

Changing
<xsl:number level="any" from="//h4[@class='yes'][1]"/>
to
<xsl:number level="any" from="body"/>

now produces;
<?xml version="1.0" encoding="UTF-16"?>
<TableMatch>
<Table>
<row id="2">Some Data</row>
<row id="3">Some Data 2</row>
<row id="4">Some Data 3</row>
</Table>
<Table>
<row id="5">Some Data</row>
<row id="6">Some Data 2</row>
<row id="7">Some Data 3</row>
</Table>
<Table>
<row id="8">Some Data</row>
<row id="9">Some Data 2</row>
</Table>
</TableMatch>

in by all engines. Starting from 2 is not ideal since there could be n
number of tables @class='no' beforehand.

So it could be that in .NET XslTransform <xsl:number> doesn't like "//"
document root references?

Nov 12 '05 #3

P: n/a
I have managed to get this to work now in XML .NET.

One that don't work (only in XML .NET but fine in MSXML 3.0 and 4.0);

<xsl:number level="any" from="//H4[@class='yes'][1]" />

One that works in all versions;

<xsl:number level="any" from="//H4[@class='yes'][position()=1] />

I am surprised myself that I never tried this before, but I *always* use the
shorthand of [1] instead of [position() = 1] - just my lazy development
techniques ;).

The shorthand works in all but XML .NET version so I am not sure if this is
by design that it doesn't work or whether it is a slight oversight.
Eitherway I am happy I have found a solution.

So hopefully this will serve as some useful information for others out
there!

Enjoy

b0yce
Nov 12 '05 #4

This discussion thread is closed

Replies have been disabled for this discussion.