Discussion:
XSL transformation with Ant: sorting a list
Al Le
2016-03-07 06:37:14 UTC
Permalink
Hello,

I'm facing a weird problem (IMHO) which, in short, is:

a node list passed as a parameter to a template can't be sorted.

The problem occurs only if I do the transformation from within Ant (I use Ant 1.8.4). It does not occur if I perform it via a Java program or in XmlSpy or through http://xsltransform.net.

Here's an example.

The input file (a.xml) is:

<root>
<a>BBB</a>
<a>AAA</a>
</root>

The transformation (trans.xml) is:

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

<xsl:output method="xml" />

<xsl:template match="/">
<Root>
<xsl:call-template name="processThis">
<xsl:with-param name="nodeList" select="/*/a"/>
</xsl:call-template>
</Root>
</xsl:template>

<xsl:template name="processThis">
<xsl:param name="nodeList" />

<xsl:for-each select="$nodeList">
<xsl:sort /><!-- ***** This causes the problem -->
<xsl:variable name="thisVal" select="." />
<result value="{$thisVal}" />
</xsl:for-each>
</xsl:template>

</xsl:stylesheet>

The Ant script is:

<project default="trans">

<target name="trans">
<delete file="out.xml"/>
<xslt style="trans.xsl" in="a.xml" out="out.xml"/>
</target>

</project>


The expected output is:

<Root>
<result value="AAA" />
<result value="BBB" />
</Root>

But if I run the ant script, just an empty 'Root' element is generated, without child nodes.

If I comment out the line marked with '*****', the generated Root element does contain child elements, but unsorted (as one would expect in this case).

If I process the elements directly (and not in a template passing the list to process as a parameter), then I can use 'sort', and everything works as expected. Here is the 'direct' transformation:

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

<xsl:output method="xml" />

<xsl:template match="/">
<Root>
<xsl:for-each select="/*/a">
<xsl:sort />
<xsl:variable name="thisVal" select="." />
<result value="{$thisVal}" />
</xsl:for-each>
</Root>
</xsl:template>

</xsl:stylesheet>

So my question is: why isn't a list passed as a parameter to a template processed with a 'sort' option -- in Ant?

Thank you!
AL

---------------------------------------------------------------------
To unsubscribe, e-mail: user-***@ant.apache.org
For additional commands, e-mail: user-***@ant.apache.org
Al Le
2016-03-07 11:01:21 UTC
Permalink
> It does not occur if I perform it via a Java program

I have to correct myself. It tried a java program in different JVMs, and it gives me different results. In one case it gives the correct result, in other cases still the wrong result is delivered. I could not find out yet what the difference is.

But it's not necessarily related to Ant.

---------------------------------------------------------------------
To unsubscribe, e-mail: user-***@ant.apache.org
For additional commands, e-mail: user-***@ant.apache.org
Klaus Malorny
2016-03-07 13:25:08 UTC
Permalink
On 07.03.2016 12:01, Al Le wrote:
>> It does not occur if I perform it via a Java program
>
> I have to correct myself. It tried a java program in different JVMs, and it
> gives me different results. In one case it gives the correct result, in other
> cases still the wrong result is delivered. I could not find out yet what the
> difference is.
>

Hi,

a quick look into the lib directory of my ANT installation indicates that ANT
does not come with an own XSL/T implementation, but uses the one provided by the
JVM. So I would check whether the JVM is the latest available and/or whether
other included tasks may introduce another XSL/T implementation, which is then
used by default.

Klaus



---------------------------------------------------------------------
To unsubscribe, e-mail: user-***@ant.apache.org
For additional commands, e-mail: user-***@ant.apache.org
Scot P. Floess
2016-03-07 11:54:33 UTC
Permalink
So a few things - first you are killing yourself in the way you XSLT is
written. Personally, I'd do:

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

<xsl:output method="xml" />

<xsl:template match="/">
<Root>
<xsl:apply-templates select="a">
<xsl:sort select="a"/>
</xsl:apply-templates>
</Root>
</xsl:template>

<xsl:template name="a">
<result>
<xsl:attribute name="value">
<xsl:value-of select="."/>
</xsl:attribute>
</result>
</xsl:template>
</xsl:stylesheet>

The sort above may be wrong as I didn't test it - but you get the idea.

You are trying to do the work of the templating engine in your XSLT :)

See if this works and holler at me if you still can't get it working from
Ant...


On Mon, 7 Mar 2016, Al Le wrote:

> Hello,
>
> I'm facing a weird problem (IMHO) which, in short, is:
>
> a node list passed as a parameter to a template can't be sorted.
>
> The problem occurs only if I do the transformation from within Ant (I use Ant 1.8.4). It does not occur if I perform it via a Java program or in XmlSpy or through http://xsltransform.net.
>
> Here's an example.
>
> The input file (a.xml) is:
>
> <root>
> <a>BBB</a>
> <a>AAA</a>
> </root>
>
> The transformation (trans.xml) is:
>
> <xsl:stylesheet version="1.0"
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
>
> <xsl:output method="xml" />
>
> <xsl:template match="/">
> <Root>
> <xsl:call-template name="processThis">
> <xsl:with-param name="nodeList" select="/*/a"/>
> </xsl:call-template>
> </Root>
> </xsl:template>
>
> <xsl:template name="processThis">
> <xsl:param name="nodeList" />
>
> <xsl:for-each select="$nodeList">
> <xsl:sort /><!-- ***** This causes the problem -->
> <xsl:variable name="thisVal" select="." />
> <result value="{$thisVal}" />
> </xsl:for-each>
> </xsl:template>
>
> </xsl:stylesheet>
>
> The Ant script is:
>
> <project default="trans">
>
> <target name="trans">
> <delete file="out.xml"/>
> <xslt style="trans.xsl" in="a.xml" out="out.xml"/>
> </target>
>
> </project>
>
>
> The expected output is:
>
> <Root>
> <result value="AAA" />
> <result value="BBB" />
> </Root>
>
> But if I run the ant script, just an empty 'Root' element is generated, without child nodes.
>
> If I comment out the line marked with '*****', the generated Root element does contain child elements, but unsorted (as one would expect in this case).
>
> If I process the elements directly (and not in a template passing the list to process as a parameter), then I can use 'sort', and everything works as expected. Here is the 'direct' transformation:
>
> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
>
> <xsl:output method="xml" />
>
> <xsl:template match="/">
> <Root>
> <xsl:for-each select="/*/a">
> <xsl:sort />
> <xsl:variable name="thisVal" select="." />
> <result value="{$thisVal}" />
> </xsl:for-each>
> </Root>
> </xsl:template>
>
> </xsl:stylesheet>
>
> So my question is: why isn't a list passed as a parameter to a template processed with a 'sort' option -- in Ant?
>
> Thank you!
> AL
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-***@ant.apache.org
> For additional commands, e-mail: user-***@ant.apache.org
>
>

Scot P. Floess RHCT (Certificate Number 605010084735240)
Chief Architect FlossWare http://sourceforge.net/projects/flossware
http://flossware.sourceforge.net
https://github.com/organizations/FlossWare

---------------------------------------------------------------------
To unsubscribe, e-mail: user-***@ant.apache.org
For additional commands, e-mail: user-***@ant.apache.org
Al Le
2016-03-07 12:56:55 UTC
Permalink
Hello Scot,

thanks for a quick response!

> first you are killing yourself in the way you XSLT is
> written
> [. . .]
> You are trying to do the work of the templating engine in your XSLT :)

Yes, I know this is a "procedural" way of doing things and maybe not the best. But the example is just an example. The real script is much bigger and more complicated. I just tried to give a simple case to reproduce the problem.

Do you also think that it should work (despite the fact that it's may be not the best way to do it)?

The java program I used to verify the transformation is:

package my.test;

import java.io.File;
import java.io.StringWriter;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

public class Transform {

public static void main(String[] args) throws Exception {
String inputFileName = "Q:\\MiscThings\\t\\a.xml";
String xslFileName = "Q:\\MiscThings\\t\\trans.xsl";

Source xmlSource = new StreamSource(new File(inputFileName));
Source xslSource = new StreamSource(new File(xslFileName));

StringWriter stringWriter = new StringWriter();
Result transformationResult = new StreamResult(stringWriter);

TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer(xslSource);
transformer.transform(xmlSource, transformationResult);

stringWriter.flush();
String xmlResult = stringWriter.toString();

System.out.println(xmlResult);
}

}

---------------------------------------------------------------------
To unsubscribe, e-mail: user-***@ant.apache.org
For additional commands, e-mail: user-***@ant.apache.org
s***@nc.rr.com
2016-03-07 13:54:57 UTC
Permalink
Al,

It wasn't apparent to me why there'd be a difference...

If you are using the same JVM and simply executing the XSL differently, I don't see why not...

I mean once you kick of the XSL I can't imagine there is something different in running from Ant vs your Java app. I spent a number of years on an ESB team doing mostly XSLTs (and XSDs) - I always used Ant to test even though we ran the XSLTs in our environments from Java. I never noticed any difference that way at all.


---- Al Le <***@gmx.de> wrote:
> Hello Scot,
>
> thanks for a quick response!
>
> > first you are killing yourself in the way you XSLT is
> > written
> > [. . .]
> > You are trying to do the work of the templating engine in your XSLT :)
>
> Yes, I know this is a "procedural" way of doing things and maybe not the best. But the example is just an example. The real script is much bigger and more complicated. I just tried to give a simple case to reproduce the problem.
>
> Do you also think that it should work (despite the fact that it's may be not the best way to do it)?
>
> The java program I used to verify the transformation is:
>
> package my.test;
>
> import java.io.File;
> import java.io.StringWriter;
>
> import javax.xml.transform.Result;
> import javax.xml.transform.Source;
> import javax.xml.transform.Transformer;
> import javax.xml.transform.TransformerFactory;
> import javax.xml.transform.stream.StreamResult;
> import javax.xml.transform.stream.StreamSource;
>
> public class Transform {
>
> public static void main(String[] args) throws Exception {
> String inputFileName = "Q:\\MiscThings\\t\\a.xml";
> String xslFileName = "Q:\\MiscThings\\t\\trans.xsl";
>
> Source xmlSource = new StreamSource(new File(inputFileName));
> Source xslSource = new StreamSource(new File(xslFileName));
>
> StringWriter stringWriter = new StringWriter();
> Result transformationResult = new StreamResult(stringWriter);
>
> TransformerFactory transformerFactory = TransformerFactory.newInstance();
> Transformer transformer = transformerFactory.newTransformer(xslSource);
> transformer.transform(xmlSource, transformationResult);
>
> stringWriter.flush();
> String xmlResult = stringWriter.toString();
>
> System.out.println(xmlResult);
> }
>
> }
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-***@ant.apache.org
> For additional commands, e-mail: user-***@ant.apache.org
>


---------------------------------------------------------------------
To unsubscribe, e-mail: user-***@ant.apache.org
For additional commands, e-mail: user-***@ant.apache.org
Earl Hood
2016-03-07 17:18:28 UTC
Permalink
On Mar 7, 2016 7:55 AM, <***@nc.rr.com> wrote:
>
> If you are using the same JVM and simply executing the XSL differently, I
don't see why not...

If the classpath is not identical, you could get a different transform
provider. For example, we use Saxon as our provider, overriding what is
provided in the runtime library.

Wrt Ant, we put Saxon in its lib path so we know it will get used since we
have other programs outside of Ant invocation context that use Saxon.
Puting it in the lib path avoids the need to explicitly designate the
provider in the xslt task.

--ewh
Al Le
2016-03-07 22:00:41 UTC
Permalink
> If the classpath is not identical, you could get a different transform
> provider. For example, we use Saxon as our provider, overriding what is
> provided in the runtime library.


Thank you for the hint! I downloaded the latest xalan distribution and
executed the ant script with the "classpath" attribute pointing to xalan.

And it worked! I naively assumed that a modern Java distributions (Java
8) include an xslt processor good enough to carry out this simple
transformation correctly. But it's apparently not the case.

So, when in doubt, specify the xslt processor explicitly and do not rely
on the one contained in the JDK!

Thank you all who has responded! Now the world is half sane again (only
half because JDK contains a flawed xslt processor).

---------------------------------------------------------------------
To unsubscribe, e-mail: user-***@ant.apache.org
For additional commands, e-mail: user-***@ant.apache.org
Loading...