Язык XML - практическое введение


DOM совместимые анализаторы

   Другим способом представления внутренней структуры документа являются DOM - интерфейсы. Как уже упоминалось, их реализацией занимаются разработчики XML-анализатора, используя для этого возможности конкретного языка программирования. Программисты на Java могут найти эти классы в библиотеке org.w3.dom. Наследуя виртуальные методы DOM интерфейсов, классы анализатора предоставляют приложению стандартный способ манипулирования структурой документа. В свою очередь, приложение, использующее XML-анализатор, может не знать о способе реализации интерфейсов, ему доступна готовая библиотека методов, при помощи которой он может производить поиск нужных фрагментов документа, создавать, удалять и модифицировать его элементы.

   Одним из доступных на сегодня DOM-совместимых наборов классов для работы с документами является библиотека com.ibm.dom, входящая в состав XML анализатора xml4j от IBM. Получить ее можно по адресу www.alphaworks.ibm.com. Принцип использования DOM интерфесов по сравнению с IE5 практически не изменился - поменялись только названия объектов и методов. Их краткий обзор представлен в следующей таблице.

   

Node

Базовый интерфейс для остальных элементов объектной модели XML, представляющий узел дерева структуры документа.

Document

Используется для получения информации о документе и изменения его структуры. Это интерфейс представляет собой корневой элемент XML документа и содержит методы доступа ко всему содержимому документа. При помощи методов объекта Document в программе можно создавать дочерние объекты, представляющие различные конструкции документа (например, createElement - создание элемента, createComment - создание комментария, createTextNode - текстового фрагмента), удалять, перемещать, добавлять объекты (removeChild, replaceChild, insertBefore, ...), перемещаться по дереву элементов(getFirstChild, getLastChild, getNextSibling, getParentNode, getPreviousSibling, ...), получать элементы по их названию (getElementsByTagName, :) и т.д. В объектной модели IE5 этот интерфейс доступен для сценариев на JScript, VB через объект XMLDOMDocument

Element

Представляет элемент документа, определяя методы доступа к его названию(getTagName, getElementsByTagName), атрибутам (getAttribute, getAttributeNode, setAttribute, removeAttribute, : ) и дочерним элементам(appendChild, getChildNodes, getFirstChild, ...).

Attr

Интерфейс, представляющий атрибут элемента. Имеет методы для получения(getValue) и установления(setValue) значения атрибута. Хотя согласно синтаксису XML атрибуты должны назначаться только элементам, в DOM возможно их создание любым объектом, наследующим интерфейс Node. Поэтому можно создать атрибут для документа, который будет находится в списке атрибутов, но не принадлежать ни одному из его элементов.

CharacterData

Интерфейс, предоставляющий доступ к текстовым данным документа. В XML документе к этому типу данных относятся комментарии, текстовое содержимое элементов, секции CDATA. При помощи методов этого интерфейса можно добавлять, удалять, редактировать данные(appendData, deleteData, replaceData, setData), получать размер области текста (getLength) и извлекать текстовое содержимое(getData, substringData, ...)

Comments

Интерфейс для доступа к тексту комментариев

Text

Представляет текстовое содержимое элемента

CDATASection

Интерфейс, представляющий секции CDATA - фрагментов документа, заключенные в символы "[[" и "]]>", которые не обрабатываются XML-анализатором и поэтому могут содержать символы, "запрешенные" в спецификации XML. В эту область можно, к примеру, помещать стилевые таблицы или JavaScript сценарии, используемые при отображении HTML страницы.

ProcessingInstruction

Предоставляет доступ к т.н. области "инструкций процессора", данные из которой используются XML-анализатором при разборе документа. Доступ к этим данным возможен при помощи методо getData, setData и getTarget

Notation

Определяет инструкцию DTD описания. Для получения ее идентификаторов используются методы getPublicId и getSystemId . DOM Level 1 не поддерживает прямого доступа к DTD декларациям по записи и сейчас они доступны лишь для чтения (при помощи параметра nodeName интерфейса Node)

   В следующем примере демонстрируется использование DOM-объектов для вывода содержимого XML документа в двух форматах - в виде дерева элементов и обычной HTML страницы. Немного изменив пример, можно заставить программу сохранять выходной формат в файле и мы получим таким образом обычный XML-HTML конвертор.

/*
Пример использования DOM анализатора.
Демонстрируется возможность рекурсивного обхода дерева элементов,
создание новых элементов, фильтрация элементов (поиска по параметрам)
*/

import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.*;

import org.w3c.dom.*;

import org.xml.sax.Parser;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.ParserFactory;

import com.ibm.xml.parsers.DOMParser;

public class logParser {

    static String defaultParser =
	 "com.ibm.xml.parsers.DOMParser";
    static String urlLog;
    static  Document xmldoc = null;
    static  PrintWriter out;

/* 
Конструктор нашего класса- обработчика. 
В нем создается выходной поток для печати 
*/
 
    public logParser(String url){
     urlLog = url;

       try {
            out = new PrintWriter
			(new OutputStreamWriter(System.out,
			 "koi8-r"));
        }
        catch (UnsupportedEncodingException e) {
         System.err.println(e.toString());
        }

    }

    public void parseDoc(){
     parseDoc(defaultParser);
    }

/* 
Создание класса анализатора, обрабтка им XML-документа 
и создание объектной модели документа
*/

    public void parseDoc(String parserName){
      
        try {
            Parser parser =
		ParserFactory.makeParser(parserName);
	    parser.parse(urlLog);

// Получение указателя на корневой элемент документа
            xmldoc = ((DOMParser)parser).getDocument();

        }
        catch (Exception e) {
         System.err.println(e.toString());          
        }   
    }

//=================================================
// Вывод содержимого документа в виде форматированного 
списка XML- элементов 
//========================
            
                    
    public void viewLogAsXML(){

        try {

	     viewLogAsXML(xmldoc,"");  

        }
        catch (Exception e) {
         System.out.println(e.toString());          
        }   
      out.flush();

    }

/* 
Рекурсивный обход элементов документа, начиная с указанного
элемента node.
*/

    public void viewLogAsXML(Node node,String offs){

        if (node == null) {
            return;
        }
        int type = node.getNodeType(); //
		 Получение информации о типе текущего узла
        switch (type) {
/* Если текщий узел - корневой элемент документа */

            case Node.DOCUMENT_NODE: {
                out.println("<?xml
				 version=\"1.0\"
				 encoding=\"koi-8\"?>");
                viewLogAsXML(((Document)node).
				getDocumentElement(),offs);
                out.flush();
                break;
            }

/* Если текщий узел - элемент */

            case Node.ELEMENT_NODE: {
                out.print(offs+"<");
// Печать названия элемента 
                out.print(node.getNodeName());
// Получение списка атрибутов текущего элемента

                NamedNodeMap attrs = node.getAttributes();
		Node attr;
                for (int i = 0; i <
				 attrs.getLength(); i++) {
                    attr = attrs.item(i);
                    out.print(' ');
                    
out.print(attr.getNodeName()+"=\""
+attr.getNodeValue()+"\"");
                }
                out.println('>');

// Получение списка дочерних элементов
                NodeList children = node.getChildNodes(); 

// Если у текщего элемента есть дочерние, то выводим и их

                if (children != null) {
                    int len = children.getLength();
                    for (int i = 0; i < len; i++) {
                        viewLogAsXML(children.item(i),
						offs+" ");
                    }
                }
                break;
            }   

/* Если текщий узел - текстовый */
            case Node.TEXT_NODE: {
                out.println(offs+node.getNodeValue());
                break;
            }
    
        }
// Печать закрывающего тэга элемента
        if (type == Node.ELEMENT_NODE) {
            out.print(offs+"</");
            out.print(node.getNodeName());
            out.println('>');
        }          
            
    }               


//===============================================
// Вывод в формате HTML
//=====================
 
/* Вызов рекурсивного обходчика */

    public void viewLog(){

// Header
        viewAsHTML("All log records:");

        try {

// Вывод содержимого
	     viewLog(null);

        }
        catch (Exception e) {
         System.out.println(e.toString());          
        }

// Header
        viewAsHTML();

    }


/* Печать только сообщений об ошибках */

    public void viewErrors(){

// Header
        viewAsHTML("Log errors:");

        try {
// Вывод содержимого
	     viewLog("error");
        }
        catch (Exception e) {
         System.out.println(e.toString());          
        }
// Footer
        viewAsHTML();

    }


/* 
Рекурсивный обход элементов, у которых 
атрибут type равен заданному. 
*/                         
                                        
    public int viewLog(String type){
        

        int i=0;
        int elemNum=0;
        int messageCount=0;
	Element elem;
	NodeList elements;

	elements = xmldoc.getElementsByTagName
	("event");
        if(elements==null) System.out.println
		("Empty element collection");

        elemNum = elements.getLength();

        if (type == null) {

            for (i = 0; i < elemNum; i++) {
	        if(elements.item(i)==null) 
			System.out.println
			("Empty element");
              viewLogMessage((Element)elements.item(i));
            }
            messageCount=elemNum;

        }
        else {
            for (i = 0; i < elemNum; i++) {
                elem = (Element)elements.item(i);

                if(elem.getAttribute
				("type")==type){
                 messageCount++;
                 viewLogMessage(elem);
                }

            }
        }
       return messageCount;
    }

/* Печать заголовка таблицы */

    public void viewAsHTML(String title){
        out.println("<html>");
        out.println("<head><title>
		Log parser
		 sample</title></head>");
        
out.println("<body><br><b>"
+title+"</b><hr>");
        out.println("<table cellspacing=\"2\" 
cellpadding=\"2\" border=\"1\" 
width=\"600\">");
        out.println("<tr 
bgcolor=\"silver\"><th>IP</th>
<th>Date</th><th>Method</th>
<th>Request</th><th>
Response</th></tr>");
    }

/* Печать комментариев к таблице */

    public void viewAsHTML(){
        Date d = new Date();
        String date = new 
String(""+d.getHours()+":"
+d.getMinutes()+":"+d.getSeconds());
        out.println("</table><hr>
		generated by logParser at 
<i>"+date+"</i><br>
</body></html>");
        out.flush();
    }

/* Форматированный вывод содержимого элемента event */

    public void viewLogMessage(Element elem){

      /* 
	 Получение текста внутри элемента - обращаемся
 к первому	 дочернему узлу (им должен оказаться текст)
 и получаем его	 значение, используя метод 
 getNodeValue() интерфейса Node 
      */

      String 
str_from=(elem.getElementsByTagName
("ip-from")).item(0)
    .getFirstChild().getNodeValue();
      String 
str_method=(elem.getElementsByTagName
("method")).item(0).
     getFirstChild().getNodeValue();
      String 
str_to=(elem.getElementsByTagName
("url-to")).item(0).
getFirstChild().getNodeValue();
      String 
str_result=(elem.getElementsByTagName
("response")).item(0).
getFirstChild().getNodeValue();

      
out.println("<tr><td>"+str_from
+"</td><td>"+elem.getAttribute
("date")+"</td><td>"
+str_method+"</td><td>"+str_to+"</td>
<td>"+str_result+"</td></tr>");

    }
                             

//=======================================================
// Модификация дерева элементов
//=============================

public void logMessage(String result, String datetime,
	 String method, String ipfrom, String urlto, 
	 String response){

      if(xmldoc==null) return;

      Element root = xmldoc.getDocumentElement();
      Element log_elem = xmldoc.createElement
	  ("event");
      log_elem.setAttribute("result",result);
      log_elem.setAttribute("date",datetime);

      Element elem;
      Text elem_value;

      elem = xmldoc.createElement("method");
      elem_value = xmldoc.createTextNode(method);
      elem.appendChild(elem_value);
      log_elem.appendChild(elem);

      elem = xmldoc.createElement("ip-from");
      elem_value = xmldoc.createTextNode(ipfrom);
      elem.appendChild(elem_value);
      log_elem.appendChild(elem);

      elem = xmldoc.createElement("url-to");
      elem_value = xmldoc.createTextNode(urlto);
      elem.appendChild(elem_value);
      log_elem.appendChild(elem);

      elem = xmldoc.createElement("response");
      elem_value = xmldoc.createTextNode(response);
      elem.appendChild(elem_value);
      log_elem.appendChild(elem);

      root.appendChild(log_elem); 
    }


//================================================
// Пример использования методов класса logParser
//==============================================

    public static void main(String argv[]) {

/*
 Создание объекта анализатора. В качестве параметра ему 
 передается название документа(можно и через 
 командную строку, конечно...)
*/

 logParser log_file = new logParser("log.xml");  
  log_file.parseDoc();              // Анализ документа

   if (argv.length == 0) {         // Что с ним делать
      log_file.viewLogAsXML();
		    System.exit(0);
        }                     

        for (int i = 0; i < argv.length; i++) {
            String arg = argv[i];

            if (arg.startsWith("-")) {
                if (arg.equals("-vx")) {
                    log_file.viewLogAsXML();
                    break;
                }
                if (arg.equals("-va")) {
                    log_file.viewLog();
                    break;
                }
                if (arg.equals("-ve")) {
                    log_file.viewErrors();
                    break;
                }

	        if (arg.equals("-h")) {
        	   usage();
                }
            }
        }


      
log_file.logMessage("success","12",
"GET","127.0.0.1","./index.html",
"200");
      log_file.viewLogAsXML();


    }
    private static void usage() {

        System.err.println("usage: 
		java logParser (options)");
        System.err.println();
        System.err.println("options:");
        System.err.println("  
	-vx View result as XML tree (default)");
        System.err.println("  
	-va View all messages as HTML page");
        System.err.println(" 
	 -ve View only errors as HTML page");
        System.err.println(" 
	 -h  View help ");

    } 

}

   Комментарии

   Более подробные комментарии, файлы приложений и результатов их работы можно найти по адресу www.mrcpk.nstu.ru/xml/

Назад | Содержание