XML transformation with DOMResult

10,399

Solution 1

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.

Solution 2

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.

Share:
10,399

Related videos on Youtube

Admin
Author by

Admin

Updated on September 14, 2022

Comments

  • Admin
    Admin over 1 year

    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!)