-
Bug
-
Resolution: Fixed
-
P3
-
9
-
None
-
b153
XSL transformations are by default namespace aware, as are XPath expressions.
However, default DOM or SAX parsers are not configured to be namespace aware.When an XPath Expression used in an XSL is selecting elements without namespaces it expects them to be in the default namespace. Reading XML input with namespace unaware parsers should place all elements regardless of the namespace used into the default namespace and hence XPath expressions selecting in the default namespace should find them. This seems to work with DOM Input sources but it fails with SAX input.
This test shows the issue:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
public class DOMSAXTestcase {
public static void main(String[] args)
throws TransformerFactoryConfigurationError,
TransformerException,
SAXException,
IOException,
ParserConfigurationException
{
final String LINE_SEPARATOR = System.getProperty("line.separator");
final String xsl =
"<?xml version=\"1.0\"?>" + LINE_SEPARATOR +
"<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">" + LINE_SEPARATOR +
" <xsl:template match=\"/\">" + LINE_SEPARATOR +
" <xsl:variable name=\"Counter\" select=\"count(//row)\"/>" + LINE_SEPARATOR +
" <Counter><xsl:value-of select=\"$Counter\"/></Counter>" + LINE_SEPARATOR +
" </xsl:template>" + LINE_SEPARATOR +
"</xsl:stylesheet>" + LINE_SEPARATOR;
final String sourceXml =
"<?xml version=\"1.0\"?>" + LINE_SEPARATOR +
"<envelope xmlns=\"http://www.sap.com/myns\">" + LINE_SEPARATOR +
" <row>1</row>" + LINE_SEPARATOR +
" <row>2</row>" + LINE_SEPARATOR +
" <row>3</row>" + LINE_SEPARATOR +
"</envelope>" + LINE_SEPARATOR;
System.out.println("Stylesheet:");
System.out.println("===========================================");
System.out.println(xsl);
System.out.println();
System.out.println("Source before transformation:");
System.out.println("===========================================");
System.out.println(sourceXml);
System.out.println();
// create transformer and resources
Transformer t = TransformerFactory.newInstance().newTransformer(new StreamSource(new ByteArrayInputStream(xsl.getBytes())));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// transform from DOM source
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().
parse(new InputSource(new ByteArrayInputStream(sourceXml.getBytes())));
t.transform(new DOMSource(doc), new StreamResult(baos));
String resFromDOM = baos.toString();
baos.reset();
// transform from SAX source
XMLReader xmlr = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
t.transform(new SAXSource(xmlr, new InputSource(new ByteArrayInputStream(sourceXml.getBytes()))),
new StreamResult(baos));
String resFromSAX = baos.toString();
System.out.println("Result after transformation from DOMSource:");
System.out.println("===========================================");
System.out.println(resFromDOM);
System.out.println();
System.out.println("Result after transformation from SAXSource:");
System.out.println("===========================================");
System.out.println(resFromSAX);
System.out.println();
if (!resFromDOM.contains("3"))
System.out.println("Error: Output from DOM should contain number 3");
if (!resFromSAX.contains("3"))
System.out.println("Error: Output from SAX should contain number 3");
}
}
Current result:
Stylesheet:
===========================================
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:variable name="Counter" select="count(//row)"/>
<Counter><xsl:value-of select="$Counter"/></Counter>
</xsl:template>
</xsl:stylesheet>
Source before transformation:
===========================================
<?xml version="1.0"?>
<envelope xmlns="http://www.sap.com/myns">
<row>1</row>
<row>2</row>
<row>3</row>
</envelope>
Result after transformation from DOMSource:
===========================================
<?xml version="1.0" encoding="UTF-8"?><Counter>3</Counter>
Result after transformation from SAXSource:
===========================================
<?xml version="1.0" encoding="UTF-8"?><Counter>0</Counter>
Error: Output from SAX should contain number 3
The resulting counter should be 3, not 0.
However, default DOM or SAX parsers are not configured to be namespace aware.When an XPath Expression used in an XSL is selecting elements without namespaces it expects them to be in the default namespace. Reading XML input with namespace unaware parsers should place all elements regardless of the namespace used into the default namespace and hence XPath expressions selecting in the default namespace should find them. This seems to work with DOM Input sources but it fails with SAX input.
This test shows the issue:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
public class DOMSAXTestcase {
public static void main(String[] args)
throws TransformerFactoryConfigurationError,
TransformerException,
SAXException,
IOException,
ParserConfigurationException
{
final String LINE_SEPARATOR = System.getProperty("line.separator");
final String xsl =
"<?xml version=\"1.0\"?>" + LINE_SEPARATOR +
"<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">" + LINE_SEPARATOR +
" <xsl:template match=\"/\">" + LINE_SEPARATOR +
" <xsl:variable name=\"Counter\" select=\"count(//row)\"/>" + LINE_SEPARATOR +
" <Counter><xsl:value-of select=\"$Counter\"/></Counter>" + LINE_SEPARATOR +
" </xsl:template>" + LINE_SEPARATOR +
"</xsl:stylesheet>" + LINE_SEPARATOR;
final String sourceXml =
"<?xml version=\"1.0\"?>" + LINE_SEPARATOR +
"<envelope xmlns=\"http://www.sap.com/myns\">" + LINE_SEPARATOR +
" <row>1</row>" + LINE_SEPARATOR +
" <row>2</row>" + LINE_SEPARATOR +
" <row>3</row>" + LINE_SEPARATOR +
"</envelope>" + LINE_SEPARATOR;
System.out.println("Stylesheet:");
System.out.println("===========================================");
System.out.println(xsl);
System.out.println();
System.out.println("Source before transformation:");
System.out.println("===========================================");
System.out.println(sourceXml);
System.out.println();
// create transformer and resources
Transformer t = TransformerFactory.newInstance().newTransformer(new StreamSource(new ByteArrayInputStream(xsl.getBytes())));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// transform from DOM source
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().
parse(new InputSource(new ByteArrayInputStream(sourceXml.getBytes())));
t.transform(new DOMSource(doc), new StreamResult(baos));
String resFromDOM = baos.toString();
baos.reset();
// transform from SAX source
XMLReader xmlr = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
t.transform(new SAXSource(xmlr, new InputSource(new ByteArrayInputStream(sourceXml.getBytes()))),
new StreamResult(baos));
String resFromSAX = baos.toString();
System.out.println("Result after transformation from DOMSource:");
System.out.println("===========================================");
System.out.println(resFromDOM);
System.out.println();
System.out.println("Result after transformation from SAXSource:");
System.out.println("===========================================");
System.out.println(resFromSAX);
System.out.println();
if (!resFromDOM.contains("3"))
System.out.println("Error: Output from DOM should contain number 3");
if (!resFromSAX.contains("3"))
System.out.println("Error: Output from SAX should contain number 3");
}
}
Current result:
Stylesheet:
===========================================
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:variable name="Counter" select="count(//row)"/>
<Counter><xsl:value-of select="$Counter"/></Counter>
</xsl:template>
</xsl:stylesheet>
Source before transformation:
===========================================
<?xml version="1.0"?>
<envelope xmlns="http://www.sap.com/myns">
<row>1</row>
<row>2</row>
<row>3</row>
</envelope>
Result after transformation from DOMSource:
===========================================
<?xml version="1.0" encoding="UTF-8"?><Counter>3</Counter>
Result after transformation from SAXSource:
===========================================
<?xml version="1.0" encoding="UTF-8"?><Counter>0</Counter>
Error: Output from SAX should contain number 3
The resulting counter should be 3, not 0.