Help! 'dummy.xsl' ?

S

Simon Brooke

As various people will have noticed, I've been having a lot of trouble with
XSL lately. Brief history: I wrote myself an XML toolkit back in 2000, and
it worked well enough for me, so it's been little changed since. However,
it works only with an obsolete version of Saxon (6.2.2 I think), and it
has a number of small bugs; and I've at last got to the point where I need
to fix it. And I'm finding it, frankly, absurdly frustrating and
difficult.

But what's frustrating me at this moment is something absurd and weird.
Some weeks ago I did a test with a dummy XSL file called 'dummy.xsl'. Now,
whenever I test with modern Xalan2, I'm persistently getting an error
message:

/home/simon/tmp/test/dummy.xsl; Line #0; Column #0; stylesheet requires
attribute: version

I am really, really not referring to a file called 'dummy.xsl'. I have
grepped through every single file in my working set, and nothing - really
nothing at all - contains the text 'dummy.xsl'. Also, the stylesheet I am
using, really does have a version attribute - see below.

I do not get this message when I'm using my obsolete version of Saxon (and,
indeed, all my transforms work with my obsolete Saxon). So I guessed that
Xalan might use a cache somewhere on my hard disk that I don't know about.
I copied my working files - all three of them, stripping my test down as
far as I could - to my laptop, which should be virgin.

When I run the test, on the laptop, using Xalan2, using GCJ as the Java
implementation I get the 'stylesheet requires attribute: version' error,
but no reference to dummy.xsl. But if I use IBM's Java, I get exactly the
same error message as I get on my development machine - *INCLUDING* the
reference to dummy.xsl!

So I now completely fail to understand where my problem is coming from. I
include my three files below, so that anyone who has the time and patience
can verify my problem and suggest solutions (hopefully not including
either pistols at dawn or a vial of cyanide)

,----[ /home/simon/tmp/xsltest/testharness.sh ]
#!/bin/bash

# XSLPROC=/usr/share/java/xalan2.jar
XSLPROC=/usr/local/lib/java/saxon.jar

export CLASSPATH=".:$XSLPROC"

javac TransformerTestHarness.java


java TransformerTestHarness \
-d org.apache.xerces.dom.DOMImplementationImpl -s test.xsl
`----

,----[ /home/simon/tmp/xsltest/test.xsl ]
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

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

</xsl:stylesheet>
`----

,----[ /home/simon/tmp/xsltest/TransformerTestHarness.java ]
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;

import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import org.xml.sax.InputSource;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io_OutputStream;
import java.io.StringReader;

import java.text.DateFormat;

import java.util.Date;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;


/**
* Test XSL transformations
*/
public class TransformerTestHarness
{
//~ Static fields/initializers ------------------------------------------

/** A string with parsable content */
public static final String PARSETHIS =
"<parsable><p>Parse me</p></parsable>";

//~ Instance fields -----------------------------------------------------

/** the DOM Implementation I will use */
public DOMImplementation rebus = null;

/** the XSL stylesheet (transform) I will use */
public File stylesheet;

/** DOCUMENT ME! */
public String label = "Transformer test harness";

/**
* A directory into which to write output files - if null, use standard
* out
*/
protected File baseDir = null;

/** A factory class for XSL transformers; */
protected TransformerFactory transformerFactory = null;

//~ Constructors --------------------------------------------------------

/**
* Construct a new test harness
*/
public TransformerTestHarness( )
{
super( );

try
{
transformerFactory = TransformerFactory.newInstance( );
}
catch ( Exception d )
{
System.err.println( "Could not instantiate transformer: " +
d.getMessage( ) );
System.exit( 4 );
}
}

//~ Methods -------------------------------------------------------------

/**
* Generate a document
*
* @return the document
*/
public Document generate( )
{
Document doc = rebus.createDocument( "", "root", null );
Element root = doc.getDocumentElement( );
Element generated = doc.createElement( "generated" );
root.appendChild( generated );

DateFormat df = DateFormat.getDateTimeInstance( );

generated.appendChild( doc.createTextNode( df.format( new
Date( ) ) ) );

try
{
root.appendChild( maybeParse( doc, PARSETHIS ) );
}
catch ( Exception any )
{
System.err.println( "Failed to parse: " + any.getMessage( ) );
}

return doc;
}

/**
* @param args
*/
public static void main( String[] args ) throws Exception
{
TransformerTestHarness tth = new TransformerTestHarness( );

for ( int i = 0; i < args.length; i++ )
{
if ( args.startsWith( "-" ) && ( args.length( ) > 1 ) )
{
switch ( args.charAt( 1 ) )
{
case 'b':
tth.baseDir = new File( args[++i] );

if ( tth.baseDir.exists( ) &&
tth.baseDir.canWrite( ) &&
tth.baseDir.isDirectory( ) )
{
System.err.println( "Using base directory " +
tth.baseDir.getCanonicalPath( ) );
}
else
{
System.err.println( "Bad base directory: " +
args );
}

break;

case 'd':

try
{
tth.rebus =
(DOMImplementation) Class.forName( args[++i] )
.newInstance( );
System.err.println(
"Using DOM implementation of class " +
tth.rebus.getClass( ).getName( ) );
}
catch ( Exception any )
{
System.err.println( "Could not find DOM " +
"implementation " + args );
System.err.println( any.getMessage( ) );
System.exit( 2 );
}

break;

case 's':
tth.stylesheet = new File( args[++i] );

if ( tth.stylesheet.exists( ) &&
tth.stylesheet.canRead( ) )
{
System.err.println( "Using XSL stylesheet " +
tth.stylesheet.getCanonicalPath( ) );
}
else
{
System.err.println( "Can't read stylesheet " +
args );
System.exit( 1 );
}

break;

default:
System.err.println( "Unrecognised arg " + args );
System.exit( 3 );

break;
}
}
else
{
System.err.println( "Unrecognised arg " + args );
System.exit( 3 );

break;
}
}

tth.test( );
}

/**
* Get a suitable output stream - if I have a base directory, a file in
* that directory with this name; else the standard out
*
* @param name a name ofr my file if any
*
* @return an output stream
*
* @throws Exception unlikely
*/
public OutputStream getOutputStream( String name )
throws Exception
{
OutputStream out = System.out;

if ( ( baseDir != null ) && baseDir.exists( ) &&
baseDir.canWrite( ) && baseDir.isDirectory( ) )
{
out = new FileOutputStream( new File( baseDir, name ) );
}

return out;
}


/**
* Run the tests
*/
public void test( )
{
Document generated = generate( );
System.out.println( label );

try
{
System.out.println( "Printer test -> justprint" );
justPrint( generated, "justprint" );

if ( stylesheet != null )
{
DocumentBuilder p =
DocumentBuilderFactory.newInstance( ).newDocumentBuilder( );
Document xslDocument =
p.parse( new InputSource( new FileInputStream( stylesheet ) ) );

System.out.println( "Verify stylesheet -> transform.xsl");
justPrint( xslDocument, "transform.xsl");

System.out.println( "DOM to DOM test -> dom2dom" );
domToDom( generated, xslDocument, "dom2dom" );

System.out.println( "DOM to Stream test -> dom2stream" );
domToDom( generated, xslDocument, "dom2stream" );
}
else
{
System.err.println( "No stylesheet?");
}
}
catch ( Exception e )
{
System.err.println( "Whilst running print test:" );
e.printStackTrace( );
}
}

/**
* Transform from DOM object to DOM object; seralize after
*
* @param doc the document transformed
* @param name the name for printing
*/
protected void domToDom( Document doc, Document xslDocument, String
name )
{
try
{
if ( stylesheet != null )
{
DOMSource domSource = new DOMSource( doc );
DOMResult domResult = new DOMResult( );

transformerFactory.newTransformer( new DOMSource( xslDocument ) )
.transform( domSource, domResult );

Node root = domResult.getNode( );

if ( root instanceof Document )
{
justPrint( (Document) root, name );
}
else
{
System.err.println( "DOM to DOM transform returned " +
root );
}
}
}
catch ( Exception e )
{
System.err.println( "DOM to DOM failed: " + e.getMessage( ) );
e.printStackTrace( );
}
}

/**
* Transform from DOM object to output stream directly
*
* @param doc the document transformed
* @param transform the xsl transform to apply
* @param name the name for printing
*/
protected void domToStream( Document doc, Document transform, String
name )
{
try
{
if ( stylesheet != null )
{
DOMSource domSource = new DOMSource( doc );
StreamResult result =
new StreamResult( getOutputStream( name ) );

transformerFactory.newTransformer( new DOMSource( transform ) )
.transform( domSource, result );
}
}
catch ( Exception e )
{
System.err.println( "DOM to DOM failed: " + e.getMessage( ) );
e.printStackTrace( );
}
}

/**
* Just print the document
*
* @param doc the document to print
* @param name the name of the file to print to
*
* @throws Exception DOCUMENT ME!
*/
protected void justPrint( Document doc, String name )
throws Exception
{
XMLSerializer dickens =
new XMLSerializer( getOutputStream( name ),
new OutputFormat( doc, null, true ) );
dickens.serialize( doc );
}

/**
* Construct a node representing this value. It's perfectly possible (and
* possibly legitimate) that the value of a child should contain embedded
* markup. If so, try to parse a node out of it.
*
* @param doc the document in which the node is to be created
* @param unparsed the string, possibly with embedded markup, to parse
*
* @exception GenerationException if parsing fails
*/
protected Node maybeParse( Document doc, String unparsed )
throws Exception
{
Node val = doc.createTextNode( unparsed ); // safe default

if ( unparsed != null ) // defensive
{
if ( unparsed.indexOf( "<" ) > -1 ) // it looks like markup
{
if ( !unparsed.trim( ).startsWith( "<" ) )
{
// nasty: if it contains markup, but
// isn't contained in markup, the
// parser will barf.
unparsed = "<parsed>" + unparsed + "</parsed>";
}

try
{
DocumentBuilder parser =
DocumentBuilderFactory.newInstance( )
.newDocumentBuilder( );

if ( parser == null )
{
System.err.println( "Could not initialise XML parser" );
}

InputSource i =
new InputSource( new StringReader( unparsed ) );

Document parsed = parser.parse( i );

if ( parsed != null )
{
Node root = parsed.getDocumentElement( );

val = doc.importNode( root, true );
}
}
catch ( Exception e )
{
System.err.println( "Could not parse '" + unparsed +
"'as XML" );
e.printStackTrace( System.err );
}
}
}

return val;
}
}
`----

,----[ Sample output with Saxon (i.e. what I think you should get) ]
Using DOM implementation of class
org.apache.xerces.dom.DOMImplementationImpl
Using XSL stylesheet /home/simon/tmp/xsltest/test.xsl
Transformer test harness
Printer test -> justprint
<?xml version="1.0"?>
<root>
<generated>18-Mar-2007 14:33:26</generated>
<parsable>
<p>Parse me</p>
</parsable>
</root>
Verify stylesheet -> transform.xsl
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<test>
<xsl:apply-templates/>
</test>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
DOM to DOM test -> dom2dom
<?xml version="1.0"?>
<test>
<root>
<generated>18-Mar-2007 14:33:26</generated>
<parsable>
<p>Parse me</p>
</parsable>
</root>
</test>
DOM to Stream test -> dom2stream
<?xml version="1.0"?>
<test>
<root>
<generated>18-Mar-2007 14:33:26</generated>
<parsable>
<p>Parse me</p>
</parsable>
</root>
</test>

,----[ Sample output with Xalan2 ]
Using DOM implementation of class
org.apache.xerces.dom.DOMImplementationImpl
Using XSL stylesheet /home/simon/tmp/xsltest/test.xsl
Transformer test harness
Printer test -> justprint
<?xml version="1.0"?>
<root>
<generated>18-Mar-2007 14:34:50</generated>
<parsable>
<p>Parse me</p>
</parsable>
</root>
Verify stylesheet -> transform.xsl
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<test>
<xsl:apply-templates/>
</test>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
DOM to DOM test -> dom2dom
/home/simon/tmp/xsltest/dummy.xsl; Line #0; Column #0; stylesheet requires
attribute: version
file:///home/simon/tmp/xsltest/dummy.xsl; Line #0; Column #0;
java.util.EmptyStackException
DOM to Stream test -> dom2stream
/home/simon/tmp/xsltest/dummy.xsl; Line #0; Column #0; stylesheet requires
attribute: version
file:///home/simon/tmp/xsltest/dummy.xsl; Line #0; Column #0;
java.util.EmptyStackException
 
M

Martin Honnen

S

Simon Brooke

Martin said:
I don't know whether that causes your problem but for namespace aware
processing
you should do e.g.
DocumentBuilderFactory docBuilderFactory =
DocumentBuilderFactory.newInstance();
docBuilderFactory.setNamespaceAware(true);
DocumentBuilder p = docBuilderFactory.newDocumentBuilder();

Thank you very much indeed!

You may not know what my problem was, but you certainly managed to solve
it! What a /bizarre/ error message for that problem!
 
D

David Carlisle

Simon said:
it! What a /bizarre/ error message for that problem!

not entirely bizarre, the top level element of an xsl stylesheet can be
any element in any namespace (because of the so called literal result
element as stylesheet syntax) however in that case there has to be an
xsl:version attribute on the LRE (basically so that a processor can trap
the case of a file which isn't an xsl file at all being passed in as xsl
code) so if there's an error in specifying the namespace, the
xsl:stylesheet is just some element in an unknown mamepsace, so the
system looks for an xsl:version attribute....


David
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,539
Members
45,024
Latest member
ARDU_PROgrammER

Latest Threads

Top