Для управления процессом анализа документа можно изменять следующие рассмотренные ранее свойства XMLDOMObject : async, validateOnParse, resolveExternals, preserveWhiteSpaces. Необходимо запомнить, что анализ XML документа производится непосредственно после загрузки его содержимого - остановить этот процесс можно только используя метод abort. Поэтому свойства обработчика нужно изменять перед его загрузкой. В процессе анализа документа обработчиком могут вызываться некоторые события, перехватывая которые можно отслеживать все шаги обработки. Для назначения классов обработчиков используются свойства , описанные в таблице. Вот пример программы-обработчика события , возникающего при изменении текущего состояния анализатора.
Другой способ назначить обработчик событий для элемента - это использование атрибута event тэга :
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 анализатора. Демонстрируется возможность рекурсивного обхода дерева элементов, создание новых элементов, фильтрация элементов (поиска по параметрам) */
//========================================================================== // Вывод содержимого документа в виде форматированного списка XML- элементов //========================
/* Рекурсивный обход элементов документа, начиная с указанного элемента node. */
public void viewLogAsXML(Node node,String offs){
if (node == null) { return; } int type = node.getNodeType(); // Получение информации о типе текущего узла switch (type) { /* Если текщий узел - корневой элемент документа */
case Node.DOCUMENT_NODE: { out.println(""); 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; }
/* Рекурсивный обход элементов, у которых атрибут 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);
/* Получение текста внутри элемента - обращаемся к первому дочернему узлу (им должен оказаться текст) и получаем его значение, используя метод getNodeValue() интерфейса Node */
Element root = xmldoc.getDocumentElement(); Element log_elem = xmldoc.createElement("event"); log_elem.setAttribute("result",result); log_elem.setAttribute("date",datetime);
//======================================================= // Пример использования методов класса 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; }
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/
Назад | Содержание
Использование Java XML-обработчиков
Internet Explorer, несмотря на мощную встроенную поддержку XML, сегодня далеко не единственное средство, которое можно использовать для работы с новым языком. Обработкой XML документа на стороне клиента или сервера может также заниматься любой другой анализатор XML-документов, который конвертирует их в обычную HTML страницу или извлекает из нее информацию для других приложений. Что такое XML Parser?
Любой XML-процессор, являясь, по сути, транслятором языка разметки, может быть разбит на несколько модулей, отвечающих за лексический, синтаксический и семантический анализ содержимого документа. Понятно, что если бы мы были вынуждены каждый раз писать все эти блоки самостоятельно, необходимость в XML как в таковом бы отпала - основное его преимущество, как уже упоминалось ранее, заключается в стандартном способе извлечения информации из документа. Синтаксически правильно составленный XML-документ может быть разобран любым универсальным XML анализатором, и нашему XML-обработчику остается лишь использовать полученные на его выходе "чистые" данные (прошедшие синтаксический анализ) - интерпретировать содержимое документа, в соответствии с его DTD-описанием или схемами данных. Рис. 2 Иллюстрация механизма доступа к содержимому XML-документа при помощи интерфейсов анализатора
Конечно, синтаксический анализатор может быть довольно легко реализован и самостоятельно, например, в Perl, с его мощными возможностями обработки регулярных выражений. Но в общем случае такой "ручной" способ является довольно нетривиальной задачей, требующей некоторых усилий и является дополнительным источником ошибок. Поэтому применение универсальных XML-анализаторов может существенно облегчить жизнь разработчикам, тем более, что уже сегодня количество свободно доступных программ такого рода довольно велико. В функции современного XML-процессора обычно входит получение общих сведений о документе, извлечение информации о его структуре и построения некоторой абстрактной объектной модели данных, представляющей эту структуру. По способу проверки разбираемых документов универсальные программы-анализаторы делятся на два типа: верифицирующие, способные обнаружить DTD-описания грамматики языка и использовать их для проверки документа на семантическую корректность; и неверифицирующие, не осуществляющие такой проверки. Описывая разобранный XML-документ, универсальная программа-анализатор должна представить его структуру в виде упорядоченной модели данных, для доступа к которой используется какая-то станадртная, описанная в соответствующей спецификации библиотека классов - интерфейсов XML документа. На сегодняшний день существует два подхода к их построению: собыйтийный - Simple API for XML, SAX и объектно-ориентированный - DOM(Document Object Model). Рассмотрим их использование на конкретных примерах. Что такое SAX
Сегодня стандартным интерфейсом для большинства универсальных XML-анализаторов является событийно-ориентированное API SAX - Simple API for XML.
Термин событийно-ориентированный является ключевым в этом определении и объясняет способ использования SAX. Каждый раз, когда при разборе XML документа анализатор оказывается в каком-то новом состоянии - обнаруживает какую-либо синтаксическую конструкцию XML-документа (элемент, символ, шаблон, и т.д.), фиксирует начало, конец объявлений элементов документа, просматривает DTD-правила или находит ошибку, он воспринимает его как произошедшее событие и вызывает внешнюю процедуру - обработчик этого события. Информация о содержимом текущей конструкции документа передается ему в качестве параметров функции. Обработчик события - это какой-то объект приложения, который выполняет необходимые для обработки полученной из XML информации действия и осуществляет таким образом непосредственный разбор содержимого. После завершения этой функции управление опять передается XML-анализатору и процесс разбора продолжается.
Реализацией этого механизма в Java SAX 1.0 является библиотека классов org.xml.sax (их можно получить, например, с узла: www.megginson.com, но обычно эти классы включаются в состав XML -анализатора). Наследуя клссы SAX-совместимого анализатора, мы получаем универсальный доступ к XML документу при помощи классов, содержимое и механизм использование которых приведено в соответствующем описании.
Последовательный разбор XML-документа SAX-обработчиком обычно производится по следующей схеме (более подробное описание приведено ниже):
загрузить документ, установить обработчики событий, начать просмотр его содержимого (если есть DTD-описания, то - их разбор);
найдено начало документа (его корневой, самый первый элемент) - вызвать виртуальную функцию- обработчик события startDocument;
каждый раз, когда при разборе будет найден открывающий тэг элемента вызывается обработчик-функция startElement. В качестве параметров ей передаются название элемента и список его атрибутов;
найдено содержимое элемента - передать его соответствующему обработчику - characters, ignorableWhitespace,processingInstruction и т.д.;
если внутри текущего элемента есть подэлементы, то эта процедура повторяется;
если в процессе обработки были обнаружены ошибки, то анализатором вызываются обработчики предупреждений (warning), ошибок (error) и критических ошибок обработчика (fatalError).
Ссылка на объект класса обработчика событий может передаваться объекту XML-анализатора при помощи следующих функций:
parser.setDocumentHandler(event_class); // - обработчик событий документа
parser.setEntityResolver(event_class); // - обработчик событий загрузки DTD-описаний
parser.setDTDHandler(event_class); // - обработчик событий при анализе DTD-описаний
Получение сообщения о "несерьезной" ошибке. Пдробная информация содержится в передаваемом объекте класса SAXParseException
error (SAXParseException e)
Сообщение об ошибке
fatalError (SAXParseException e)
Сообщение о критической ошибке
<
Для демонстрции использования этих методов рассмотрим небольшой пример обработчика регистрационного XML-документа (его структура описана в примере 2 первого раздела статьи). Java-приложение выводит содержимое документа и информацию о его структуре, путь к документу задается в командной строке. Для компилирования потребуется JDK 1.1.4 и классы SAX, находящиеся либо в текущем пакете, либо вместе с другими классами в classes.zip.
public void startElement(String name, AttributeList attrs) {
elements++; if (attrs != null) { attributes += attrs.getLength(); }
// Печать тэга элемента вместе со списком его атрибутов, например, out.print('<'); out.print(name); if (attrs != null) { int len = attrs.getLength(); for (int i = 0; i < len; i++) { out.print(' '); out.print(attrs.getName(i)); out.print("=\""); out.print(attrs.getValue(i)); out.print('"'); } } out.println('>');
}
// Встретился закрывающий тэг элемента
public void endElement(String name) {
out.println(""+name+">");
}
// Текстовые символы
public void characters(char ch[], int start, int length) {
Первым шагом в процессе построения XML- обработчика является создание объекта из класса анализатора (в нашем случае это классы из паекета com.ibm.xml.parsers). Для этого можно использовать класс ParserFactory, входящий в org.xml.sax.helpers:
import org.xml.sax.*; ... Parser parser = ParseFactory.createParser(); ...
Затем следует определить обработчики возникающих в процессе разбора XML-документа событий. Приложению необязательно устанавливать все обработчики сразу - в классе HandlerBase все события могут обрабатываться "по умолчанию". Более подробную информацию по использованию SAX-анализаторов можно найти в примерах приложений в пакетах анализатора или на сервере www.megginson.com. Комментарии, файлы приложений и результатов их работы можно найти по адресу www.mrcpk.nstu.ru/xml/
Назад | Содержание | Вперед
Обход дерева элементов
Для работы со списком элементов в объектной модели XML-анализатора Microsoft предназначены специальные объекты: XMLDOMNode - представляющий узел дерева и XMLDOMNodeList - список узлов, поддерево. Их описание приведено в таблице. Просмотр списка элементов документа всегда начинается с получения нужного поддерева. Для этого у объекта XMLDOMNode используется методы childNodes, selectNodes или getElementsByTagName, возвращающие объект XMLDOMNodeList. Количество элементов этом поддереве можно узнать при помощи свойства length. Вот, например, как будет выглядеть процедура рекурсивного просмотра документа произвольной структуры: