user2383349
user2383349

Reputation:

XML transformation with DOMResult

I'm getting java.lang.NullPointerException when I uncomment a line in the following code:

private static Document XSLT(String name) throws Exception{
    File xsl = new File("data/" + name + ".xsl");
    File xml = new File("data/" + name + ".xml");
    DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    Document document = db.newDocument();
    DOMSource input = new DOMSource(db.parse(xml));
    StreamResult output = new StreamResult(System.out); //That works but its not what I want!
    //DOMResult output = new DOMResult(document); //that gives the null pointer exception
    TransformerFactory.newInstance().newTransformer(new StreamSource(xsl)).transform(input, output);
    return document;
}

My intention is to make a method like that to help me transform a XML file, using both XSLT and Java language. After all I should do all the transformations before saving it into a file.

How to get a Document out of that method?

I mean, I want to do this without saving the transformed document into a file to be able to load it, I want to do it just in the "memory".

Thank you :)

Update

Let me publish the exception so you can help me better.

Exception in thread "main" javax.xml.transform.TransformerException: java.lang.NullPointerException
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:736)
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:340)
        at test.Main.XSLT(Main.java:393)
        at test.Main.test(Main.java:342)
        at test.Main.main(Main.java:329)
Caused by: java.lang.NullPointerException
        at com.sun.org.apache.xml.internal.serializer.SerializerBase.patchName(SerializerBase.java:271)
        at com.sun.org.apache.xml.internal.serializer.SerializerBase.addAttribute(SerializerBase.java:429)
        at com.sun.org.apache.xml.internal.serializer.ToSAXHandler.addUniqueAttribute(ToSAXHandler.java:438)
        at xmlname.template$dot$0()
        at xmlname.applyTemplates()
        at xmlname.transform()
        at com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet.transform(AbstractTranslet.java:611)
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:729)
        ... 4 more
---------
java.lang.NullPointerException
        at com.sun.org.apache.xml.internal.serializer.SerializerBase.patchName(SerializerBase.java:271)
        at com.sun.org.apache.xml.internal.serializer.SerializerBase.addAttribute(SerializerBase.java:429)
        at com.sun.org.apache.xml.internal.serializer.ToSAXHandler.addUniqueAttribute(ToSAXHandler.java:438)
        at xmlname.template$dot$0()
        at xmlname.applyTemplates()
        at xmlname.transform()
        at com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet.transform(AbstractTranslet.java:611)
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:729)
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:340)
        at test.Main.XSLT(Main.java:393)
        at test.Main.test(Main.java:342)
        at test.Main.main(Main.java:329)

Update 2

Lets test with a common source.

test.xml

<?xml version="1.0" encoding="UTF-8"?>
<tests>
    <test>
        <text>Hi!</text>
    </test>
</tests>

test.xsl

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output 
        method="html"
        version="1.0" 
        encoding="utf-8" 
        indent="yes" 
        omit-xml-declaration="no"
        media-type="application/xml"
        doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 
        doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
    />

    <xsl:template match="/">
        <html xmlns="http://www.w3.org/1999/xhtml" lang="pt-BR" xml:lang="pt-BR">           
            <head>
                <meta charset="UTF-8" />
                <title>Test</title>
            </head>
            <body>
                <h1>Test</h1>                       
                <xsl:apply-templates/>
            </body>
        </html> 
    </xsl:template>

    <xsl:template match="/tests/test">
       <p><xsl:value-of select="text"/></p>
    </xsl:template>

</xsl:stylesheet>

Gives the following output using StreamResult.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html lang="pt-BR" xml:lang="pt-BR" xmlns="http://www.w3.org/1999/xhtml">
<head>
<META http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<h1>Test</h1>

<p>Hi!</p>

</body>
</html>

Solved

See my answer in the appropriate place (in the answers!)

Upvotes: 4

Views: 11965

Answers (3)

user2383349
user2383349

Reputation:

The XHTML inside the XSL file was right (XML compliant), but the output after the XSLT processing was not.

I looked the line (in the output of the XSLT proc):

<META http-equiv="Content-Type" content="text/html; charset=utf-8">

The meta was all uppercase, and the > should be />.

So I changed the line where we see the method from html:

<xsl:output 
    method="html"
    version="1.0" 
    encoding="utf-8" 
    indent="yes" 
    omit-xml-declaration="no"
    media-type="application/xml"
    doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
/>

To xml:

<xsl:output 
    method="xml"
    version="1.0" 
    encoding="utf-8" 
    indent="yes" 
    omit-xml-declaration="no"
    media-type="application/xml"
    doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
/>

Update

I was having problems with self-closing tags, then I had to change another thing for the output be real XHTML compliant for the browsers.

Changing the following line fix these issues:

    media-type="application/xhtml+xml"

So an empty div:

    <div/>

Will be written as:

    <div></div>

I tested it with the XSLT processor that came with the default JDK and it works.

Upvotes: 1

andyb
andyb

Reputation: 43823

I suspect the output of the transformation is not well-formed XML. I can get the same exception with the following code and input files.

XmlTransform.java

import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import javax.xml.transform.dom.*;
import java.io.*;
import org.w3c.dom.*;

public class XmlTransform {
    public static void main(String[] args) throws Exception {
        File xsl = new File("1.xsl");
        File xml = new File("1.xml");
        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document document = db.newDocument();
        DOMSource input = new DOMSource(db.parse(xml));

//        StreamResult output = new StreamResult(System.out); //That works but its not what I want!
        DOMResult output = new DOMResult(document); //that gives the null pointer exception
        TransformerFactory.newInstance().newTransformer(new StreamSource(xsl)).transform(input, output);

        System.out.println("getNode().getLocalName()=" + output.getNode().getLocalName());
        System.out.println("((Document)getNode()).getDocumentElement().getLocalName()=" + ((Document)output.getNode()).getDocumentElement().getLocalName());

        Node n = ((Document)output.getNode()).getDocumentElement();

        System.out.println("n.hasChildNodes()=" + n.hasChildNodes());
        System.out.println("Beatles=" + n.getChildNodes().getLength());
    }
}

1.xml

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl">
<xsl:output omit-xml-declaration="yes" indent="yes"/>

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

<xsl:template match="beatle">
  <xsl:value-of select="name/first"/>
</xsl:template>
</xsl:stylesheet>

1.xsl

<?xml version="1.0" encoding="UTF-8"?>
<beatles>
  <beatle>
    <name>
      <first>John</first>
      <last>Lennon</last>
    </name>
  </beatle>
  <beatle>
    <name>
      <first>Paul</first>
      <last>McCartney</last>
    </name>
  </beatle>
  <beatle>
    <name>
      <first>George</first>
      <last>Harrison</last>
    </name>
  </beatle>
  <beatle>
    <name>
      <first>Ringo</first>
      <last>Starr</last>
    </name>
  </beatle>
</beatles>

Compiling and running this, I get the following exception:

getNode().getLocalName()=null
    Exception in thread "main" java.lang.NullPointerException
    at XmlTransform.main(XmlTransform.java:27)

which isn't exactly the same as yours (see later!) but replacing the output System.out, I get

JohnPaulGeorgeRingo

as expected.

Now, the output isn't exactly XML so if you start to add elements to the XSLT, for example, lets wrap each name with a <name></name> with:

<name><xsl:value-of select="name/first"/></name>

and switch back to the DOMResult output this results in a different exception:

ERROR: 'HIERARCHY_REQUEST_ERR: An attempt was made to insert a node where it is not permitted. '
    Exception in thread "main" javax.xml.transform.TransformerException: org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR: An attempt was made to insert a node where it is not permitted.
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:736)

because the output is not a well-formed XML document. There must be only one root node in an XML document. So by replacing:

    <xsl:apply-templates select="//beatle" />

with:

    <names><xsl:apply-templates select="//beatle" /></names>

makes the output document well-formed and the terminal result should be:

getNode().getLocalName()=null
((Document)getNode()).getDocumentElement().getLocalName()=names
n.hasChildNodes()=true
Beatles=4

Hope this helps.

Upvotes: 1

Ravi K Thapliyal
Ravi K Thapliyal

Reputation: 51721

DOMResult output = new DOMResult();
TransformerFactory.newInstance().
                   newTransformer(new StreamSource(xsl)).
                   transform(input, output);
return (Document) output.getNode();

Reference:
DOMResult#getNode()

Get the node that will contain the result DOM tree. If no node was set via DOMResult(Node node), ... , then the node will be set by the transformation, and may be obtained from this method once the transformation is complete.

Upvotes: 5

Related Questions