Once again, this post contains a good deal of critique. If
you find that somehow offensive, please just ignore it.
Christian Rühl said:
I'm transforming with javax.xml.transform.*; in Eclipse.
I strongly advise that you get a standalone XSLT processor
somewhere and use it for debugging your transformations.
I'm not a Java programmer by trade, so correct me if I'm
wrong, but I believe it's just a generic API to various
transformation engines.
// set target location and xslt location
m_result = new StreamResult( new
FileOutputStream(m_prodTreeFile) );
m_xsltSource = new StreamSource( new
FileInputStream(m_prodTreeXslt) );
// create transformer factory and transformer instance
m_factory = TransformerFactory.newInstance();
m_transformer = m_factory.newTransformer(m_xsltSource);
Once again, correct me if I'm wrong, but this gives no
indication what engine you're actually using. Could be
Saxon, Xalan-J or any other transformation engine you
happen to have registered with your factory.
// set parameters (files to copy)
m_transformer.setParameter("tree", m_prodTree);
m_transformer.setParameter("archive", m_archiveFile);
Are those file names or parsed XML documents? I believe
passing anything but integral data to your stylesheet is
ill-specified (mmm... if not outright disallowed - can't be
bothered to look it up right now), so I wouldn't do that if
there was any way around it.
<xsl:template name="calculate-level">
<xsl:value-of select="count(ancestor::*)-1"/>
</xsl:template>
Bad idea. Instead of tinkering with the total count, modify
the XPath expression so that it returns a nodeset
consisting solely of the nodes that you actually want to
count:
1+count(ancestor::Component)
<xsl:template name="calculate-number">
<xsl:variable name="level">
<xsl:call-template name="calculate-level"/>
</xsl:variable>
<xsl:value-of select="1 +
count(//*[count(ancestor::*)-1 <
$level]) + count(preceding::*[count(ancestor::*)-1 =
$level])"/> </xsl:template>
Same here.
<xsl:template name="top-level-component" match="/">
Generally bad idea, unless you have a very good reason to do
this.
<xsl:for-each select="$treeDoc//PRODUCT_TREE">
for-each? $treeDoc?
<xsl:if test="Component">
<Component>
<xsl:attribute name="mncl"><xsl:call-template
name="calculate-level"/></xsl:attribute>
<xsl:attribute name="mncn"><xsl:call-template
name="calculate-number"/></xsl:attribute>
Wrong. The current node is in the nodeset resulting from
evaluating the XPath expression in for-each. <xsl:if> does
not affect the current node. So you're creating a Component
element, then invoke the named templates meant to calculate
the level and number in context of PRODUCT_TREE element.
<xsl:if test="Component">
<xsl:call-template name="component"/>
</xsl:if>
You haven't defined a component named template, though...
</Component>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="/">
<xsl:call-template name="top-level-component"/>
</xsl:template>
This whole idea is wrong. That's what identity
transformation is for (google it, it's THE ultimate
essential technique in XSLT).
My main problem here might be, that I can't put "$treeDoc"
in the match-tag of a template.
*shrug* What is $treeDoc anyway? You seem to be using it,
you're talking about, but haven't defined it anywhere.
Therefore I have one template for the top-level-component
which calls an analog template "component" that then
handles all following nodes. Maybe you can give me a hint
here, for I really doubt that this is a good way to go.
Why do you want to process top Component element
differently, anyway?
And the result looks like:
<top>
<product>
<Component level="1" number="1">
<Component level="2" number="2">
<Component level="3" number="2">
<Component level="4" number="4"/>
</Component>
<Component level="3" number="3"/>
</Component>
<Component level="2" number="3">
<Component level="3" number="5"/>
</Component>
</Component>
</product>
</top>
Well, I cannot run your version of it. But everything works
just fine in my version:
pavel@debian:~/dev/xslt$ xmllint comp2.xml
<?xml version="1.0"?>
<top>
<product>
<Component>
<Component>
<Component>
<Component/>
</Component>
<Component/>
</Component>
<Component>
<Component/>
</Component>
</Component>
</product>
</top>
pavel@debian:~/dev/xslt$ xmllint comp2.xsl
<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="
http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl
utput method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Component">
<xsl:copy>
<xsl:attribute name="level">
<xsl:call-template name="calc-level"/>
</xsl:attribute>
<xsl:attribute name="number">
<xsl:call-template name="calc-number"/>
</xsl:attribute>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template name="calc-level">
<xsl:value-of select="1+count(ancestor::Component)"/>
</xsl:template>
<xsl:template name="calc-number">
<xsl:variable name="level">
<xsl:call-template name="calc-level"/>
</xsl:variable>
<xsl:value-of select=" 1 +count
( //Component
[1+count(ancestor::Component) < $level] )
+count ( preceding::Component
[1+count(ancestor::Component)=$level] ) "/>
</xsl:template>
</xsl:stylesheet>
pavel@debian:~/dev/xslt$ saxon -t comp2.xml comp2.xsl
Saxon 8.8J from Saxonica
Java version 1.5.0
Warning: at xsl:stylesheet on line 2 of
file:///var/www/dev/xslt/comp2.xsl:
Running an XSLT 1.0 stylesheet with an XSLT 2.0 processor
Stylesheet compilation time: 754 milliseconds
Processing file:/var/www/dev/xslt/comp2.xml
Building tree for file:/var/www/dev/xslt/comp2.xml using
class net.sf.saxon.tinytree.TinyBuilder
Tree built in 10 milliseconds
Tree size: 25 nodes, 0 characters, 0 attributes
<?xml version="1.0" encoding="UTF-8"?>
<top>
<product>
<Component level="1" number="1">
<Component level="2" number="2">
<Component level="3" number="4">
<Component level="4" number="7"/>
</Component>
<Component level="3" number="5"/>
</Component>
<Component level="2" number="3">
<Component level="3" number="6"/>
</Component>
</Component>
</product>
</top>Execution time: 145 milliseconds
Memory used: 14512128
NamePool contents: 20 entries in 19 chains. 7 prefixes, 8
URIs
pavel@debian:~/dev/xslt$