Recker Recker - 4 months ago 9
Perl Question

exsl:document in xsl:if block

Here is a toned down version of my use case.

1) I have a transformation xsl file which is as follows

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xalan="http://xml.apache.org/xslt"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" media-type="text/xml"/>

<xsl:param name="isfile"/>

<xsl:variable name="dotransformation">
<xsl:choose>
<xsl:when test="$isfile = 'true'">
<xsl:value-of select="true()"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="false()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>

<xsl:template match="/">
<xsl:if test="$dotransformation = true()">
<exsl:document href = "outputfile1.xml" method="xml" version="1.0" encoding="UTF-8" indent="yes">
Article:- <xsl:value-of select="/Article/Title"/>
Authors:- <xsl:apply-templates select="/Article/Authors/Author"/>
</exsl:document>
</xsl:if>
</xsl:template>

<xsl:template match="Author">
<exsl:document href = "outputfile2.xml" method="xml" version="1.0" encoding="UTF-8" indent="yes">
always Generate this output!! <xsl:value-of select="." />
</exsl:document>
</xsl:template>
</xsl:stylesheet>


2) I have an example file which needs to transformed and output needs to generated to
output1.xml
and
output2.xml
depending on condition in the xsl file

<?xml version="1.0"?>
<?xml-stylesheet type="xsl" href="trans.xsl"?>
<Article>
<Title>My Article</Title>
<Authors>
<Author>Mr. Foo</Author>
<Author>Mr. Bar</Author>
</Authors>
<Body>This is my article text.</Body>
</Article>


3) Here is the perl script that I use for transformation

#!/usr/local/bin/perl -w

use strict;
use warnings;
use File::Path;
use File::Spec;
use File::Basename;
use XML::LibXSLT;
use XML::LibXML;

my $isfile;

my ($xmlfile,$xsltfile,$samplefile) = qw/ Example.xml trans.xsl sample.xml/;

if(-f $samplefile)
{
$isfile = "true";
print "File is present\n";
}
else
{
$isfile = "false";
print "File is absent\n";
}

my %args = ( "isfile" => $isfile );
my $xslt = XML::LibXSLT->new;
my $stylesheet = $xslt->parse_stylesheet_file($xsltfile);
my $results =
$stylesheet->transform_file($xmlfile,XML::LibXSLT::xpath_to_string(%{args}));
0;


From my perl script, I am supplying a parameter named
$isfile
which checks if certain other file
sample.xml
is available in the directory and sets its value accordingly.

I receive that parameter my xsl transformation template file and I create a new variable
dotransformation
out of it.

I need to generate
output1.xml
only when
$dotransformation
has a true value otherwise it should generate
output2.xml
.

However, even when
sample.xml
is not present in the directory,
exsl:document
is generating both
output1.xml
and
output2.xml
instead of just
output2.xml
.

Why is this happening? Does
exsl:document
not work with
xsl:if
?

Answer

The main problem here is that you're defining dotransformation as a result tree fragment and not a boolean value. Only an empty fragment is false, so your test $dotransformation = true() is always true

You have a few options. The most obvious is to put a real boolean value into dotransformation like this

<xsl:variable name="dotransformation" select="$isfile = 'true'" />

then your existing test will work, or you may say just

<xsl:if test="$dotransformation">

Alternatively, of course, you may write simply

<xsl:if test="$isfile = 'true'">

and forget about the intermediate variable

Another issue is that the match="Author" template is executed only because you have

<xsl:apply-templates select="/Article/Authors/Author" />

within the conditional section. If that section is disabled then there is nothing to cause anything beneath the root node to be processed and, as it stands, neither file will be generated

The solution is to put a simple recursion template in there that will cause the processor to follow through all the layers of elements

<xsl:template match="*">
    <xsl:apply-templates select="*" />
</xsl:template>