| [ directory ] |
|
3.2 Creating a DOM Tree from ScratchThis section covers how to create DOM objects and how to construct a tree by using example programs. 3.2.1 Creating a Document ObjectFirst, we show how to create a DOM tree without reading an XML document externally. The steps for the creation are as follows:
If you want to see a complete program in advance, refer to Listing 3.1. Recall that in the DOM tree structure, a document is represented by a Document object, so this is what you need to create first. There are several ways to create the object:
The implementation class for the Document interface is org.apache.xerces.dom.DocumentImpl. In the first approach, the class is explicitly generated as follows: import org.w3c.dom.Document; import org.apache.xerces.dom.DocumentImpl; ... // Creates Document object Document doc = new DocumentImpl(); ... This program fragment is very simple, but you must modify the code if you want to use an XML processor other than Xerces, because the implementation class of the Document interface depends on the implementation of the XML processor. If the DOM implementation is to be dynamically selected at runtime, you can use Java's reflection feature to create a class object and then create an instance of it as follows: import org.w3c.dom.Document; ... // Creates Document object String documentImpl = "org.apache.xerces.dom.DocumentImpl"; Document doc = (Document)Class.forName(documentImpl).newInstance(); ... Note that the org.apache.xerces.dom.DocumentImpl class is not imported in the previous example. The class name can be specified by using a command-line argument, a system property, or an external file at runtime. The second approach is a little more complicated but preferable because it can compile without Xerces and is more XML processor杋ndependent. From the viewpoint of XML processor dependence, using the JAXP API is the best way to create a Document object. As described in Chapter 2, the javax.xml.parsers.DocumentBuilderFactory class is used as a DOM parser. This class provides the newDocument() method, which returns a Document object. This method makes it possible to get a Document object without depending on specific implementation classes. An example follows. import org.w3c.dom.Document; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilder; ... // Creates Document object DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.newDocument(); ... 3.2.2 Creating and Appending Child NodesOther DOM objects, such as Element and Text, also need to be created as implementation-specific objects. However, the Document interface provides implementation-neutral methods for creating them. Therefore, after you get the Document object, you can create these nodes without specifying their implementation classes. This is based on the design patterns mentioned in Section 2.3.4. Let's look at how we use the patterns. Suppose that we want to create a person element and set it as the root element doc. In Xerces, the Element interface is implemented by the class org.apache.xerces.dom.ElementImpl, so some simple code may look like this: Element root = new ElementImpl((DocumentImpl)doc, "person"); doc.appendChild(root); Unfortunately, this code is dependent on the specific implementation; Xerces. We can eliminate this kind of implementation dependency by using a factory method. Therefore the previous example can be rewritten as:
Element root = doc.createElement("person");
In this code, the Element node is not created directly by using a new function but is created with the createElement() method. Now the code is solely written in the DOM API and so is more portable. Listing 3.1 lists the factory methods provided by the Document interface. In the DOM Level 2 specification, two methods were added to support namespaces. Listing 3.1 Factory methods provided by the Document interfacepublic Element createElement(String tagName) public Element createElementNS(String namespaceURI, String qualifiedName) (Level 2) public DocumentFragment createDocumentFragment() public Text createTextNode(String data) public Comment createComment(String data) public CDATASection createCDATASection(String data) public ProcessingInstruction createProcessingInstruction(String target, String data) public Attr createAttribute(String name) public Attr createAttributeNS(String namespaceURI, String qualifiedName) (Level 2) public EntityReference createEntityReference(String name) The following objects can be attached to a Document object as its children (remember that Document is also derived from Node):
We have already created the root element. Next, we add a new element named name as a child node of the root element (the person element just created).
Element item = doc.createElement("name");
item.appendChild(doc.createTextNode("John Doe"));
root.appendChild(item);
We created a name element that contains a Text node with the content string "John Doe" and appended the element as the (last) child of the root element. An Element object can take the following objects as children:
At this point, we have created the DOM object tree shown in Figure 3.1. Figure 3.1. A generated DOM tree
Note that you can recursively add elements to build a complex tree structure. Listing 3.2 shows a complete program that generates and outputs a simple XML document. This code creates a Document instance (lines 16?0), creates and appends the root element (line 23), and creates a comment (lines 25?6), an element and an attribute (lines 29?1), and a processing instruction (lines 32?4). The created DOM tree is output by using the serialization package from Xerces (lines 48?3). It is important to output a well-formed or valid XML document to be able to store it or pass it to other applications. We discuss serialization in Section 3.4. Listing 3.2 Creating a DOM tree, chap03/MakeDocumentWithFactory.java
package chap03;
/**
* MakeDocumentWithFactory.java
**/
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import org.w3c.dom.ProcessingInstruction;
[9] import org.apache.xml.serialize.XMLSerializer;
[10] import org.apache.xml.serialize.OutputFormat;
public class MakeDocumentWithFactory {
public static void main(String[] argv) {
try {
[15] // Creates Document object
[16] String documentImpl =
[17] "org.apache.xerces.dom.DocumentImpl";
[18] Document doc = (Document)Class.
[19] forName(documentImpl).newInstance();
[20] // Creates <department> element as root
[21] Element root = doc.createElement("department");
[22] // Sets the element as root
[23] doc.appendChild(root);
[24] // Creates comment node
[25] root.appendChild(doc.createComment(
[26] "The first employee description."));
[27] // Creates <employee> elements and its text
[28] // content, and adds it
[29] Element employee = doc.createElement("employee");
[30] employee.setAttribute("id", "J.D");
[31] root.appendChild(employee);
[32] // Create Processing Instruction
[33] root.appendChild(doc.createProcessingInstruction(
[34] "application", "commandForApp"));
// Creates <name> element and adds it
Element name = doc.createElement("name");
name.appendChild(doc.createTextNode("John Doe"));
employee.appendChild(name);
// Creates <email> element and adds it
Element email = doc.createElement("email");
email.appendChild(
doc.createTextNode("John.Doe@foo.com"));
employee.appendChild(email);
// Prepares output format
OutputFormat formatter = new OutputFormat();
[47] // Preserves whitespace
[48] formatter.setPreserveSpace(true);
[49] // The XML document is output to standard output
[50] XMLSerializer serializer =
[51] new XMLSerializer(System.out, formatter);
[52] // Serializes the DOM tree as an XML document
[53] serializer.serialize(doc);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Executing this program produces the following output. R:\samples>java chap03.MakeDocumentWithFactory <?xml version="1.0" encoding="UTF-8"?> <department><!--The first employee description.--><employee id="J.D"> <name> John Doe</name><email>John.Doe@foo.com</email></employee> <?application commandForApp?></department> Although the result is divided into multiple lines, it is actually output on one line (compare it with department.xml, which appeared in Chapter 2. This occurs because no whitespace for improving readability is contained in the program-generated XML document. Handling whitespace is discussed further in Section 3.5. Listing 3.3 shows a JAXP version (MakeDocumentWithFactoryJAXP) to generate the same XML document. The Document object can be created by using the DocumentBuilder class. That means the class is a factory to create new Document objects, and newDocumentBuilder() is a factory method. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.newDocument(); Listing 3.3 contains no implementation class. If you want to use Listing 3.2 with an XML processor other than Xerces, the program should be modified (line 17) because the DOM specification does not provide an API to create a Document instance. When you use Listing 3.3, you can use it with other JAXP-aware XML processors without modification. Listing 3.3 Creating a DOM tree with the JAXP API, chap03/ MakeDocumentWithFactoryJAXP.java
package chap03;
/**
* MakeDocumentWithFactoryJAXP.java
**/
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import org.w3c.dom.ProcessingInstruction;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
public class MakeDocumentWithFactoryJAXP {
public static void main(String[] argv) {
try {
// Creates document builder factory
DocumentBuilderFactory
factory = DocumentBuilderFactory.newInstance();
DocumentBuilder
builder = factory.newDocumentBuilder();
Document doc = builder.newDocument();
// Creates <department> element as root
Element root = doc.createElement("department");
// Sets the element as root
doc.appendChild(root);
// Creates comment node
root.appendChild(doc.createComment(
"The first employee description."));
// Creates <employee> elements and its text content,
// and adds it
Element employee = doc.createElement("employee");
employee.setAttribute("id", "J.D");
root.appendChild(employee);
// Create Processing Instruction
root.appendChild(doc.createProcessingInstruction(
"application", "commandForApp"));
// Creates <name> element and adds it
Element name = doc.createElement("name");
name.appendChild(doc.createTextNode("John Doe"));
employee.appendChild(name);
// Creates <email> element and adds it
Element email = doc.createElement("email");
email.appendChild(doc.createTextNode(
"John.Doe@foo.com"));
employee.appendChild(email);
// Prepares output format
OutputFormat formatter = new OutputFormat();
// Preserves whitespace
formatter.setPreserveSpace(true);
// The XML document is output to standard output
XMLSerializer serializer =
[55] new XMLSerializer(System.out, formatter);
// Serializes the DOM tree as an XML document
serializer.serialize(doc);
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.2.3 Handling NamespacesThe DOM Level 2 specification introduced two new methods (see the following) to the Element and Attr nodes for supporting namespaces. Using these methods makes it possible to create XML documents with namespaces. public Element createElementNS(String namespaceURI, String qualifiedName) throws DOMException public Attr createAttributeNS(String namespaceURI, String qualifiedName) throws DOMException Both methods take two arguments. The first argument is a namespace URI. A "qualified" name is specified as the second argument. The format of a qualified name is "prefix:local-name," where "prefix" is the namespace prefix used in an XML document and "local-name" is the name of an element or attribute. A special attribute named xmlns is used to associate a namespace URI and a prefix. This attribute is not created automatically when the methods are executed. Developers should create this attribute and set it to an appropriate element. Listing 4.1 in Section 4.3.5 shows a sample program that checks namespaces in an XML document and adds xmlns attributes automatically. Listing 3.4 shows a sample program to create an XML document with namespaces. Listing 3.4 Creating a DOM tree with namespaces, chap03/MakeDocumentWithNS.java
package chap03;
/**
* MakeDocumentWithNS.java
**/
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import org.w3c.dom.ProcessingInstruction;
import org.apache.xml.serialize.XMLSerializer;
import org.apache.xml.serialize.OutputFormat;
public class MakeDocumentWithNS {
public static void main(String[] argv) {
final String NAMESPACE_URI
= "http://www.foo.com/department";
final String NAMESPACE_PREFIX_WITH_COLON = "ns:";
final String NAMESPACE_SPEC
= "http://www.w3.org/2000/xmlns/";
try {
// Creates document builder factory
DocumentBuilderFactory
factory = DocumentBuilderFactory.newInstance();
DocumentBuilder
builder = factory.newDocumentBuilder();
Document doc = builder.newDocument();
// Creates <department> element as root with namespace
Element root = doc.createElementNS(NAMESPACE_URI,
NAMESPACE_PREFIX_WITH_COLON+"department");
// Sets xmlns attribute to specify namespace
// prefix and uri
root.setAttributeNS(NAMESPACE_SPEC, "xmlns:ns",
NAMESPACE_URI);
// Sets the element as root
doc.appendChild(root);
// Creates comment node
root.appendChild(doc.createComment(
"The first employee description."));
// Creates <employee> elements and its text content,
// and adds it
Element employee = doc.createElementNS(NAMESPACE_URI,
NAMESPACE_PREFIX_WITH_COLON+"employee");
employee.setAttributeNS(NAMESPACE_URI,
NAMESPACE_PREFIX_WITH_COLON+"id", "J.D");
root.appendChild(employee);
// Create Processing Instruction
root.appendChild(doc.createProcessingInstruction(
"application", "commandForApp"));
// Creates <name> element and adds it
Element name = doc.createElementNS(NAMESPACE_URI,
NAMESPACE_PREFIX_WITH_COLON+"name");
name.appendChild(doc.createTextNode("John Doe"));
employee.appendChild(name);
// Creates <email> element and adds it
Element email = doc.createElementNS(NAMESPACE_URI,
NAMESPACE_PREFIX_WITH_COLON+"email");
email.appendChild(
doc.createTextNode("John.Doe@foo.com"));
employee.appendChild(email);
// Prepares output format
OutputFormat formatter = new OutputFormat();
formatter.setPreserveSpace(true);
// The XML document is output to standard output
XMLSerializer serializer =
new XMLSerializer(System.out, formatter);
// Serializes the DOM tree as an XML document
serializer.serialize(doc);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Executing this program produces the following output. R:\samples>java chap03.MakeDocumentWithNS <?xml version="1.0" encoding="UTF-8"?> <ns:department xmlns:ns="http://www.foo.com/department"><!--The first employee description.--><ns:employee ns:id="J.D"><ns:name>John Doe</ ns:name><ns:email>John.Doe@foo.com</ns:email></ns:employee> <?application commandForApp?></ns:department> |
| [ directory ] |
|