Abstract

Die W3C-Spezifikation des Document Object Models (abgekürzt als: DOM) definiert eine Programmiersprachen-unabhängige und plattformneutrale Menge abstrakter Schnittstellen, mit denen Programme und Skripte lesend und schreibend auf gültige HTML-Dokumente und wohlgeformte XML-Dokumente sowie eine Reihe weiterer Formate zugreifen können.
HTML: Das Dokument kann weiterverarbeitet werden, das Ergebnis dieser Verarbeitung kann direkt in die angezeigte Seite eingebunden werden.

Was ist DOM?

DOM versteht sich als Application Programming Interface (API) für beliebige XML-Dokumente (und damit auch XHTML-Dokumente). Es definiert die logische Struktur eines Dokumentes und die Art und Weise, wie auf diese Struktur zugegriffen und die Information verändert werden kann. Hierzu versammelt es auf Basis einer generischen Speicherrepräsentation für XML eine Menge von Operationen.

Programmierer können mit DOM Dokumente erstellen, entlang ihrer Struktur navigieren, Elemente und deren Inhalt hinzufügen, verändern oder löschen.

Als W3C-Spezifikation zielt DOM nicht auf eine spezielle Programmierumgebung ab, sondern wurde vor dem Hintergrund entworfen, für beliebige unterschiedlicher Programmiersprachen einsetzbar zu sein.
Aus diesem Grund wurde die Spezifikation in einer besonderen Sprache für Schnittstellen, der sogenannten Interface Definition Language (IDL) entworfen.
Es existiert eine Abbildung der IDL Spezifikation auf die Programmiersprache Java.

DOM ist...

DOM ist nicht...

DOM - Herkunft

DOM spezifizierte ursprünglich, wie JavaScript Skripte und Java-Programme über Web Browser hinweg portabel sein konnten. "Dynamisches HTML" war der direkte Vorgänger des DOM. Der Fokus lag damals stark auf Browsern. Im Rahmen der Weiterentwicklung hatte die SGML und schließlich die XML so starken Einfluß auf DOM, daß mittlerweile der Hauptfokus auf XML-Dokumenten liegt.

Die DOM Module

DOM bietet eine Menge von einzelner APIs, die zusammen die DOM API bilden. Jede dieser Spezifikationen definiert ein oder mehrere Module, von denen wiederum jedes mit ein oder mehr Feature-Namen assoziiert ist.

Die DOM Core spezifikation definiert beispielsweise zwei Module:

Die folgende Abbildung zeigt alle DOM Module mit ihren Feature-Namen, die in DOM spezifiziert sind:

DOM - Übersicht über die verschiedenen Spezifikationen

DOM - Vergleich Level 1 - Level 2 - Level 3

DOM Level 2 erweitert die in Level 1 eingeführten Schnittstellen hinsichtlich der Erfordernisse des aktuellen XML-Standes um Namensräume und bietet einige neue Operationen, die seitens der Anwendergemeinde gefordert wurden. Die bisherigen Operationen existieren aus Kompatibilitätsgründen weiter, die Namespace-berücksichtigenden Pendants sind identisch benannt, jedoch um ein angehängtes NS erweitert.

DOM Level 3 komplettiert im Vergleich zu DOM Level 2 die Abbildung zwischen DOM und dem XML Information Set. Dies beinhaltet Unterstützung für XML Base, Unterstützung zur Auflösung von Namensraumpräfixen oder der Manipulation von ID Attributen, etc.

DOM Conformance

Eine Implementierung darf sich als konform zur DOM Level 3 Spezifikation bezeichnen, wenn sie das Core -Modul unterstützt.

Eine Implementierung darf sich als konform zu einem DOM Level 3 Modul bezeichnen, wenn sie alle zu diesem Modul definierten Schnittstellen unterstützt, sowie die damit verbundene Semantik.

Ob eine DOM-Implementierung ein einzelnes Modul unterstützt, kann durch die Schnittstellenfunktion hasFeature der Schnittstelle DOMImplementation des Moduls Core ermittelt werden.

DOM - erstes Beispiel: Ermitteln der unterstützten DOM-Module

DOM - erstes Beispiel: komplettes Listing

import org.w3c.dom.DOMImplementation;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

public class DOMExample2 {
    public static void main(String argv[]) throws Exception {
        // implementation specific part begins ...
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        DOMImplementation implementation = builder.getDOMImplementation();
    // ... ends
    
        String feature[] = {
          "Core", "XML", "HTML", "XPath", "Validation", 
          "Events", "LS", "Views", "Traversal", "LS-Async",
          "StyleSheets", "Range", "HTMLEvents", "MutationEvents",
          "UIEvents", "CSS", "MutationNameEvents", "CSS2", 
          "KeyboardEvents", "TextEvents", "MouseEvents"
          };

        for (int i = 0; i < feature.length; i++) {

            System.out.print(feature[i]);
            if (!implementation.hasFeature(feature[i], "3.0")) {
                System.out.println(" not supported");
            } //if 
            else {
                System.out.println(" supported");
            } //else
        } //for
    } //main()
} //class domtest

Die grundlegenden DOM-Schnittstellen - Document

Die Schnittstelle Document stellt eine spezialisierte Schnittstelle von Node dar. Sie stellt den Einstieg in ein XML-Dokument dar und wird deshalb zuerst behandelt.

Diese Schnittstelle steht für das gesamte XML oder XHTML-Dokument. Sie bildet die Wurzel des Dokumentbaumes und bietet den ersten Einstiegspunkt, um auf die Daten des Dokuments zuzugreifen.

Weil es außerhalb des Kontexts eines Dokuments keine Textknoten, Kommentare, Processing Instructions, etc. geben kann, enthält die Schnittstelle Document auch die Fabrikmethoden zur Erzeugung dieser Objekte.

Die vier durch DOM definierten Datentypen

DOM definiert folgende vier Datentypen

Die grundlegenden DOM-Schnittstellen - Document - Attribute

Die Schnittstelle besitzt folgende Eigenschaften

  // Modified in DOM Level 3:
  readonly attribute DocumentType    doctype;
  readonly attribute DOMImplementation implementation;
  readonly attribute Element         documentElement;

  // Introduced in DOM Level 3:
  readonly attribute DOMString       inputEncoding;
  readonly attribute DOMString       xmlEncoding;
  readonly attribute DOMConfiguration domConfig;
           attribute boolean         xmlStandalone;
                                        // raises(DOMException) on setting
           attribute DOMString       xmlVersion;
                                        // raises(DOMException) on setting
           attribute boolean         strictErrorChecking;
           attribute DOMString       documentURI;

Einige wenige Attribute der Schnittstelle erlauben einfachen und schnellen Zugriff auf Kindelemente, ohne daß dorthin navigiert werden muss:

Bedeutung DOM-sezifischer Attribute:

Abbildung nach Java:

DOM Attribut Java Methode(n)
doctype DocumentType getDoctype()
implementation DOMImplementation getImplementation()
documentElement Element getDocumentElement()
inputEncoding String getInputEncoding()
xmlEncoding String getXmlEncoding()
xmlStandalone boolean getXmlStandalone() ,
void setXmlStandalone(boolean xmlStandalone)
xmlVersion String getXmlVersion() ,
void setXmlVersion(String xmlVersion)
strictErrorChecking boolean getStrictErrorChecking() ,
void setStrictErrorChecking(boolean strictErrorChecking)
documentURI String getDocumentURI() ,
void setDocumentURI(String documentURI

Die grundlegenden DOM-Schnittstellen - Document - Operationen

Folgende Operationen sind für die Schnittstelle Document definiert:

  Element            createElement(in DOMString tagName)
                                        raises(DOMException);
  DocumentFragment   createDocumentFragment();
  Text               createTextNode(in DOMString data);
  Comment            createComment(in DOMString data);
  CDATASection       createCDATASection(in DOMString data)
                                        raises(DOMException);
  ProcessingInstruction createProcessingInstruction(in DOMString target, 
                                                    in DOMString data)
                                        raises(DOMException);
  Attr               createAttribute(in DOMString name)
                                        raises(DOMException);
  EntityReference    createEntityReference(in DOMString name)
                                        raises(DOMException);
  NodeList           getElementsByTagName(in DOMString tagname);

  // Introduced in DOM Level 2:
  Node               importNode(in Node importedNode, 
                                in boolean deep)
                                        raises(DOMException);
  Element            createElementNS(in DOMString namespaceURI, 
                                     in DOMString qualifiedName)
  Attr               createAttributeNS(in DOMString namespaceURI, 
                                       in DOMString qualifiedName)
                                        raises(DOMException);
  NodeList           getElementsByTagNameNS(in DOMString namespaceURI, 
                                            in DOMString localName);
  Element            getElementById(in DOMString elementId);

  // Introduced in DOM Level 3:
  Node               adoptNode(in Node source)
                                        raises(DOMException);
  void               normalizeDocument();
  Node               renameNode(in Node n, 
                                in DOMString namespaceURI, 
                                in DOMString qualifiedName)
                                        raises(DOMException);

Abbildung in Java

DOM Methode Java Methode(n)
createElement(in DOMString tagName) Element createElement(String tagName)
createDocumentFragment() DocumentFragment createDocumentFragment()
createTextNode(in DOMString data) Text createTextNode(String data)
createComment(in DOMString data) Comment createComment(String data)
createCDATASection(in DOMString data)
createProcessingInstruction(in DOMString target, in DOMString data) CDATASection createCDATASection(String data)
createAttribute(in DOMString name) Attr createAttribute(String name)
createEntityReference(in DOMString name) EntityReference createEntityReference(String name)
getElementsByTagName(in DOMString tagname) NodeList getElementsByTagName(String tagname)
importNode(in Node importedNode, in boolean deep) Node importNode(Node importedNode, boolean deep)
createElementNS(in DOMString namespaceURI, in DOMString qualifiedName) Element createElementNS(String namespaceURI, String qualifiedName)
createAttributeNS(in DOMString namespaceURI, in DOMString qualifiedName) Attr createAttributeNS(String namespaceURI, String qualifiedName)
getElementsByTagNameNS(in DOMString namespaceURI, in DOMString localName) NodeList getElementsByTagNameNS(String namespaceURI, String localName)
getElementById(in DOMString elementId) Element getElementById(String elementId)
adoptNode(in Node source) Node adoptNode(Node source)
normalizeDocument() void normalizeDocument()
renameNode(in Node n, in DOMString namespaceURI, in DOMString qualifiedName) Node renameNode(Node n, String namespaceURI, String qualifiedName)

Es ist festzustellen, daß die Abbildung der DOM Attribute und Operationen in die Programmiersprache Java sich sehr übersichtlich gestaltet.

DOM - zweites Codebeispiel: einfacher Parser

In diesem Codebeispiel soll eine DOM-basierte Speicherstruktur mit SUNs JDK erzeugt werden.

Die grundlegenden DOM-Schnittstellen - Node

Die Schnittstelle Node ist der wichtigste Datentyp für das gesamte DOM. Sie stellt einen einzelnen Knoten im gesamten Dokumentbaum dar.

Die Schnittstelle konzentriert alle gemeinsamen Anteile der verschiedenen Knoten eines XML-Baumes. Hierzu gehören:

Alle Objekte, die die Schnittstelle Node implementieren, stellen Methoden zur Verfügung, um mit Kindknoten umzugehen. Gleichzeitig verfügen jedoch nicht alle dieser Objekte über Kindknoten (z.B. Textknoten, diese haben keine Kindknoten).

Die grundlegenden DOM-Schnittstellen - Node - Knotentypisierung

In der Schnittstelle sind verschiedene Konstanten definiert, die dazu dienen, eine Typisierung für die verschiedenen Arten von Knoten zu realisieren. Ein Integer weist darauf hin, um welchen Knotentyp es sich handelt (die Zahlen bis 200 sind hierfür reserviert). Für jeden dieser Knotentypen existiert jeweils eine eigene DOM-Schnittstelle.

  const unsigned short      ELEMENT_NODE                   = 1;
  const unsigned short      ATTRIBUTE_NODE                 = 2;
  const unsigned short      TEXT_NODE                      = 3;
  const unsigned short      CDATA_SECTION_NODE             = 4;
  const unsigned short      ENTITY_REFERENCE_NODE          = 5;
  const unsigned short      ENTITY_NODE                    = 6;
  const unsigned short      PROCESSING_INSTRUCTION_NODE    = 7;
  const unsigned short      COMMENT_NODE                   = 8;
  const unsigned short      DOCUMENT_NODE                  = 9;
  const unsigned short      DOCUMENT_TYPE_NODE             = 10;
  const unsigned short      DOCUMENT_FRAGMENT_NODE         = 11;
  const unsigned short      NOTATION_NODE                  = 12;

Die grundlegenden DOM-Schnittstellen - Node - Knotentypisierung - Beispiel

Der Knotentyp eines jeden Knotens kann über das in DOM spezifizierte Attribut nodeType abgefragt werden.
In Java ist dieses DOM-Attribut durch die Operation getNodeType() abgebildet.

Im vorgestellten Beispiel wird diese Operation auf verschiedenen Knotentypen aufgerufen:

Auszug aus dem Sourcecode: Aufruf der Operation auf Inhaltsknoten des Wurzelelementes

        for (int i=0; i< childNodes.getLength(); i++) {
         System.out.println("Child Node at position " + i + " has type " + childNodes.item(i).getNodeType()  );
        }        

Angewendet auf das folgendes XML-Dokument...

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<Vorlesung>
  <Pflichtfach/>
  <Hochschule>Fachhochschule Augsburg</Hochschule>
  <Studiengang semester="3">IAM</Studiengang>
  <Titel>XML</Titel>
  <Semester>WS 2008/2009</Semester>
  Montag, 08:00h - 09:30h
  <Praktikum>Seminar</Praktikum>
</Vorlesung>

... ergibt sich folgende Ausgabe:

Document node is of type: 9
Root element is of type: 1
Root element has 13 child elements
Child Node at position 0 has type 3
Child Node at position 1 has type 1
Child Node at position 2 has type 3
Child Node at position 3 has type 1
Child Node at position 4 has type 3
Child Node at position 5 has type 1
Child Node at position 6 has type 3
Child Node at position 7 has type 1
Child Node at position 8 has type 3
Child Node at position 9 has type 1
Child Node at position 10 has type 3
Child Node at position 11 has type 1
Child Node at position 12 has type 3

Die gefundenen Textknoten entsprechen dem textuellen Inhalt in Vorlesung inkl. der Zeilenumbrüche.

Die grundlegenden DOM-Schnittstellen - Node - grundlegende Attribute

Mit den Attributen nodeName , nodeValue und attributes stehen grundlegende Attribute zur Verfügung, die es erlauben, einfach auf die Information der betreffenden Knoten zuzugreifen, ohne daß auf die spezifische Schnittstelle des jeweiligen Knotentyps direkt zugegriffen werden muß.
Hinweis: die spezifischen Schnittstellen enthalten unter Umständen zusätzliche Mechanismen, mit denen man sehr einfach relevante Informationen erhalten oder setzen kann.

  readonly attribute DOMString       nodeName;
           attribute DOMString       nodeValue;
                                        // raises(DOMException) on setting
                                        // raises(DOMException) on retrieval
  readonly attribute NamedNodeMap    attributes;

Abbildung nach Java:

Das vorige Beispiel erweitert um Ausgaben zu nodeName und nodeValue liefert folgende Ausgabe:

Document node is of type: 9
Root element of name Vorlesung is of type: 1
Root element has 13 child elements
Child Node at position 0 with name #text has type 3
Text Node has Value: 
  
Child Node at position 1 with name Pflichtfach has type 1
Child Node at position 2 with name #text has type 3
Text Node has Value: 
  
Child Node at position 3 with name Hochschule has type 1
Child Node at position 4 with name #text has type 3
Text Node has Value: 
  
Child Node at position 5 with name Studiengang has type 1
Child Node at position 6 with name #text has type 3
Text Node has Value: 
  
Child Node at position 7 with name Titel has type 1
Child Node at position 8 with name #text has type 3
Text Node has Value: 
  
Child Node at position 9 with name Semester has type 1
Child Node at position 10 with name #text has type 3
Text Node has Value: 
  Montag, 08:00h - 09:30h
  
Child Node at position 11 with name Praktikum has type 1
Child Node at position 12 with name #text has type 3
Text Node has Value: 

Die grundlegenden DOM-Schnittstellen - Node - weitere Attribute

Des weiteren versammelt die Schnittstelle Node folgende weiteren Attribute:

  readonly attribute unsigned short  nodeType;
  readonly attribute Node            parentNode;
  readonly attribute NodeList        childNodes;
  readonly attribute Node            firstChild;
  readonly attribute Node            lastChild;
  readonly attribute Node            previousSibling;
  readonly attribute Node            nextSibling;

  // Modified in DOM Level 2:
  readonly attribute Document        ownerDocument;

  // Introduced in DOM Level 2:
  readonly attribute DOMString       namespaceURI;
           attribute DOMString       prefix;
                                        // raises(DOMException) on setting
  readonly attribute DOMString       localName;

  // Introduced in DOM Level 3:
  readonly attribute DOMString       baseURI;
           attribute DOMString       textContent;
                                        // raises(DOMException) on setting
                                        // raises(DOMException) on retrieval

Abbildung nach Java:

DOM Attribut Java Methode(n)
nodeType short getNodeType()
parentNode Node getParentNode()
childNodes NodeList getChildNodes()
firstChild Node getFirstChild()
lastChild Node getLastChild()
previousSibling Node getPreviousSibling()
nextSibling Node getNextSibling()
ownerDocument Document getOwnerDocument()
namespaceURI String getNamespaceURI()
prefix String getPrefix()
localName String getLocalName()
baseURI String getBaseURI()
textContent String getTextContent()

Die grundlegenden DOM-Schnittstellen - Node - Operationen

Die aufgeführten Operationen erlauben Veränderungen der Knotenstruktur. So können etwa neue Knoten in eine bestehendes DOM-Objektmodell eingefügt werden. Darüberhinaus können existierende Knoten ersetzt, gelöscht und kopiert werden. Die Schnittstelle Node wird von allen im folgenden diskutierten nach Knotentyp spezialisierten Schnittstellen erweitert.

  boolean            hasChildNodes();
  Node               cloneNode(in boolean deep);


  // Modified in DOM Level 3:
  Node               insertBefore(in Node newChild, 
                                  in Node refChild)
                                        raises(DOMException);
  Node               replaceChild(in Node newChild, 
                                  in Node oldChild)
                                        raises(DOMException);
  Node               removeChild(in Node oldChild)
                                        raises(DOMException);
  Node               appendChild(in Node newChild)
                                        raises(DOMException);
  void               normalize();
  unsigned short     compareDocumentPosition(in Node other)
                                        raises(DOMException);

  // Introduced in DOM Level 2:
  boolean            isSupported(in DOMString feature, 
                                 in DOMString version);
  boolean            hasAttributes();

  // Introduced in DOM Level 3:
  boolean            isSameNode(in Node other);
  DOMString          lookupPrefix(in DOMString namespaceURI);
  boolean            isDefaultNamespace(in DOMString namespaceURI);
  DOMString          lookupNamespaceURI(in DOMString prefix);
  boolean            isEqualNode(in Node arg);
  DOMObject          getFeature(in DOMString feature, 
                                in DOMString version);
  DOMUserData        setUserData(in DOMString key, 
                                 in DOMUserData data, 
                                 in UserDataHandler handler);
  DOMUserData        getUserData(in DOMString key);

Die Abbildung in Java wird ab hier nicht mehr explizit aufgeführt. Für eine Übersicht der Java Schnittstellen siehe Java API Dokumentation , Paket org.w3c.dom .

Die grundlegenden DOM-Schnittstellen - Node - Beispiel

Das komplette Beispiel zur Schnittstelle Node

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

public class DOMNode {
    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(args[0]);

        System.out.println("Document node is of type: " + document.getNodeType());        
        Element theRootElement = document.getDocumentElement();   
        System.out.println("Root element of name " + theRootElement.getNodeName() + " is of type: " + theRootElement.getNodeType());
        NodeList childNodes = theRootElement.getChildNodes();
        System.out.println("Root element has " + childNodes.getLength() + " child elements");
        
        for (int i=0; i< childNodes.getLength(); i++) {
         System.out.println("Child Node at position " + i + " with name " + childNodes.item(i).getNodeName() + " has type " + childNodes.item(i).getNodeType()  );
         if (childNodes.item(i).getNodeType()==3) {
          System.out.println("Text Node has Value: " + childNodes.item(i).getNodeValue() );
         } else {
          
         }
        }        
        
    } //main()
} //class DOMNode

Die grundlegenden DOM-Schnittstellen - Element

Die Schnittstelle Element entspricht einem Element eines XML- oder HTML-Dokumentes. Da die Schnittstelle Node erweitert wird, können die dort definierte generischen Attribute verwendet werden, um beispielsweise die Menge von Attributen zu einem Element zu erhalten.
Des weiteren enthält die Schnittstelle eine Reihe von Operationen zum Zugriff auf XML-Elemente.

Die Schnittstelle versammelt folgende Eigenschaften:

  readonly attribute DOMString       tagName;
  // Introduced in DOM Level 3:
  readonly attribute TypeInfo        schemaTypeInfo;

Die grundlegenden DOM-Schnittstellen - Element - Operationen

Folgende Operationen sind für die Schnittstelle Element definiert:

  DOMString          getAttribute(in DOMString name);
  Attr               getAttributeNode(in DOMString name);
  void               setAttribute(in DOMString name, 
                                  in DOMString value)
                                        raises(DOMException);
  Attr               setAttributeNode(in Attr newAttr)
                                        raises(DOMException);
  void               removeAttribute(in DOMString name)
                                        raises(DOMException);
  Attr               removeAttributeNode(in Attr oldAttr)
                                        raises(DOMException);
  NodeList           getElementsByTagName(in DOMString name);

  // Introduced in DOM Level 2:
  DOMString          getAttributeNS(in DOMString namespaceURI, 
                                    in DOMString localName)
                                        raises(DOMException);
  Attr               getAttributeNodeNS(in DOMString namespaceURI, 
                                        in DOMString localName)
                                        raises(DOMException);
  void               setAttributeNS(in DOMString namespaceURI, 
                                    in DOMString qualifiedName, 
                                    in DOMString value)
                                        raises(DOMException);
  Attr               setAttributeNodeNS(in Attr newAttr)
                                        raises(DOMException);
  void               removeAttributeNS(in DOMString namespaceURI, 
                                       in DOMString localName)
                                        raises(DOMException);
  boolean            hasAttribute(in DOMString name);
  boolean            hasAttributeNS(in DOMString namespaceURI, 
                                    in DOMString localName)
                                        raises(DOMException);
  NodeList           getElementsByTagNameNS(in DOMString namespaceURI, 
                                            in DOMString localName)
                                        raises(DOMException);
  // Introduced in DOM Level 3:
  void               setIdAttribute(in DOMString name, 
                                    in boolean isId)
                                        raises(DOMException);
  void               setIdAttributeNS(in DOMString namespaceURI, 
                                      in DOMString localName, 
                                      in boolean isId)
                                        raises(DOMException);
  void               setIdAttributeNode(in Attr idAttr, 
                                        in boolean isId)
                                        raises(DOMException);

DOM - Beispiel: Zugriff auf das Wurzelelement eines Dokuments

In diesem Beispiel soll der Einsatz der Operation hasAttributes gezeigt werden. Die Methode testet, ob für das gegebene Element Attribute existieren.

Zunächst wird mit der Methode getDocumentElement auf das Wurzelelement des Dokuments zugegriffen. Diese Methode entspricht keiner DOM-Operation, sondern dem DOM-Attribut documentElement .
Grund: Java erlaubt in Schnittstellen keine änderbaren Attribute. Daher stellt die DOM-Implementierung des JDK für diese Attribute eigene Zugriffsmethoden zur Verfügung.

        Element theRootElement = document.getDocumentElement();

In einem weiteren Schritt wird mittels getTagName() der Name des Wurzelelements ermittelt. Diese Java-Methode entspricht dem DOM-Attribut tagName .

        System.out.println("root element's name: " + theRootElement.getTagName());

Mit der Methode hasAttributes() wird schließlich abgefragt, ob das Element Attribute besitzt, und eine entsprechende Ausgabe erzeugt.

        System.out.print("the element has");
        if (!theRootElement.hasAttributes())
            System.out.print(" no");
        System.out.println(" attributes");

Das gesamte Listing:

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

public class DOMExample4 {
    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(args[0]);

        Element theRootElement = document.getDocumentElement();

        System.out.println("root element's name: " + theRootElement.getTagName());

        System.out.print("the element has");
        if (!theRootElement.hasAttributes())
            System.out.print(" no");
        System.out.println(" attributes");
    } //main()
} //class DOMExample4

Angewandt auf die XML-Datei der Projektverwaltung liefert das Programm die Ausgabe:

root element's name: ProjektVerwaltung
the element has attributes

DOM - Beispiel: Ein Dokument modifizieren

Mit DOM kann -- im Gegensatz zu SAX -- ein eingelesenes Dokument verändert werden. Das hier diskutierte Beispiel demonstriert dies.

Dem Wurzelelement eines Dokuments (das Objekt theRootElement vom Typ Element ) soll ein Attribut (benannt mit myFirstNewAttribute ) hinzugefügt und mit dem Wert 01 belegt werden.

        Element theRootElement = document.getDocumentElement();
        System.out.println("root element's name: " + theRootElement.getTagName());
        theRootElement.setAttribute("myFirstNewAttribute", "01");
        if (theRootElement.hasAttribute("myFirstNewAttribute")){
         System.out.println("Setting of attribute 'myFirstNewAttribute' successful!");
         System.out.println("Value of attribute: " + theRootElement.getAttribute("myFirstNewAttribute"));
        } else {
         System.out.println("Setting of attribute failed.");
        }

Zudem soll ein neues Element myNewElement als Kindelement des Wurzelelements erzeugt werden.

        Element aNewElement = document.createElement("myNewElement");
        theRootElement.appendChild(aNewElement);
        if (theRootElement.hasChildNodes()){
         System.out.println("Appending successful - root node now has child elements.");
        } else {
         System.out.println("Appending of child element failed.");
        }

Achtung:
Die Methode createElement ist für die Schnittstelle document definiert und muß auf dieser aufgerufen werden.
Das neu erzeugte Element muß mit appendChild (von der Schnittstelle Element ) an das Wurzelelement angehängt werden.

Hinweis: In früheren JDK-Versionen konnte durch den Aufruf der Methode String.println ein DOM-Baum in eine Zeichenkettenrepräsentation serialisiert und über die Standardausgabe ausgegeben werden. Dies ist inzwischen nicht mehr der Fall!

Angewendet auf eine sehr einfache Eingabedatei mit dem (einzigen) Element empty als Wurzelelement ergibt sich folgende Ausgabe:

root element's name: empty
Setting of attribute 'myFirstNewAttribute' successful!
Value of attribute: 01
Appending successful - root node now has child elements.
[empty: null]

Die grundlegenden DOM-Schnittstellen - NodeList

Die Schnittstelle NodeList definiert einen Container zur Aufnahme beliebiger Objekte des Typs Node . Sie definiert das Attribut length , welches zu jedem Zeitpunkt die Anzahl der verwalteten Elemente enthält. Der Zugriff auf die verwalteten Knoten erfolgt indexsequentiell durch die Methode item .

interface NodeList {
  Node               item(in unsigned long index);
  readonly attribute unsigned long   length;
};

DOM - Beispiel NodeList: Ein Dokument modifizieren

Das Beispiel zeigt die Verwendung der Schnittstelle, um festzustellen, wie oft ein als Kommandozeilenparameter übergebener Elementname in einem Dokument auftritt.

Die Methode getElementsByTagName der Schnittstelle Document fügt während der Ausführung alle Auftreten von Elementen mit dem gesuchten Namen in die Ergebnismenge ein.

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

public class DOMExample6 {
    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(args[0]);

        Element theRootElement = document.getDocumentElement();

        NodeList nodes = theRootElement.getElementsByTagName(args[1]);

        System.out.println("document contains " + nodes.getLength() + " elements of type " + args[1]);
    } //main()
} //class DOMExample6

Angewendet auf die XML-Datei der erweiterte Projektverwaltung ergibt die Suche nach Elementen mit dem Namen Vorname ...

java DOMExample6 projektverwaltung-erweitert.xml Vorname

... folgende Ausgabe:

document contains 4 elements of type Vorname

DOM - Beispiel NodeList: Anzahl enthaltener Elemente zählen

In diesem Beispiel (aus der Praxis) soll eine statistische Aussage getroffen werden: Wie viele Fehlerspeicher sind für ein Steuergerät in einer XML-Datei definiert?

Für die Definition von Diagnosedaten für Steuergeräte existiert ein XML-Standard namens ODX . In diesem XML-Vokabular werden sogenannte Fehlerspeicher und Diagnosejobs definiert.

Eine Fehlerspeicher wird in ODX durch ein Element mit dem Namen DTC definiert. Möchte man wissen, wie viele Fehlerspeicher definiert sind, so benötigt man die Anzahl der DTC -Elemente.

Diese werden analog zum vorherigen Beispiel durch die Methode getElementsByTagName in einer Knotenliste gesammelt. Die Länge der Knotenliste ergibt die Anzahl der enthaltenen DTC -Elemente.

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;

public class countDTCs {
    public static void main(String[] args) throws Exception {
     int numDTCs = 0;
     
     System.out.println("\nFiles to work on:" + args.length);
     for (int i=0; i<args.length; i++){
     File myFile = new File (args[i]);

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(myFile);

        Element theRootElement = document.getDocumentElement();   
        
        NodeList DTCNodeList = theRootElement.getElementsByTagName("DTC");
        System.out.println("File " + myFile.getName() + " contains " + DTCNodeList.getLength() + " DTCs!");
        numDTCs = numDTCs + DTCNodeList.getLength();
     } // for
     
     System.out.println("\nAll Files together contain " + numDTCs + " DTCs.");
     
    } //main()
} //class countDTCs
Files to work on:20
File ECU0.odx-d contains 0 DTCs!
File ECU1.odx-d contains 65 DTCs!
File ECU2.odx-d contains 83 DTCs!
File ECU3.odx-d contains 0 DTCs!
File ECU4.odx-d contains 0 DTCs!
File ECU5.odx-d contains 0 DTCs!
File ECU6.odx-d contains 20 DTCs!
File ECU7.odx-d contains 36 DTCs!
File ECU8.odx-d contains 28 DTCs!
File ECU9.odx-d contains 6 DTCs!
File ECU10.odx-d contains 99 DTCs!
File ECU11.odx-d contains 18 DTCs!
File ECU12.odx-d contains 101 DTCs!
File ECU13.odx-d contains 64 DTCs!
File ECU14.odx-d contains 133 DTCs!
File ECU15.odx-d contains 10 DTCs!
File ECU16.odx-d contains 1 DTCs!
File ECU17.odx-d contains 43 DTCs!
File ECU18.odx-d contains 65 DTCs!
File ECU19.odx-d contains 30 DTCs!

All Files together contain 802 DTCs.

Die grundlegenden DOM-Schnittstellen - Attr

Die Schnittstelle Attr erweitert Node. Sie steht für ein Attribut eines Elements. Objekte vom Typ Attr erben von Node . Dabei wird Node um drei Attribute zur Abbildung der Charakteristika eines XML-Attributs erweitert.

DOM betrachtet Attribute eher als Eigenschaften von Elementen denn als eigenständige Objekte mit einer eigenen Identität. Sie werden in DOM demnach nicht als Kindknoten des Elements betrachtet, das sie beschreiben. Attribute werden werden von DOM nicht als Teil des Dokumentbaums gesehen. Die Eigenschaften parentNode , previousSibling und nextSibling sind für Attr -Objekte nicht definiert und haben den Nullwert.

In DOM werden alle Attributwerte als einfache Zeichenketten dargestellt, auch wenn eine DTD oder ein Schema sie als einem bestimmten Typ zugehörig (z.B. als Token) definiert.

interface Attr : Node {
  readonly attribute DOMString       name;
  readonly attribute boolean         specified;
           attribute DOMString       value;
                                        // raises(DOMException) on setting

  // Introduced in DOM Level 2:
  readonly attribute Element         ownerElement;
  // Introduced in DOM Level 3:
  readonly attribute TypeInfo        schemaTypeInfo;
  readonly attribute boolean         isId;
};

Die Attribut-spezifischen Eigenschaften werden durch den Attributnamen ( name ) und seinen Wert ( value ) abgebildet.
Ferner ist verfügbar, ob es sich um ein im eingelesenen Quelldokument auftretendes Attribut handelt ( specified hat den Wert true ), oder durch den Parser der in der DTD oder dem Schema festgelegte Vorgabewert geliefert wird. schemaTypeInfo liefert Information über den Typ, der mit dem Attribut verbunden ist. Einen Verweis auf das umgebende Element liefert das Attribut ownerElement .

DOM - Beispiel: Zugriff auf Attributinformation

Im folgenden Codebeispiel sollen verschiedene Informationen, die in Form von Attributen vorliegen, ermittelt werden. Als Eingabe dient eine um die DOCTYPE-Deklaration erweiterte Variante der Projektverwaltung.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ProjektVerwaltung SYSTEM "projektverwaltung.dtd">
<ProjektVerwaltung>
 <Person PersID="Pers01" mitarbeitInProjekt="Prj01">
  <Vorname>Hans</Vorname>
  <Nachname>Hinterhuber</Nachname>
 </Person>
 <Person PersID="Pers02" mitarbeitInProjekt="Prj02">
  <Vorname>Franz</Vorname>
  <Vorname>Xaver</Vorname>
  <Nachname>Obermüller</Nachname>
  <Qualifikationsprofil>
     IT-Kompetenz verschiedene Betriebssysteme und <Leistungsstufe>professionelle</Leistungsstufe>
   <Qualifikation>Programmierung</Qualifikation> verschiedener Programmiersprachen
     <Qualifikation>Entwickler</Qualifikation> von 1988-1990
     <Qualifikation>Projektleiterfunktion</Qualifikation> von 1990-93 im X42-Projekt in Abteilung AB&amp;C
   </Qualifikationsprofil>
 </Person>
 <Person PersID="Pers03" mitarbeitInProjekt="Prj02">
  <Vorname>Fritz</Vorname>
  <Nachname>Meier</Nachname>
 </Person>
 <Projekt ID="Prj01" Projektleiter="Pers01" Mitarbeiter="Pers01"/>
 <Projekt ID="Prj02" Projektleiter="Pers02" Mitarbeiter="Pers03"/>
</ProjektVerwaltung>

Zunächst werden alle Elemente des Typs Projekt in einer NodeList zusammengestellt.

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(args[0]);

        Element theRootElement = document.getDocumentElement();

        NodeList projects = theRootElement.getElementsByTagName("Projekt");

Danach werden alle Elemente der Knotenmenge durchlaufen, und im Falle der Existenz (geprüft mit hasAttributes) verschiedene Charakteristika des Attributs ausgegeben.

        for (int i = 0; i < projects.getLength(); i++) {
            Element theElement;
            if ((theElement = (Element) projects.item(i)).hasAttributes()) {
                Attr theAttribute = theElement.getAttributeNode("ID");
                System.out.println("Attribute: " + theAttribute.getName());
                System.out.println("value=" + theAttribute.getValue());
                System.out.println("specified=" + theAttribute.getSpecified());

                theAttribute = theElement.getAttributeNode("budget");
                System.out.println("Attribute: " + theAttribute.getName());
                System.out.println("value=" + theAttribute.getValue());
                System.out.println("specified=" + theAttribute.getSpecified());
            }//if
        }//for

Ein Aufruf ergibt folgendes Ergebnis:

Attribute: ID
value=Prj01
specified=true
Attribute: budget
value=10000
specified=false
Attribute: ID
value=Prj02
specified=true
Attribute: budget
value=10000
specified=false

Die Auswertungen zum ID-Attribut sind direkt aus dem XML-Eingabedokument ersichtlich.

Woher jedoch kommen die Werte für das Attribut budget (Auflösung mit Taste n )?

Der XML-Prozessor erhält seine Informationen über budget aus der referenzierten Dokument Typ Deklaration. In ihr ist das Attribut mit dem Vorgabwert 10.000 definiert. Dieser Wert wird an die Applikation zurückgegeben, wenn keine andere Belegung im Dokument gefunden wird. Dies ist für beide Projekt -Elemente der Fall. Verfügt das Eingabedokument über keine DOCTYPE-Deklaration, so kann diese Information nicht ausgewertet werden.

Die grundlegenden DOM-Schnittstellen - Processing Instruction

Die Schnittstelle ProcessingInstruction steht für eine processing instruction , wie sie in XML verwendet wird, um dem verarbeitenden Prozessor Hinweise zur Verarbeitung des XML-Dokuments zu übergeben.
Der Inhalt einer processing instruction wird keiner Prüfung unterzogen.
Die Processing Instruction enthält folgende zwei Eigenschaften:

interface ProcessingInstruction : Node {
  readonly attribute DOMString       target;
           attribute DOMString       data;
                                        // raises(DOMException) on setting

};

target : Der Name des Prozessors / der Applikation, die die Processing Instruction berücksichtigen soll.

data : der Inhalt der Processing Instruction.

Die grundlegenden DOM-Schnittstellen - Character Data

Die Schnittstelle CharacterData erweitert Node um eine Reihe von Attributen und Methoden, mit denen auf Zeichendaten in DOM zugegriffen werden kann. Es gibt kein DOM Objekt, das direkt dieser Schnittstelle entspricht. Es handelt sich hierbei vielmehr um eine Sammlung von Methoden und Attribute, die ansonsten für jedes Objekt, das diese Schnittstelle erweitert (z.B. Text , neu definiert werden hätten müssen.

interface CharacterData : Node {
           attribute DOMString       data;
                                        // raises(DOMException) on setting
                                        // raises(DOMException) on retrieval

  readonly attribute unsigned long   length;
  DOMString          substringData(in unsigned long offset, 
                                   in unsigned long count)
                                        raises(DOMException);
  void               appendData(in DOMString arg)
                                        raises(DOMException);
  void               insertData(in unsigned long offset, 
                                in DOMString arg)
                                        raises(DOMException);
  void               deleteData(in unsigned long offset, 
                                in unsigned long count)
                                        raises(DOMException);
  void               replaceData(in unsigned long offset, 
                                 in unsigned long count, 
                                 in DOMString arg)
                                        raises(DOMException);
};

data : Die Zeichendaten des Knotens als DOMString Datentyp. The DOM implementation may not put arbitrary limits on the amount of data that may be stored in a CharacterData node. However, implementation limits may mean that the entirety of a node's data may not fit into a single DOMString. In such cases, the user may call substringData to retrieve the data in appropriately sized pieces.

length : Gibt die Anzahl der 16-bit Einheiten an, die über die Methoden data und substringData verfügbar sind. Leere Zeichenketten liefern den Wert 0 .

appendData : dient dazu, den übergebenen String and Ende der Daten des Knotens anzuhängen. Bei Erfolg, kann mit data auf die so zusammengefügte Zeichenkette zugegriffen werden.

deleteData : Entfernt einen Bereich von 16-bit Einheiten vom Knoten.

insertData : Fügt einen String am angegebenen Ort ein.

replaceData : Ersetzt die Zeichen am angegebenen Ort durch die übergebene Zeichenkette.

substringData : Liefert einen Teilstring aus dem angegebenen Bereich zurück.

Die grundlegenden DOM-Schnittstellen - Text

Die Schnittstelle Text erweitert CharacterData . Sie steht für textuellen Inhalt von ELementen oder Attributen.

Wenn innerhalb eines Elements kein Markup vorkommt, ist der enthaltene Text in einem einzigen Objekt vom Typ Text enthalten. Dieses Objekt ist das einzige Kind des Elements.

Andernfalls wird das enthaltene Markup analysiert und entsprechende Knoten (Elemente, Attribute, Kommentare, Text) als Kindknoten des Elements erzeugt.

Zusätzlich zu den in CharacterData bereits definierten Attributen und Methoden definiert Text folgende:

interface Text : CharacterData {
  // Introduced in DOM Level 3:
  readonly attribute boolean         isElementContentWhitespace;
  // Introduced in DOM Level 3:
  readonly attribute DOMString       wholeText;

  Text               splitText(in unsigned long offset)
                                        raises(DOMException);
  // Introduced in DOM Level 3:
  Text               replaceWholeText(in DOMString content)
                                        raises(DOMException);
};

isElementContentWhitespace : Gibt zurück, ob dieser Textkniten Leerzeichen enthält, der ignoriert werden kann.

wholeText :Gibt den Text all der Textknoten zurück, die vom aktuellen Knoten aus besucht werden können, ohne die Grenzen von Elementmarkup, Kommentaren oder Processing Instructions zu überschreiten.

        String myStr = contentNode.getWholeText();
        System.out.println("Content of TextNode is: " + myStr);

replaceWholeText : Ersetzt den Text des aktuellen Knotens, der vom aktuellen Knoten aus besucht werden kann, ohne die Grenzen von Elementmarkup, Kommentaren oder Processing Instructions zu überschreiten.

        contentNode = contentNode.replaceWholeText("yo");

splitText : Spaltet den Knoten an der angegebenen Position in zwei Geschwisterknoten auf.

DOM - Beispiel Textknotenverarbeitung

Das hier vorgestellte Beispiel versammelt Zugriff auf alle vorgestellten Methoden zur Textknotenverarbeitung.

Es extrahiert zunächst alle Paragraphen p (in denen üblicherweise Textinhalt steht) aus dem Eingabedokument. Die weitere Textverarbeitung findet dann aus Gründen der Einfachheit auf dem Inhalt des ersten extrahierten Paragraphen statt.

Es werden zuerst einige Statistiken zum textuellen Inhalt auf stdout ausgegegeben, bevor der Text zum besseren Verständnis dieser ermittelten Statistiken zeichenweise ausgegeben wird.

Im Anschluß wird der Textinhalt des einen Knotens auf zwei Textknoten aufgeteilt, um danach durch neuen Text ersetzt zu werden.

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

public class DOMText {
    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(args[0]);

        Element theRootElement = document.getDocumentElement();   
        NodeList paragraphs = theRootElement.getElementsByTagName("p");
        Element theElement = (Element) paragraphs.item(0);
        NodeList elemContent = theElement.getChildNodes();
        System.out.println("Nodelist of Element Content has " + elemContent.getLength() + " items");
        Text contentNode = (Text) elemContent.item(0); 
        System.out.println("Name of Node is: " + contentNode.getNodeName());
        System.out.println("Node is of Type " + contentNode.getNodeType());
        System.out.println("Length of Text is: " + contentNode.getLength());
        
        String myStr = contentNode.getWholeText();
        System.out.println("Content of TextNode is: " + myStr);

        for (int i=0; i< contentNode.getLength(); i++) {
         System.out.println("Text at position " + i + " : " + contentNode.substringData(i,1)  );
        }        
        
        Text newcontentNode = contentNode.splitText(contentNode.getLength()/2);
        String newStr = newcontentNode.getData();
        String oldStr = contentNode.getData();
        System.out.println("Content of Text Node #1 is: " + oldStr);
        System.out.println("Content of Text Node #2 is: " + newStr);
        System.out.println("getWholeText() gets data from ALL nodes: " + newcontentNode.getWholeText());
        
        contentNode = contentNode.replaceWholeText("yo");
        System.out.println ("Content of Node after text replacement is: " + contentNode.getWholeText());

    } //main()
} //class DOMText

Angewendet auf folgendes Eingabedokument...

<test>
 <p>
  bar
  &amp;
  foo
 </p>
</test>

... ergibt sich folgende Ausgabe:

Nodelist of Element Content has 1 items
Name of Node is: #text
Node is of Type 3
Length of Text is: 18
Content of TextNode is: 
  bar
  &
  foo
 
Text at position 0 : 

Text at position 1 :  
Text at position 2 :  
Text at position 3 : b
Text at position 4 : a
Text at position 5 : r
Text at position 6 : 

Text at position 7 :  
Text at position 8 :  
Text at position 9 : &
Text at position 10 : 

Text at position 11 :  
Text at position 12 :  
Text at position 13 : f
Text at position 14 : o
Text at position 15 : o
Text at position 16 : 

Text at position 17 :  
Content of Text Node #1 is: 
  bar
  
Content of Text Node #2 is: &
  foo
 
getWholeText() gets data from ALL nodes: 
  bar
  &
  foo
 
Content of Node after text replacement is: yo

DOM - abschließendes Beispiel - Erzeugen eines Dokuments im Hauptspeicher

Das abschließende Beispiel zeigt die Nutzung aller vorgestellten Schnittstellen zur Konstruktion eines neuen XML-Dokuments.

Folgendes Dokument soll komplett im Hauptspeicher erzeugt werden und danach über die Standardausgabe ausgegeben werden.

<?xml version="1.0"?>
<?myPI this is a test?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg">
   <head>
      <title>Testpage</title>
   </head>
   <body>
      <p>This is a <a href="http://www.barbara-zengler.de">link</a>

      <svg:svg width="4cm" height="8cm">
         <svg:ellipse cx="2cm" cy="4cm" rx="2cm" ry="1cm"/>
      </svg:svg>      
      </p>
   </body>
</html>

Zuerst wird ein Dokument erzeugt und die Processing Instruction als Kindelement an das Dokument hinzugefügt.

public class DOMFinalExample {
    public static void main(String[] args) throws Exception {
        // implementation specific part begins ...
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document myDocument = builder.newDocument();
        // ... ends

        myDocument.appendChild(myDocument.createProcessingInstruction("myPI", "this is a test"));

Danach wird das html -Element als Kindelement des Dokuments im korrekten Namensraum erzeugt sowie die beiden Attribute xmlns und xmlns:svg hinzugeügt.

        Element htmlElement = myDocument.createElementNS("http://www.w3.org/1999/xhtml", "html");
        //htmlElement.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
        htmlElement.setAttribute("xmlns:svg", "http://www.w3.org/2000/svg");

        myDocument.appendChild(htmlElement);

In einem nächsten Schritt werden head - und title -Element samt textuellem Inhalt erzeugt und an den jeweils korrekten Stellen in den Baum eingefügt.

        Element headElement = myDocument.createElementNS("http://www.w3.org/1999/xhtml", "head");
        htmlElement.appendChild(headElement);

        Element titleElement = myDocument.createElementNS("http://www.w3.org/1999/xhtml", "title");

        titleElement.appendChild(myDocument.createTextNode("Testpage"));

        headElement.appendChild(titleElement);

Analog zum head -Element wird das body -Element erzeugt und als Kindelement an das html -Element angehängt.

        Element bodyElement = myDOcument.createElementNS("http://www.w3.org/1999/xhtml", "body");
        htmlElement.appendChild(bodyElement);

Element p sowie dessen Kindelement a werden samt textuellem Inhalt erstellt und in die Dokumentstruktur eingebunden.

        Element pElement = (Element) bodyElement.appendChild((myDocument.createElementNS("http://www.w3.org/1999/xhtml", "p")));
        Element aElement = myDocument.createElementNS("http://www.w3.org/1999/xhtml", "a");
        aElement.setAttribute("href", "http://www.barbara-zengler.de");
        aElement.appendChild(myDocument.createTextNode("link"));

        pElement.appendChild(myDocument.createTextNode("This is a"));
        pElement.appendChild(aElement);

Schließlich wird das Element svg im Namensraum http://www.w3.org/2000/svg mit seinen Attributen width und height sowie dessen Kindelement ellipse mit Attributen erzeugt und in den Dokumentbaum eingehängt.

        Element svgElement = myDocument.createElementNS("http://www.w3.org/2000/svg", "svg:svg");
        pElement.appendChild(svgElement);
        svgElement.setAttribute("width", "4cm");
        svgElement.setAttribute("height", "8cm");

        Element ellipseElement = myDocument.createElementNS("http://www.w3.org/2000/svg", "svg:ellipse");
        ellipseElement.setAttribute("cx", "2cm");
        ellipseElement.setAttribute("cy", "4cm");
        ellipseElement.setAttribute("rx", "2cm");
        ellipseElement.setAttribute("ry", "1cm");

        svgElement.appendChild(ellipseElement);

In früheren DOM Spezifikationen wurden durch den Standard weder lesende Operationen definiert, noch die Möglichkeiten zum Schreiben der erstellen Objektstrukturen. Die hierfür notwendigen Operationen wurden in konkreten Implementierungen durch proprietären Code umgesetzt.
Im vorliegenden Beispiel wurde mit einer früheren Implementierung von SUNs JDK die dort vorgeschlagene (umständliche) Verfahrensweise genutzt: zur Ausgabe ein StreamResult-Objekt als Ergebnis der Dokumenttransformation mittels XSLT zu erzeugen. Dies funktioniert mit aktuellen JDK-Versionen nicht mehr.

Ein- und Ausgabe sind seit DOM Level 3 wesentlich einfacher gestaltet: DOM Load and Save .

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.OutputStream;
import java.io.FileOutputStream;

public class DOMFinalExample {
    public static void main(String[] args) throws Exception {
        // implementation specific part begins ...
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document myDocument = builder.newDocument();
        // ... ends

        myDocument.appendChild(myDocument.createProcessingInstruction("myPI", "this is a test"));

        Element htmlElement = myDocument.createElementNS("http://www.w3.org/1999/xhtml", "html");
        //htmlElement.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
        htmlElement.setAttribute("xmlns:svg", "http://www.w3.org/2000/svg");

        myDocument.appendChild(htmlElement);

        Element headElement = myDocument.createElementNS("http://www.w3.org/1999/xhtml", "head");
        htmlElement.appendChild(headElement);

        Element titleElement = myDocument.createElementNS("http://www.w3.org/1999/xhtml", "title");

        titleElement.appendChild(myDocument.createTextNode("Testpage"));

        headElement.appendChild(titleElement);
        
        Element bodyElement = myDOcument.createElementNS("http://www.w3.org/1999/xhtml", "body");
        htmlElement.appendChild(bodyElement);

        // this is the usual sequence ...
        Element pElement = (Element) bodyElement.appendChild((myDocument.createElementNS("http://www.w3.org/1999/xhtml", "p")));
        Element aElement = myDocument.createElementNS("http://www.w3.org/1999/xhtml", "a");
        aElement.setAttribute("href", "http://www.barbara-zengler.de");
        aElement.appendChild(myDocument.createTextNode("link"));

        pElement.appendChild(myDocument.createTextNode("This is a"));
        pElement.appendChild(aElement);

        Element svgElement = myDocument.createElementNS("http://www.w3.org/2000/svg", "svg:svg");
        pElement.appendChild(svgElement);
        svgElement.setAttribute("width", "4cm");
        svgElement.setAttribute("height", "8cm");

        Element ellipseElement = myDocument.createElementNS("http://www.w3.org/2000/svg", "svg:ellipse");
        ellipseElement.setAttribute("cx", "2cm");
        ellipseElement.setAttribute("cy", "4cm");
        ellipseElement.setAttribute("rx", "2cm");
        ellipseElement.setAttribute("ry", "1cm");

        svgElement.appendChild(ellipseElement);

        //Output - does not work anymore!
        //TransformerFactory transFactory = TransformerFactory.newInstance();
        //Transformer myTransformer = transFactory.newTransformer();
        //DOMSource src = new DOMSource(myDocument);
        //System.out.println(myDocument);
        //myTransformer.transform(src, new StreamResult());

    } //main()
} //class DOMFinalExample

Ausgabe mit DOM Level 3: Load and Save

Die Spezifikation DOM Level 3: Load and Save definiert eine plattform- und programmiersprachenunabhängige Schnittstelle zum Laden und Speichern von XML-Dokumenten. Sie beinhaltet das dynamische Laden eines Dokumentinhalts in ein DOM Dokument und umgekehrt die Serialisierung eines DOM Dokumentes in ein XML-Dokument. Softwareentwickler und Autoren von Webskripten können hiermit XML-Inhalt sehr komfortabel laden und speichern. Auch die Filterung des Inhalts während des Ladens und Speicherns ist möglich.

DOM Load and Save - die Schnittstellen

Folgende Schnittstellen werden in DOM Load and Save definiert

DOM Load and Save - die Datentypen

Folgende zu DOM Core zusätzlichen Datentypen werden in Load and Save definiert:

DOM Load and Save - die grundlegenden Schnittstellen

Die im folgenden besprochenen grundlegenden Schnittstellen müssen von zu DOM Load and Save konformen Modulen unterstützt werden.
Sie sind mit der Methode hasFeature mit den Parametern LS (für Load and Save ) und 3.0 (für DOM Level 3.0 )abfragbar.

Core supported
XML supported
HTML not supported
XPath not supported
Validation not supported
Events not supported
LS supported
Views not supported
Traversal not supported
LS-Async not supported
StyleSheets not supported
Range not supported
HTMLEvents not supported
MutationEvents not supported
UIEvents not supported
CSS not supported
MutationNameEvents not supported
CSS2 not supported
KeyboardEvents not supported
TextEvents not supported
MouseEvents not supported

DOM Load and Save - Fehlerbehandlung

Während Lese- oder Schreibvorgängen können Fehler auftreten, die dazu führen, daß die Verarbeitung nicht fortgesetzt werden kann. In diesem Fall tritt ein Fehler der Art LSException auf. Durch die Abfrage eines Integerwerts kann die Art des Fehler noch näher bestimmt werden:

DOM Load and Save - die Schnittstelle DOMImplementationLS

DOMImplementationLS enthält die Fabrikmethoden, um Parser, Serializer, sowie Input- und Outputobjekte aus Load and Save zu erzeugen.

interface DOMImplementationLS {

  // DOMImplementationLSMode
  const unsigned short      MODE_SYNCHRONOUS               = 1;
  const unsigned short      MODE_ASYNCHRONOUS              = 2;

  LSParser           createLSParser(in unsigned short mode, 
                                    in DOMString schemaType)
                                        raises(DOMException);
  LSSerializer       createLSSerializer();
  LSInput            createLSInput();
  LSOutput           createLSOutput();
};

Eine Instanz dieser Schnittstelle kann durch Aufruf der Methode DOMImplementation.getFeature("LS", "3.0") erhalten werden (sofern DOM Level 3 Core unterstützt wird) , oder alternativ durch Casten einer DOMImplementation -Instanz.

public class DOMImplementationExample {
 
    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        DOMImplementation implementation = builder.getDOMImplementation();
     DOMImplementationLS impLS = (DOMImplementationLS) implementation.getFeature("LS","3.0");

DOM Load and Save - Die Schnittstelle LSParser

Die Schnittstelle bietet die Möglichkeit, aus verschiedenen Eingabequellen einen DOM Baum zu erstellen.

Asynchrone LSParser bieten die Möglichkeit, Event Listener für Ereignisse zu registrieren. Sie implementieren die Schnittstelle EventTarget .
Folgende Ereignisse sind unterstützt:

DOM Load and Save - Die Schnittstelle LSParser - Attribute

interface LSParser {
  readonly attribute DOMConfiguration domConfig;
           attribute LSParserFilter   filter;
  readonly attribute boolean          async;
  readonly attribute boolean          busy;

DOM Load and Save - Die Schnittstelle LSParser - Operationen

  Document           parse(in LSInput input)
                                        raises(DOMException, 
                                               LSException);
  Document           parseURI(in DOMString uri)
                                        raises(DOMException, 
                                               LSException);
  void               abort();
  Node               parseWithContext(in LSInput input, 
                                      in Node contextArg, 
                                      in unsigned short action)
                                        raises(DOMException, 
                                               LSException);

DOM Load and Save - Beispiel: Datei per URI einlesen

Zunächst muß mit Hilfe der Methode DOMImplementationLS.createLSParser() eine Instanz eines LSParsers erzeugt werden.

        // obtain a parser instance and parse file given as argument on command line
        LSParser myParser = impLS.createLSParser((short) 1, null);

Mit der Methode parseURI kann ein Dokument eingelesen werden, z.B. auch eine durch Kommandozeile übergebene Datei.

        //LSParser myParser = impLS.createLSParser(MODE_SYNCHRONOUS, null);
        Document myFirstDocument = myParser.parseURI(args[0]);

DOM Load and Save - Die Schnittstelle LSInput

Die andere Alternative, ein Dokument einzulesen, ist über die Schnittstelle LSInput . Sie repräsentiert eine Eingabequelle für Daten.

Die Schnittstelle kapselt Information über die Informationsquelle, z.B. einen Public Identifier, einen System Identifier, einen Basis-URI, einen ByteStream und/oder einen CharacterStream.

Die Schnittstelle kann erzeugt werden, indem die Fabrikmethode createLSInput() auf die Schnittstelle DOMImplementationLS angewendet wird.

Mit LSInput ist ein Parser in der Lage, verschiedene Eingabequellen komfortabel einzulesen. Die Engabequellen können durch entsprechende set - Methoden auf der Schnittstelle angegeben werden. Sie werden in der angegebenen Reihenfolge ausgewertet:

interface LSInput {
  // Depending on the language binding in use,
  // this attribute may not be available.
           attribute LSReader        characterStream;
           attribute LSInputStream   byteStream;
           attribute DOMString       stringData;
           attribute DOMString       systemId;
           attribute DOMString       publicId;
           attribute DOMString       baseURI;
           attribute DOMString       encoding;
           attribute boolean         certifiedText;
};

Mit der Methode parse(LSInput input) wird schlußendlich die Eingabe durch den Parser verarbeitet.

        // obtain LSInput and read in file
        LSInput myInput = impLS.createLSInput();
        FileInputStream myFIS = new FileInputStream("namespace15-noBOM.xml");
        myInput.setByteStream(myFIS);
        Document mySecondDocument = myParser.parse(myInput);

DOM Load and Save - Die Schnittstelle LSSerializer

Der LSSerializer dient der Serialisierung (dem Schreiben) eines DOM Knotens, typischerweise eines ganzen Dokuments, nach XML. Die XML Daten werden dabei entweder in einen String oder in einen OutputStream geschrieben. Während der Serialisierung werden Namensräume insofern "korrigiert", daß der leere Namensraum (der prinzipiell in XML-Dokumenten vorkommen darf) nicht ausgegeben wird sowie Namensräume nach einem spezifizierten Algorithmus auf ihre Konsistenz geprüft und bei Bedarf korrigiert werden (vgl. Appendix B.1, "Namespace normalization", aus [DOM Level 3 Core]).

Das (konfigurierbare) Standardverhalten eines LSSerializers beinhaltet, daß für Dokumentknoten der XML-Prolog sowie das gesamte Dokument ausgegeben wird.
Für Dokumentteilbäume (Knotentyp DocumentFragment ) werden alle Kindknoten in der Reihenfolge ihres Auftretens ausgegeben.
Alle anderen Knotentypen werden in ihrer entsprechenden XML-Repräsentation ausgegeben.

interface LSSerializer {
  readonly attribute DOMConfiguration domConfig;
           attribute DOMString       newLine;
           attribute LSSerializerFilter filter;
  boolean            write(in Node nodeArg, 
                           in LSOutput destination)
                                        raises(LSException);
  boolean            writeToURI(in Node nodeArg, 
                                in DOMString uri)
                                        raises(LSException);
  DOMString          writeToString(in Node nodeArg)
                                        raises(DOMException, 
                                               LSException);
};

Hinweis: Die Serialisierung von Knoten erzeugt nicht immer wohlgeformtes XML!

Im nachfolgenden Beispiel werden zwei Serializer für zwei Dokumente erzeugt. Dabei wird jeweils der Dokumentknoten mit Hilfe der Methode writeToString serialisiert. Das erste Dokument wird mit System.out.println direkt auf die Standardausgabe ausgegeben. Das zweite Dokument wird zunächst in der Variable outStr vom Typ String gespeichert.

        // create a Serializer and print first document on stdout
        LSSerializer myFirstSerializer = impLS.createLSSerializer();
        System.out.println(myFirstSerializer.writeToString(myFirstDocument));
        
        // create a Serializer for second document
        LSSerializer mySecondSerializer = impLS.createLSSerializer();        
        String outStr = mySecondSerializer.writeToString(mySecondDocument);

DOM Load and Save - Die Schnittstelle LSOutput

LSOutput repräsentiert (und kapselt) ein Ausgabeziel für Daten, z.B. eine URI, einen ByteStream, eine Basis-URI und/oder einen CharacterStream.

Die Schnittstelle kann erzeugt werden, indem die Fabrikmethode createLSOutput() auf die Schnittstelle DOMImplementationLS angewendet wird.

Mit LSOutput ist ein Parser in der Lage, verschiedene Ausgabequellen komfortabel zu verwenden. Die Ausgabequellen können durch entsprechende set - Methoden auf der Schnittstelle angegeben werden. Sie werden in der angegebenen Reihenfolge ausgewertet:

Im nachfolgenden Codeauszug werden Daten in eine Datei ausgegeben. Dazu wird ein FileOutputStream erzeugt und dieser durch setByteStream mit LSOutput verbunden.

        // Obtain LSOutput
        LSOutput myOutput = impLS.createLSOutput();
        FileOutputStream myFOS = new FileOutputStream("DOMImplementationExampleOutput.xml");
        myOutput.setByteStream(myFOS);
        myFOS.write(outStr.getBytes());

DOM Load and Save - Das komplette Beispiel

Im nachfolgenden Beispiel ist die Verwendung aller Schnittstellen aus DOM Load and Save demonstriert.

import org.w3c.dom.DOMImplementation;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSParser;
import org.w3c.dom.ls.LSInput;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;
import org.w3c.dom.Document;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;


public class DOMImplementationExample {
 
    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        DOMImplementation implementation = builder.getDOMImplementation();
     DOMImplementationLS impLS = (DOMImplementationLS) implementation.getFeature("LS","3.0");

        // obtain a parser instance and parse file given as argument on command line
        LSParser myParser = impLS.createLSParser((short) 1, null);
        //LSParser myParser = impLS.createLSParser(MODE_SYNCHRONOUS, null);
        Document myFirstDocument = myParser.parseURI(args[0]);

        // obtain LSInput and read in file
        LSInput myInput = impLS.createLSInput();
        FileInputStream myFIS = new FileInputStream("namespace15-noBOM.xml");
        myInput.setByteStream(myFIS);
        Document mySecondDocument = myParser.parse(myInput);
        
        // create a Serializer and print first document on stdout
        LSSerializer myFirstSerializer = impLS.createLSSerializer();
        System.out.println(myFirstSerializer.writeToString(myFirstDocument));
        
        // create a Serializer for second document
        LSSerializer mySecondSerializer = impLS.createLSSerializer();        
        String outStr = mySecondSerializer.writeToString(mySecondDocument);
        
        // Obtain LSOutput
        LSOutput myOutput = impLS.createLSOutput();
        FileOutputStream myFOS = new FileOutputStream("DOMImplementationExampleOutput.xml");
        myOutput.setByteStream(myFOS);
        myFOS.write(outStr.getBytes());
        
    }
 
} // end DOMImplementationExample

Ein Aufruf des Beispiels ...

java DOMImplementationExample erstes-XML-dokument.xml

... ergibt folgendes Ausgabe auf stdout :

㰿硭氠癥牳楯渽∱⸰∠敮捯摩湧㴢啔䘭ㄶ∿㸊㱖潲汥獵湧㸊†㱐晬楣桴晡捨⼾ਠ‼䡯捨獣桵汥㹆慣桨潣桳捨畬攠䅵杳扵牧㰯䡯捨獣桵汥㸊†㱓瑵摩敮条湧⁳敭敳瑥爽∳∾䥁䴼⽓瑵摩敮条湧㸊†㱔楴敬㹘䵌㰯呩瑥氾ਠ‼卥浥獴敲㹗匠㈰〸⼲〰㤼⽓敭敳瑥爾ਠ⁍潮瑡本‰㠺〰栠ⴠ〹㨳とਠ‼偲慫瑩歵派卥浩湡爼⽐牡歴楫畭㸊㰯噯牬敳畮朾

Zusätzlich wird die Datei DOMImplementationExampleOutput.xml erzeugt und mit dem Inhalt der zweiten eingelesenen Datei befüllt.

DOM Load and Save - Abschließendes Beispiel

Das nach DOM LS einführende Beispiel (im Hauptspeicher erzeugtes Dokument) soll hier nochmals aufgeführt und mit DOM LS ausgegeben werden.

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.OutputStream;
import java.io.FileOutputStream;
import org.w3c.dom.ls.LSSerializer;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;

public class DOMFinalExample_LS {
    public static void main(String[] args) throws Exception {
        // implementation specific part begins ...
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document myDocument = builder.newDocument();
        DOMImplementation implementation = builder.getDOMImplementation();
     DOMImplementationLS impLS = (DOMImplementationLS) implementation.getFeature("LS","3.0");        
        // ... ends

        myDocument.appendChild(myDocument.createProcessingInstruction("myPI", "this is a test"));

        Element htmlElement = myDocument.createElementNS("http://www.w3.org/1999/xhtml", "html");
        //htmlElement.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
        htmlElement.setAttribute("xmlns:svg", "http://www.w3.org/2000/svg");

        myDocument.appendChild(htmlElement);

        Element headElement = myDocument.createElementNS("http://www.w3.org/1999/xhtml", "head");
        htmlElement.appendChild(headElement);

        Element titleElement = myDocument.createElementNS("http://www.w3.org/1999/xhtml", "title");

        titleElement.appendChild(myDocument.createTextNode("Testpage"));

        headElement.appendChild(titleElement);
        
        Element bodyElement = myDocument.createElementNS("http://www.w3.org/1999/xhtml", "body");
        htmlElement.appendChild(bodyElement);

        // this is the usual sequence ...
        Element pElement = (Element) bodyElement.appendChild((myDocument.createElementNS("http://www.w3.org/1999/xhtml", "p")));
        Element aElement = myDocument.createElementNS("http://www.w3.org/1999/xhtml", "a");
        aElement.setAttribute("href", "http://www.barbara-zengler.de");
        aElement.appendChild(myDocument.createTextNode("link"));

        pElement.appendChild(myDocument.createTextNode("This is a"));
        pElement.appendChild(aElement);

        Element svgElement = myDocument.createElementNS("http://www.w3.org/2000/svg", "svg:svg");
        pElement.appendChild(svgElement);
        svgElement.setAttribute("width", "4cm");
        svgElement.setAttribute("height", "8cm");

        Element ellipseElement = myDocument.createElementNS("http://www.w3.org/2000/svg", "svg:ellipse");
        ellipseElement.setAttribute("cx", "2cm");
        ellipseElement.setAttribute("cy", "4cm");
        ellipseElement.setAttribute("rx", "2cm");
        ellipseElement.setAttribute("ry", "1cm");

        svgElement.appendChild(ellipseElement);

        // Output via DOM Load and Save
        // Serialize Document into String
        LSSerializer mySerializer = impLS.createLSSerializer();        
        String outStr = mySerializer.writeToString(myDocument);
        // Output on stdout
        System.out.println(outStr);
        
        // In addition, output into file
        LSOutput myOutput = impLS.createLSOutput();
        FileOutputStream myFOS = new FileOutputStream("DOMFinalExample_LS_Output.xml");
        myOutput.setEncoding("UTF-8");
        myOutput.setByteStream(myFOS);
        mySerializer.write(myDocument, myOutput);
        
    } //main()
} //class DOMFinalExample_LS

Die Ausgabe erfolgt zunächst nach stdout sowie in eine Datei.

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg"><head><title>Testpage</title></head><body><p>This is a<a href="http://www.barbara-zengler.de">link</a><svg:svg xmlns:svg="http://www.w3.org/2000/svg" height="8cm" width="4cm"><svg:ellipse cx="2cm" cy="4cm" rx="2cm" ry="1cm"/></svg:svg></p></body></html><?myPI this is a test?>