DOMBuilder failure -- Cannot have more than one root on a DOM

C

Collin VanDyck

I've been using org.apache.xml.utils.DOMBuilder to build an
org.w3c.dom.Document object from a stream of SAX2 events in my application.

I encounter serious problems when I try and build the document using any
DOCTYPE preset.

My algorithm, should a DOCTYPE be needed in the final Document, is to

1. Create a DocumentBuilder from a DocumentFactory
2. Get the DOMImplementation from the DocumentBuilder
3. Ask the DOMImplementation to create a DocumentType object with some
presets.
4. Use that DocumentType to help create a new Document using the
DOMImplementation
5. Create a DOMBuilder on that Document, using the root Node of the
Document as the current Node so that any further events are built from
that node.

The problem I'm getting is that the DOMBuilder seems to think that I am
appending multiple elements to the root of the Document instead of the
root Node.

To illustrate this, I'm inserting some source that should be runnable
using standard J2SE 1.4.2 runtime libraries. This example will
illustrate my frustration.

Also, John Bollinger, I read your posts on DOCTYPEs, which helped to get
me to this point -- thanks.


The output from my program I get is:

Starting body element failed: Can't have more than one root on a DOM!
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html><head /></html>

But I believe it should be:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html><head /><body/></html>

Any ideas on this, anyone?

thanks,
Collin

----------starting source code-------------------------------


package run;

import java.io.BufferedWriter;
import java.io.StringWriter;
import java.io.Writer;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.xalan.templates.OutputProperties;
import org.apache.xml.utils.DOMBuilder;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.xml.sax.helpers.AttributesImpl;

/**
* Test of the DOMBuilder
*
* @author Collin VanDyck
*/
public class DOMBuilderTest {

public static void main(String[] args)
{
try
{
////////////////////////
// set up the dombuilder
////////////////////////

final DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();

factory.setValidating(false);
factory.setNamespaceAware(false);
factory.setExpandEntityReferences(false);
factory.setIgnoringComments(false);
factory.setIgnoringElementContentWhitespace(false);

final DocumentBuilder builder = factory.newDocumentBuilder();
final DOMImplementation domImplementation =
builder.getDOMImplementation();
final DocumentType documentType =
domImplementation.createDocumentType(
"html",
"-//W3C//DTD XHTML 1.0 Strict//EN",

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");

// this document is created with a root node already in place.
final Document document = domImplementation.createDocument(
"",
documentType.getName(),
documentType);
final Element documentElement = document.getDocumentElement();

// create the DOMBuilder with the current node to be the
document element.
final DOMBuilder domBuilder = new DOMBuilder(document,
documentElement);


////////////////////////
// add elements to my document
////////////////////////

// this works
domBuilder.startElement("","head","head",new AttributesImpl());
domBuilder.endElement("","head","head");

// this fails -- why, when we are not appending this
element to the document root but
// instead the root node of the document?
try
{
domBuilder.startElement("","body","body",new
AttributesImpl());
domBuilder.endElement("","body","body");
}
catch (Exception e)
{
System.err.println("Starting body element failed: " +
e.getMessage());
}

////////////////////////
// print it out
////////////////////////

printDocument(document);

}
catch (Exception e)
{
throw new RuntimeException(e);
}

}

/**
* Prints a Document.
*
* @param document
* @throws Exception
*/
private static void printDocument(Document document) throws Exception
{
final DOMSource domSource = new DOMSource(document);
final Writer stringWriter = new StringWriter();
final Result result = new StreamResult(new
BufferedWriter(stringWriter));

final TransformerFactory factory =
TransformerFactory.newInstance();
// produce an identity transform to copy from the source to the
result.
final Transformer transformer = factory.newTransformer();

transformer.setOutputProperties(OutputProperties.getDefaultMethodProperties("xml"));

final DocumentType doctype = document.getDoctype();
if (doctype != null)
{
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,
doctype.getPublicId());
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
doctype.getSystemId());
}

// let her rip
transformer.transform(domSource, result);
final String output = stringWriter.toString();
System.out.println(output);
}

}
 
S

SPG

Hi,

Forgive me as I do not have the documentation in front of me, but from my
recollection, I think you are in fact appending two elements tot he root
from the looks fo your code..

Try this:

domBuilder.startElement("","head","head",new AttributesImpl());

domBuilder.startElement("","body","body",new AttributesImpl());
domBuilder.endElement("","body","body");

domBuilder.endElement("","head","head");



Collin VanDyck said:
I've been using org.apache.xml.utils.DOMBuilder to build an
org.w3c.dom.Document object from a stream of SAX2 events in my
application.

I encounter serious problems when I try and build the document using any
DOCTYPE preset.

My algorithm, should a DOCTYPE be needed in the final Document, is to

1. Create a DocumentBuilder from a DocumentFactory
2. Get the DOMImplementation from the DocumentBuilder
3. Ask the DOMImplementation to create a DocumentType object with some
presets.
4. Use that DocumentType to help create a new Document using the
DOMImplementation
5. Create a DOMBuilder on that Document, using the root Node of the
Document as the current Node so that any further events are built from
that node.

The problem I'm getting is that the DOMBuilder seems to think that I am
appending multiple elements to the root of the Document instead of the
root Node.

To illustrate this, I'm inserting some source that should be runnable
using standard J2SE 1.4.2 runtime libraries. This example will illustrate
my frustration.

Also, John Bollinger, I read your posts on DOCTYPEs, which helped to get
me to this point -- thanks.


The output from my program I get is:

Starting body element failed: Can't have more than one root on a DOM!
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html><head /></html>

But I believe it should be:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html><head /><body/></html>

Any ideas on this, anyone?

thanks,
Collin

----------starting source code-------------------------------


package run;

import java.io.BufferedWriter;
import java.io.StringWriter;
import java.io.Writer;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.xalan.templates.OutputProperties;
import org.apache.xml.utils.DOMBuilder;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.xml.sax.helpers.AttributesImpl;

/**
* Test of the DOMBuilder
*
* @author Collin VanDyck
*/
public class DOMBuilderTest {

public static void main(String[] args)
{
try
{
////////////////////////
// set up the dombuilder
////////////////////////

final DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();

factory.setValidating(false);
factory.setNamespaceAware(false);
factory.setExpandEntityReferences(false);
factory.setIgnoringComments(false);
factory.setIgnoringElementContentWhitespace(false);

final DocumentBuilder builder = factory.newDocumentBuilder();
final DOMImplementation domImplementation =
builder.getDOMImplementation();
final DocumentType documentType =
domImplementation.createDocumentType(
"html",
"-//W3C//DTD XHTML 1.0 Strict//EN",

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");

// this document is created with a root node already in place.
final Document document = domImplementation.createDocument(
"",
documentType.getName(),
documentType);
final Element documentElement = document.getDocumentElement();

// create the DOMBuilder with the current node to be the
document element.
final DOMBuilder domBuilder = new DOMBuilder(document,
documentElement);


////////////////////////
// add elements to my document
////////////////////////

// this works
domBuilder.startElement("","head","head",new
AttributesImpl());
domBuilder.endElement("","head","head");

// this fails -- why, when we are not appending this element
to the document root but
// instead the root node of the document?
try
{
domBuilder.startElement("","body","body",new
AttributesImpl());
domBuilder.endElement("","body","body");
}
catch (Exception e)
{
System.err.println("Starting body element failed: " +
e.getMessage());
}

////////////////////////
// print it out
////////////////////////

printDocument(document);

}
catch (Exception e)
{
throw new RuntimeException(e);
}

}

/**
* Prints a Document.
*
* @param document
* @throws Exception
*/
private static void printDocument(Document document) throws Exception
{
final DOMSource domSource = new DOMSource(document);
final Writer stringWriter = new StringWriter();
final Result result = new StreamResult(new
BufferedWriter(stringWriter));

final TransformerFactory factory =
TransformerFactory.newInstance();
// produce an identity transform to copy from the source to the
result.
final Transformer transformer = factory.newTransformer();

transformer.setOutputProperties(OutputProperties.getDefaultMethodProperties("xml"));

final DocumentType doctype = document.getDoctype();
if (doctype != null)
{
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,
doctype.getPublicId());
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
doctype.getSystemId());
}

// let her rip
transformer.transform(domSource, result);
final String output = stringWriter.toString();
System.out.println(output);
}

}
 
S

SPG

Also..

It seems you may be making life a bit hard for yourself, when there is a
nice wrapper for XML generation and manipulation provided by JDOM (
www.jdom.org )

Steve
SPG said:
Hi,

Forgive me as I do not have the documentation in front of me, but from my
recollection, I think you are in fact appending two elements tot he root
from the looks fo your code..

Try this:

domBuilder.startElement("","head","head",new
AttributesImpl());

domBuilder.startElement("","body","body",new
AttributesImpl());
domBuilder.endElement("","body","body");

domBuilder.endElement("","head","head");



Collin VanDyck said:
I've been using org.apache.xml.utils.DOMBuilder to build an
org.w3c.dom.Document object from a stream of SAX2 events in my
application.

I encounter serious problems when I try and build the document using any
DOCTYPE preset.

My algorithm, should a DOCTYPE be needed in the final Document, is to

1. Create a DocumentBuilder from a DocumentFactory
2. Get the DOMImplementation from the DocumentBuilder
3. Ask the DOMImplementation to create a DocumentType object with some
presets.
4. Use that DocumentType to help create a new Document using the
DOMImplementation
5. Create a DOMBuilder on that Document, using the root Node of the
Document as the current Node so that any further events are built from
that node.

The problem I'm getting is that the DOMBuilder seems to think that I am
appending multiple elements to the root of the Document instead of the
root Node.

To illustrate this, I'm inserting some source that should be runnable
using standard J2SE 1.4.2 runtime libraries. This example will
illustrate my frustration.

Also, John Bollinger, I read your posts on DOCTYPEs, which helped to get
me to this point -- thanks.


The output from my program I get is:

Starting body element failed: Can't have more than one root on a DOM!
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html><head /></html>

But I believe it should be:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html><head /><body/></html>

Any ideas on this, anyone?

thanks,
Collin

----------starting source code-------------------------------


package run;

import java.io.BufferedWriter;
import java.io.StringWriter;
import java.io.Writer;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.xalan.templates.OutputProperties;
import org.apache.xml.utils.DOMBuilder;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.xml.sax.helpers.AttributesImpl;

/**
* Test of the DOMBuilder
*
* @author Collin VanDyck
*/
public class DOMBuilderTest {

public static void main(String[] args)
{
try
{
////////////////////////
// set up the dombuilder
////////////////////////

final DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();

factory.setValidating(false);
factory.setNamespaceAware(false);
factory.setExpandEntityReferences(false);
factory.setIgnoringComments(false);
factory.setIgnoringElementContentWhitespace(false);

final DocumentBuilder builder = factory.newDocumentBuilder();
final DOMImplementation domImplementation =
builder.getDOMImplementation();
final DocumentType documentType =
domImplementation.createDocumentType(
"html",
"-//W3C//DTD XHTML 1.0 Strict//EN",

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");

// this document is created with a root node already in
place.
final Document document = domImplementation.createDocument(
"",
documentType.getName(),
documentType);
final Element documentElement =
document.getDocumentElement();

// create the DOMBuilder with the current node to be the
document element.
final DOMBuilder domBuilder = new DOMBuilder(document,
documentElement);


////////////////////////
// add elements to my document
////////////////////////

// this works
domBuilder.startElement("","head","head",new
AttributesImpl());
domBuilder.endElement("","head","head");

// this fails -- why, when we are not appending this element
to the document root but
// instead the root node of the document?
try
{
domBuilder.startElement("","body","body",new
AttributesImpl());
domBuilder.endElement("","body","body");
}
catch (Exception e)
{
System.err.println("Starting body element failed: " +
e.getMessage());
}

////////////////////////
// print it out
////////////////////////

printDocument(document);

}
catch (Exception e)
{
throw new RuntimeException(e);
}

}

/**
* Prints a Document.
*
* @param document
* @throws Exception
*/
private static void printDocument(Document document) throws Exception
{
final DOMSource domSource = new DOMSource(document);
final Writer stringWriter = new StringWriter();
final Result result = new StreamResult(new
BufferedWriter(stringWriter));

final TransformerFactory factory =
TransformerFactory.newInstance();
// produce an identity transform to copy from the source to the
result.
final Transformer transformer = factory.newTransformer();

transformer.setOutputProperties(OutputProperties.getDefaultMethodProperties("xml"));

final DocumentType doctype = document.getDoctype();
if (doctype != null)
{
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,
doctype.getPublicId());
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
doctype.getSystemId());
}

// let her rip
transformer.transform(domSource, result);
final String output = stringWriter.toString();
System.out.println(output);
}

}
 
C

Collin VanDyck

SPG said:
Hi,

Forgive me as I do not have the documentation in front of me, but from my
recollection, I think you are in fact appending two elements tot he root
from the looks fo your code..

Try this:

domBuilder.startElement("","head","head",new AttributesImpl());

domBuilder.startElement("","body","body",new AttributesImpl());
domBuilder.endElement("","body","body");

domBuilder.endElement("","head","head");

Thanks SPG -- however, I am constructing the Document as:

final Document document = domImplementation.createDocument(
"",
documentType.getName(),
documentType);
final Element documentElement = document.getDocumentElement();

// create the DOMBuilder with the current node to be the document element.
final DOMBuilder domBuilder = new DOMBuilder(document, documentElement);

And from the documentation, any further SAX events should be appended to
the documentElement, not the root of the document.

The root element of the document was already created when I constructed
the Document using a DocumentType. I've verified that in the data
structure using a debugger.

I will look into a similar JDOM utility -- though, I am really curious
as to why I am getting this error.
 
C

Collin VanDyck

I will look into a similar JDOM utility -- though, I am really curious
as to why I am getting this error.

Update: using the latest JDOM's SAXHandler was exactly what I needed. I
like how you can set the DOCTYPE in a org.jdom.Document after the
org.jdom.Document has been created. Although I don't like the extra step
of converting the org.jdom.Document to an org.w3c.dom.Document, it's an
acceptable trade-off for the convenience of the SAXHandler.
 

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,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top