DOM СОВМЕСТИМЫЕ АНАЛИЗАТОРЫ
Другим способом представления внутренней структуры документа являются DOM - интерфейсы. Как уже упоминалось, их реализацией занимаются разработчики XML-анализатора, используя для этого возможности конкретного языка программирования. Программисты на Java могут найти эти классы в библиотеке org.w3.dom. Наследуя виртуальные методы DOM интерфейсов, классы анализатора предоставляют приложению стандартный способ манипулирования структурой документа. В свою очередь, приложение, использующее XML-анализатор, может не знать о способе реализации интерфейсов, ему доступна готовая библиотека методов, при помощи которой он может производить поиск нужных фрагментов документа, создавать, удалять и модифицировать его элементы.
Одним из доступных на сегодня DOM-совместимых наборов классов для работы с документами является библиотека com.ibm.dom, входящая в состав XML анализатора xml4j от IBM. Получить ее можно по адресу http://www.sinor.ru/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 ");
}
}
Комментарии
Более подробные комментарии, файлы приложений и результатов их работы можно найти по адресу http://www.sinor.ru/www.mrcpk.nstu.ru