Document Type Declarations

Documents created with JDOM can have document type declarations and thus can be valid. JDOM does not offer a complete object model for DTDs. However, it does allow you to point at an existing DTD or add an internal DTD subset to your documents.

Example 14.2 is a simple document type definition for the Fibonacci number documents we’ve been generating.

Example 14.2. A Fibonacci DTD

<!ELEMENT Fibonacci_Numbers (fibonacci*)>
<!ELEMENT fibonacci (#PCDATA)>
<!ATTLIST fibonacci index CDATA #IMPLIED>

Let assume that this is available at the relative URL fibonacci.dtd. Thus the following DOCTYPE declaration would make the document valid:

<!DOCTYPE Fibonacci_Numbers SYSTEM "fibonacci.dtd">

In JDOM, the DocType class represents document type declarations. You can create this object using a constructor that receives the root element name and system ID as arguments. For example,

DocType type = new DocType("Fibonacci_Numbers", "fibonacci.dtd");

You can either pass this DocType object as the second argument to the Document constructor or invoke the Document class’s setDocType() method.

Example 14.3 demonstrates a program that produces a completely valid document. However, JDOM does not provide any direct means to test the validity of a document, short of serializing it and passing the resulting stream through a validating parser.

Example 14.3. A JDOM program that produces an XML document containing Fibonacci numbers

import org.jdom.*;
import org.jdom.output.XMLOutputter;
import java.math.BigInteger;
import java.io.IOException;


public class ValidFibonacci {

  public static void main(String[] args) {

    Element root = new Element("Fibonacci_Numbers");
    DocType type = new DocType("Fibonacci_Numbers", "fibonacci.dtd");
    Document doc = new Document(root, type);

    BigInteger low  = BigInteger.ONE;
    BigInteger high = BigInteger.ONE;

    for (int i = 1; i <= 5; i++) {
      Element fibonacci = new Element("fibonacci");
      fibonacci.setAttribute("index", String.valueOf(i));
      fibonacci.setText(low.toString());
      root.addContent(fibonacci);

      BigInteger temp = high;
      high = high.add(low);
      low = temp;
    }

    // serialize with two space indents and extra line breaks
    try {
      XMLOutputter serializer = new XMLOutputter("  ", true);
      serializer.output(doc, System.out);
    }
    catch (IOException e) {
      System.err.println(e);
    }

  }

}

Here’s the output with the document type declaration in place:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Fibonacci_Numbers SYSTEM "fibonacci.dtd">
<Fibonacci_Numbers>
  <fibonacci index="1">1</fibonacci>
  <fibonacci index="2">1</fibonacci>
  <fibonacci index="3">2</fibonacci>
  <fibonacci index="4">3</fibonacci>
  <fibonacci index="5">5</fibonacci>
</Fibonacci_Numbers>

You can also specify a public ID for the external DTD subset. For example, if the public ID for Example 14.2 is -//Elliotte Rusty Harold//Fibonacci Example//EN, then the DocType object could be initialized like this:

DocType type = new DocType("Fibonacci_Numbers", 
  "-//Elliotte Rusty Harold//Fibonacci Example//EN", 
  "fibonacci.dtd");

You can also use the setInternalSubset() method to provide an internal DTD subset. As with all internal DTD subsets, this can be instead of or in addition to the external DTD subset identified by the public ID and the system ID. For example, this code fragment uses an internal DTD subset instead of an external DTD subset.

    Element root = new Element("Fibonacci_Numbers");

    DocType type = new DocType("Fibonacci_Numbers");
    String dtd = "<!ELEMENT Fibonacci_Numbers (fibonacci*)>\n";
    dtd += "<!ELEMENT fibonacci (#PCDATA)>\n";
    dtd += "<!ATTLIST fibonacci index CDATA #IMPLIED>\n";
    type.setInternalSubset(dtd);
    
    Document doc = new Document(root, type);

The document produced includes an internal DTD subset and no system or public ID:

<?xml version="1.0" encoding="UTF-8"
<!DOCTYPE Fibonacci_Numbers [
<!ELEMENT Fibonacci_Numbers (fibonacci*)>
<!ELEMENT fibonacci (#PCDATA)>
<!ATTLIST fibonacci index CDATA #IMPLIED>
]>
<Fibonacci_Numbers>
  <fibonacci index="1">1</fibonacci>
  …

Other programs and documents might specify both an internal DTD subset and a system and public ID for the external DTD subset.

Note

DTDs and document type declarations are mostly important for serialization. If the document is written onto a stream and read by some other program, then that other program may take advantage of the DTD for validation or application of default attribute values and so forth. However, JDOM itself doesn’t pay a lot of attention to the DTD. In fact, as far as it’s concerned the various parts are all just strings. It does not, for example, apply any default attribute values indicated by either the internal or external DTD subsets. If the initial JDOM Document object is created by a validating parser (rather than directly in memory), then that parser will report all the default attribute values the same as specified attribute values. However, changes made to the Document’s DocType after the document is initially parsed will not have any affect on the content of the rest of the Document.


Copyright 2001, 2002 Elliotte Rusty Haroldelharo@metalab.unc.eduLast Modified July 29, 2002
Up To Cafe con Leche