Мир, соответствующий DOM, полностью отличается от SAX. Основа сущности DOM'а - это вывод из процесса синтаксического разбора. При использовании SAX наша программа реагировала на специфичные точки в процессе разбора, при использовании DOM данные не могут использоваться до тех пор, пока не будет разобран весь документ. Вывод из синтаксического анализатора DOM предназначен для использования с интерфейсом DOM, определенном в объекте org.w3c.dom.Document. К этому объекту документа применим формат дерева, которое строится на интерфейсе DOM org.w3c.dom.Node. Наследуя от этого интерфейса, DOM предоставляет несколько специфичных для XML интерфейсов - Element, Document, Attr и Text. Ваше приложение, ориентированное на DOM, теперь может перемещать и манипулировать различными аспектами дерева.

Прежде, чем вдаваться в подробности, вы должны немного узнать об эволюции DOM'а. Первая версия DOM'а не имела официальной спецификации, была только объектная модель, которую реализовывали Navigator 3 и Explorer 3 в своих браузерах. Конечно же, эти объектные модели не были полностью законченными, так что я считаю, что в этом случае применим термин DOM Level 0.

DOM Level 1 является попыткой получить совместимость некоторого уровня между браузерами. Необходимо было быстро создать Level 1, прежде чем разные стороны пойдут по противоположным направлениям. Получив такие ограничения, DOM Level 1 был на удивление хорошей спецификацией и охватывал большинство нужд программистов для обработки XML.

DOM Level 2 произвел чистку интерфейсов DOM Level 1. Была добавлена поддержка пространства имен в интерфейсы Element и Attr, и было добавлено некоторое количество поддерживаемых интерфейсов для событий, пересечений, границ, представления и страниц стилей. В настоящее время (2002), все главные синтаксические анализаторы XML поддерживают DOM Level 2 и это должно быть вашим стандартом кодирования.

Скоро выйдет DOM Level 3. Xerces 2 начал поддерживать частично DOM Level 3. DOM 3 будет предоставлять независимые от синтаксического анализатора методы для создания нового объекта Document либо посредством синтаксического разбора файла, либо путем построения черновой формы в памяти. DOM 3 добавит поддержку DTD и Схем. Таким образом, DOM 3 добавит новую функциональность, а ваш код DOM 2 должен продолжать работать.

Вот пример NodeWalker.java, который использует DOM:

import org.apache.xerces.parsers.DOMParser;

import org.w3c.dom.*;

public class NodeWalker {
  
static String outStr [] = new String [ 250 ] ;
  
static int lineNum = 0 ;
  
  
static public void main ( String [] argv ) {
     
try {
        
// Xerces Parser
        
DOMParser parser = new DOMParser () ;
         parser.parse
( argv [ 0 ]) ;
         Document doc = parser.getDocument
() ;
         walker
( doc.getDocumentElement ()) ;
     
}
     
catch ( Exception e ) {
        
e.printStackTrace ( System.err ) ;
     
}
     
// output
     
System.out.println ( "Num of line:" + lineNum ) ;
     
for ( int i = 0 ; i < lineNum; i++ ) {
        
System.out.println ( outStr [ i ]) ;
     
}
   }
  
  
public static void walker ( Node node ) {
     
if ( node == null ) {
        
return ;
     
}
     
int type = node.getNodeType () ;
     
switch ( type ) {
     
case Node.ELEMENT_NODE: {
        
// Name of this node
        
outStr [ lineNum ] = node.getNodeName () ;
         lineNum++;
        
// attributes of this node
        
int length = ( node.getAttributes () != null ) ? node.getAttributes ()
              
.getLength () : 0 ;
        
for ( int i = 0 ; i < length; i++ ) {
           
Attr attrib = ( Attr ) node.getAttributes () .item ( i ) ;
            outStr
[ lineNum ] = attrib.getNodeName () ;
            lineNum++;
        
}
        
// children of this node
        
NodeList children = node.getChildNodes () ;
        
if ( children != null ) {
           
length = children.getLength () ;
           
for ( int i = 0 ; i < length; i++ ) {
              
walker ( children.item ( i )) ;
           
}
         }
        
break ;
     
}
     
case Node.TEXT_NODE: {
        
String str = node.getNodeValue () .trim () ;
        
if ( str.indexOf ( "n" ) < 0 && str.length () > 0 ) {
           
outStr [ lineNum ] = str;
            lineNum++;
        
}
        
break ;
     
}
      }
   }
}

Обратите внимание, что метод parse( ) возвращает void. Эти изменения позволяют приложению использовать класс синтаксического анализатора DOM и класс синтаксического анализатора SAX поочередно. Однако для этого требуются дополнительные методы для получения результирующего объекта Document после XML разбора. В случае Apache Xerces такой метод называется getDocument( ).

Метод разбора транслирует поток символов из XML файла в поток признаков. Эти признаки строятся во временную структуру в памяти, программа может переносить ее и манипулировать ей. DOM является API для XML документа. Оно предполагается как объектно-ориентированное представление XML документа, в отличие от абстрактного представления типов данных. Это значит, что каждый компонент документа определен в виде интерфейса, указывающего его поведение. Данные могут быть доступны только через интерфейс. DOM определяет интерфейс Node, а интерфейсы подклассов Element, Attribute и CharacterData наследуются от Node. NodeWalker просто переключает Node.ELEMENT_NODE и Node.TEXT_NODE, мы можем добавить другие узлы, включая CDATA_SECTION и PROCESSING_INSTRUCTION_NODE. Интерфейс Node определяет методы для доступа к компонентам узла. Например, parentNode( ) возвращает родительский узел; childNodes( ) возвращает множество детей. Кроме того, существуют методы для изменения узлов и для создания новых узлов. Поэтому приложение может полностью реструктуризировать документ с помощью DOM.

Интерфейс Document базируется на интерфейсе Node, который поддерживает объект W3C Node. Узлы представляют единичные узлы дерева документа и все, что встречается - текст, комментарии и теги - трактуются как узлы. Интерфейс узла имеет все методы, которые вы можете использовать для работы с узлами и для перемещения по DOM'у. Давайте взглянем на следующий код из примера:

  for ( Node node =
           doc.getDocumentElement
() .getFirstChild () ;
           node !=
null ;
           node = node.getNextSibling
()) {

Этот цикл for начинает свою работу с использования метода интерфейса документа getDocumentElement( ) для получения корневого узла документа. Метод getFirstChild( ) интерфейса узла возвращает узел первого дочернего элемента для корня. До тех пор, пока не будет получено значение null, цикл for продолжит движение. Узлы инкрементируются посредством метода getNextSibling( ), который возвращает узел, следующий за вызываемым.