Объектная модель XML-документа, или DOM (Document Object Model) состоит из группы программных объектов, представляющих различные компоненты XML-документа. Свойства и методы этих объектов позволяют использовать сценарии для отображения XML-документа с HTML-страницы. DOM хранит данные в древообразной структуре, отражающей иерархическую структуру XML-документа, и предоставляет доступ к любым компонентам XML-документа, включая элементы, атрибуты, инструкции по обработке, комментарии и объявления нотаций и примитивов.
Чтобы получить доступ к XML-документу с использованием DOM, вы должны связать XML-документ с HTML-страницей. На
HTML-странице это можно сделать через так называемый фрагмент данных:
<XML ID="dsoDoc" SRC="Sample.xml"></XML>
Идентификатор ID, который вы назначаете фрагменту данных, указывает на DSO (Data Source Object) документа. Свойство
объекта DSO "XMLDocument" содержит корневой объект DOM, называемый также "узел документа". Вы можете использовать
это свойство для доступа к DOM в сценариях:
xmlDOM_Document = dsoDoc.XMLDocument;
Полный перечень свойств, методов и событий объекта DSO документа вы можете получить в MSDN, воспользовавшись, например, поиском по словосочетанию "xml Object". Если вы хотите иметь доступ к нескольким XML-документам с HTML-страницы, вы можете поместить фрагмент данных для каждого из них. Кроме того, вы можете включить несколько фрагментов данных для одного XML-документа. Последний приём может оказаться полезным для поддержки нескольких различных версий данных XML, если ваша страница модифицирует эти данные (в этой статье приёмы модификации XML-данных не рассматриваются).
Программные объекты, представляющие XML-документ, называются узлами. DOM использует различные типы узлов для
представления различных компонентов XML:
Тип узла | Компонент XML | nodeName | nodeValue |
---|---|---|---|
Document | корневой узел документа (весь XML-документ) | #document | null |
Element | элемент | имя типа элемента | null |
Text | текст элемента, атрибута или примитива | #text | текст родительского XML-компонента |
Attribute | атрибут, пара имя-значение в инструкции по обработке, пара SYSTEM-литерал в объявлении внешнего примитива, пара NDATA-имя нотации в объявлении неразбираемого примитива. | имя атрибута | значение атрибута |
Processing-Instruction | инструкция по обработке | предназначение инструкции | содержимое инструкции |
Comment | комментарий | #comment | текст комментария |
CDATASection | раздел CDATA | #cdata-section | содержимое раздела CDATA |
DocumentType | объявление типа документа | имя корневого элемента | null |
Entity | объявление примитива в DTD | имя примитива | null |
Notation | объявление нотации в DTD | имя нотации | null |
Вы можете получить имя каждого узла из свойства узла nodeName. Имена, начинающиеся с символа #, представляют компоненты XML, не поименованные в документе. Например, комментарий в XML-документе не обладает именем. В связи с этим DOM использует стандартное имя #comment. В общем случае имена узлов соответствуют именам, присвоенным соответствующим компонентам в XML-документе.
Вы можете получить значение каждого узла из свойства узла nodeValue. Если компонент XML непосредственно не имеет значения, DOM устанавливает в качестве значения null.
Каждый узел, как программный объект, имеет свойства и методы. Все типы узлов, помимо специфического собственного
набора свойств и методов, используют общий набор свойств и методов. Вот некоторые полезные свойства, поддерживаемые
всеми типами узлов (полный перечень свойств, методов и событий узлов вы можете получить в MSDN, воспользовавшись,
например, поиском по словосочетанию "IXMLDOMDocument/DOMDocument Members"):
Свойство | Описание | Пример (JavaScript) |
---|---|---|
attributes | Коллекция NamedNodeMap всех дочерних узлов-атрибутов данного узла. | AttributeNode = Element.attributes.getNamedItem("ItemName"); |
childNodes | Множество NodeList всех дочерних узлов-неатрибутов данного узла. | FirstNode = Element.childNodes(0); |
dataType | Тип данных узла-атрибута, если этот тип данных определён в DTD. | AttributeType = Attribute.dataType; |
firstChild | Первый дочерний узел данного узла, не являющийся атрибутом. | FirstChildNode = Element.firstChild; |
lastChild | Последний дочерний узел данного узла, не являющийся атрибутом. | LastChildNode = Element.lastChild; |
nextSibling | Следующий узел (любого типа) на том же уровне данного узла. | NextElement = Element.nextSibling; |
nodeName | Имя данного узла. | ElementName = Element.nodeName; |
nodeType | Тип данного узла (число). | NodeTypeCode = Element.nodeType; |
nodeTypeString | Тип данного узла (строка строчными буквами). | NodeTypeString = Element.nodeTypeString; |
nodeValue | Значение данного узла (если узел не содержит значения, null). | AttributeValue = Attribute.nodeValue; |
ownerDocument | Корневой узел документа, содержащего данный узел. | Document = Element.ownerDocument; |
parentNode | Узел, для которого данный узел является дочерним (не действует для атрибутов). | parentElement = Element.parentNode; |
previousSibling | Предыдущий узел (любого типа) на том же уровне данного узла. | PreviousElement = Element.previousSibling; |
text | Всё текстовое содержимое данного узла, включая подчинённые узлы. | AllCharacterData = Element.text; |
xml | Всё xml-содержимое данного узла, включая подчинённые узлы. | XMLContent = Element.xml; |
Свойство будет иметь значение null, если оно неприменимо к данному конкретному узлу. Помимо общих свойств и методов,
каждому типу узлов присущи дополнительные свойства и методы, специфические для определённого XML-компонента, который
представляет узел. Вот некоторые полезные свойства, методы и события, предоставляемые корневым узлом документа:
Свойство / метод / событие | Описание | Пример (JavaScript) |
---|---|---|
doctype | Узел типа DocumentType, представляющий DTD. | DocumentType = Document.doctype; |
entities | Коллекция NamedNodeMap узлов типа Entity, для всех объявлений примитивов в DTD. | collEntities = Document.doctype.entities; |
notations | Коллекция NamedNodeMap узлов типа Notation, для всех объявлений нотаций в DTD. | collNotations = Document.doctype.notations; |
documentElement | Узел, представляющий корневой элемент документа. | RootElement = Document.documentElement; |
ondataavailable | Событие возникает, когда данные XML становятся доступными. | Document.ondataavailable = MyDataAvailableHandler; |
onreadystatechange | Событие возникает, когда изменяется значение свойства readyState. | Document.onreadystatechange = MyReadyStateHandler; |
parseError | Объект, содержащий информацию об ошибках, возникших в процессе обработки документа. | ErrorCode = Document.parseError.ErrorCode; |
readyState | Текущий статус загрузки и обработки XML-документа (число). Возможные значения:
|
if(Document.readyState == 4) /* обработка данных... */ |
url | URL XML-документа. | URL = Document.url; |
getElementsByTagName(typename) | Возвращает множество NodeList всех элементов заданного типа. Если указано "*", возвращает все элементы. | ProductElementsCollection = Document.getElementsByTagName("PRODUCT"); |
nodeFromID(idvalue) | Возвращает узел, представляющий элемент с заданным значением атрибута типа ID. | Element = Document.nodeFromID("S021"); |
Вот некоторые полезные методы, предоставляемые узлами документа типа Element:
Метод | Описание | Пример (JavaScript) |
---|---|---|
getAttribute(name) | Возвращает значение атрибута с заданным именем. | AttValue = Element.getAttribute("import"); |
getAttributeNode(name) | Возвращает узел типа Attribute, представляющий атрибут с заданным именем. | Attribute = Element.getAttributeNode("import"); |
getElementsByTagName(typename) | Возвращает множество NodeList всех подчинённых элементов заданного типа. Если указано "*", возвращает все подчинённые элементы. | SortElementsCollection = Element.getElementsByTagName("SORT"); |
Некоторые свойства и методы, приведённые выше, возвращают объект-коллекцию NodeList. Вот свойства и методы,
поддерживаемые этой коллекцией:
Свойство / метод | Описание | Пример (JavaScript) |
---|---|---|
length | Количество элементов (узлов) в коллекции. | NodeCount = Element.childNodes.length; |
item(index) | Возвращает узел по заданному индексу. Отсчёт начинается с нуля. Данный метод является методом по умолчанию. | SecondChild = Element.childNodes.item(1); SecondChild = Element.childNodes(1); |
reset() | Устанавливает внутренний указатель на позицию перед первым узлом в наборе, чтобы следующий вызов nextNode() возвращал первый узел. | Element.childNodes.reset(); |
nextNode() | Возвращает следующий узел в наборе, в соответствии с позицией внутреннего указателя. | Element.childNodes.reset(); FirstNode = Element.childNodes.nextNode(); |
Свойство attributes и некоторые другие свойства, приведённые ранее, возвращают объект-коллекцию NamedNodeMap.
Эта коллекция несколько отличается от коллекции NodeList. Помимо свойств и методов коллекции NodeList, коллекция
NamedNodeMap поддерживает метод getNamedItem:
Метод | Описание | Пример (JavaScript) |
---|---|---|
getNamedItem() | Возвращает узел, соответствующий атрибуту с заданным именем. | imp = Element.attributes.getNamedItem("import"); |
Свойство text, описанное ранее, хорошо подходит для извлечения символьных данных элемента в том случае,
если элемент не имеет дочерних элементов. Если элемент содержит один или более дочерних элементов помимо символьных
данных, свойство text вернёт весь текст, включая текст дочерних элементов. Чтобы получить символьные данные только
самого элемента, без символьных данных дочерних элементов, потребуется осуществить доступ к дочернему узлу типа
Text. Символьные данные элемента хранятся в дочерних узлах типа Text, и их можно получить через свойство nodeValue
каждого из дочерних узлов типа Text. Если символьные данные элемента смешаны с дочерними элементами, комментариями
или инструкциями по обработке, каждый отдельный блок символьных данных представлен собственным дочерним узлом типа
Text. Например, приведённый ниже элемент будет иметь три дочерних узла: узел типа Text, узел дочернего элемента и
ещё один узел типа Text.
<ITEM>
блок символьных данных
<SUB-ITEM>текст подчинённого элемента</SUB-ITEM>
ещё один блок символьных данных
</ITEM>
Полезные свойства и методы, предоставляемые узлами типа Text:
Свойство / метод | Описание | Пример (JavaScript) |
---|---|---|
length | Количество символов в тексте узла. | CharacterCount = Element.length; |
substringData(startNum, count) | Возвращает строку, содержащую заданное число символов из текстового содержимого узла, начиная с указанного по номеру символа. В примере будут возвращены третий, четвёртый и пятый символы. | SubString = Element.substringData(2, 3); |
Попробуем отобразить на HTML-странице следующий XML-документ, представляющий из себя некий абстрактный упрощённый
каталог товаров:
<?xml version="1.0"?>
<!DOCTYPE PRODUCTS
[
<!ELEMENT PRODUCTS (PRODUCT)*>
<!ELEMENT PRODUCT (TITLE, SORT+)>
<!ELEMENT TITLE (#PCDATA)>
<!ELEMENT COLOR (#PCDATA)>
<!ELEMENT PRICE (#PCDATA)>
<!ELEMENT SORT (COLOR, PRICE)>
<!ATTLIST PRODUCT import (yes | no) "no">
]
>
<PRODUCTS>
<PRODUCT import="yes">
<TITLE> Product #1 </TITLE>
<SORT>
<COLOR> red </COLOR>
<PRICE> $10.00 </PRICE>
</SORT>
<SORT>
<COLOR> blue </COLOR>
<PRICE> $11.00 </PRICE>
</SORT>
<SORT>
<COLOR> gray </COLOR>
<PRICE> $16.00 </PRICE>
</SORT>
</PRODUCT>
<PRODUCT>
<TITLE> Product #2 </TITLE>
<SORT>
<COLOR> red </COLOR>
<PRICE> $20.00 </PRICE>
</SORT>
<SORT>
<COLOR> green </COLOR>
<PRICE> $22.00 </PRICE>
</SORT>
</PRODUCT>
<PRODUCT import="yes">
<TITLE> Product #3 </TITLE>
<SORT>
<COLOR> red </COLOR>
<PRICE> $30.00 </PRICE>
</SORT>
<SORT>
<COLOR> blue </COLOR>
<PRICE> $33.00 </PRICE>
</SORT>
</PRODUCT>
<PRODUCT>
<TITLE> Product #4 </TITLE>
<SORT>
<COLOR> red </COLOR>
<PRICE> $40.00 </PRICE>
</SORT>
<SORT>
<COLOR> blue </COLOR>
<PRICE> $44.00 </PRICE>
</SORT>
</PRODUCT>
<PRODUCT>
<TITLE> Product #5 </TITLE>
<SORT>
<COLOR> red </COLOR>
<PRICE> $50.00 </PRICE>
</SORT>
<SORT>
<COLOR> gray </COLOR>
<PRICE> $55.00 </PRICE>
</SORT>
</PRODUCT>
</PRODUCTS>
Вот текст HTML-документа, отображающего этот каталог товаров:
<html>
<head>
<script for="window" event="onload">
//переменная, которая будет содержать разметку HTML
HTMLCode = "";
//получаем доступ к корневому объекту DOM
doc = dsoPROD.XMLDocument;
//запускаем функцию проверки XML-документа на валидность
if(doc.readyState == 4) DisplayError();
else doc.onreadystatechange = DisplayError;
//перебираем в цикле все узлы документа
for(i=0; i<doc.documentElement.childNodes.length; i++){
//получаем текущий узел (PRODUCT)
nodePRODUCT = doc.documentElement.childNodes(i);
//получаем значение атрибута "import"
imp = nodePRODUCT.attributes.getNamedItem("import");
if(imp.nodeValue == "yes") imp = " (импортный)";
else imp = " (отечественный)";
//включаем в вывод TITLE текущего PRODUCT'а (элемент TITLE всегда первый дочерний элемент у PRODUCT)
HTMLCode += "<h3>" + nodePRODUCT.childNodes(0).text + imp + "<h3>";
//получаем коллекцию сортов текущего PRODUCT'а (дочерние элементы SORT)
nodesSORTS = nodePRODUCT.getElementsByTagName("SORT");
//перебираем в цикле все сорта текущего PRODUCT'а
for(j=0; j<nodesSORTS.length; j++){
//получаем текущий сорт (узел SORT)
nodesSORT = nodesSORTS(j);
//включаем в вывод весь текст текущего сорта (это цвет и цена - дочерние элементы COLOR и PRICE)
HTMLCode += " " + nodesSORT.text + "<br>"
}//конец цикла по сортам текущего PRODUCT'а
}//конец цикла по всем узлам документа
//отображаем разметку HTML
ResultDiv.innerHTML = HTMLCode;
//функция отображает подробное сообщение об ошибке, если XML-документ не прошёл проверку на валидность
function DisplayError(){
if(doc.readyState != 4) return;
if(doc.parseError.errorCode){
mess =
"parseError.errorCode: " + doc.parseError.errorCode + "\n" +
"parseError.filepos: " + doc.parseError.filepos + "\n" +
"parseError.line: " + doc.parseError.line + "\n" +
"parseError.linepos: " + doc.parseError.linepos + "\n" +
"parseError.reason: " + doc.parseError.reason + "\n" +
"parseError.srcText: " + doc.parseError.srcText + "\n" +
"parseError.url: " + doc.parseError.url + "\n" +
"";
alert(mess);
}
}
</script>
</head>
<body>
<xml ID="dsoPROD" SRC="Sample.xml"></xml>
<h1>Каталог товаров</h1>
<div id="ResultDiv"></div>
</body>
</html>
Приведённая выше HTML-страница содержит фрагмент данных для связи с XML-документом (с идентификатором "dsoPROD"), и скрипт, использующий свойства и методы объекта dsoPROD, который выводит содержимое XML-документа в элемент HTML-страницы DIV (с идентификатором "ResultDiv"), расположенный внизу страницы. Скрипт запускается в момент загрузки HTML-документа. Текст скрипта подробно прокомментирован и в дополнительных пояснениях не нуждается.
Приведённый ниже сценарий отображает произвольный XML-документ на Web-странице в иерархическом виде, наглядно
демонстрируя иерархическую природу DOM.
<html>
<head>
<script for="window" event="onload">
//получаем доступ к корневому объекту DOM
doc = dsoPROD.XMLDocument;
//запускаем функцию проверки XML-документа на валидность
if(doc.readyState == 4) DisplayError();
else doc.onreadystatechange = DisplayError;
//отображаем корневой узел документа
ResultDiv.innerHTML = doc.url + "<br>" +
"<TABLE border='1' width='100%' cellspacing='0'>" +
"<TR><TH>Имя узла</TH><TH>Тип узла</TH><TH>Значение узла</TH></TR>" +
DisplayNodes(doc, 0) + "</TABLE>";
//*************************************************************************************************
//рекурсивная функция отображает все узлы XML-документа
//параметры:
//Node - объект текущего узла
//Level - номер текущего уровня иерархии (начинается с нуля)
function DisplayNodes(Node, Level){
var i;
var DisplayString = ""; //строка результатов
//создание отступа для текущего уровня
Indent = "";
for(i=0; i<Level; ++i){
Indent += " ";
}
//получение свойств текущего узла
DisplayString += "<TR>" +
"<TD>" + Indent + Node.nodeName + "</TD>" +
"<TD>" + Node.nodeTypeString + "</TD>" +
"<TD>" + Node.nodeValue + "</TD>"+
"</TR>";
//получение атрибутов текущего узла
Indent += " ";
for(i=0; Node.attributes != null && i<Node.attributes.length; ++i){
DisplayString += "<TR>" +
"<TD>" + Indent + Node.attributes(i).nodeName + "</TD>" +
"<TD>" + Node.attributes(i).nodeTypeString + "</TD>" +
"<TD>" + Node.attributes(i).nodeValue + "</TD>"+
"</TR>";
}
//получение дочерних узлов текущего узла
for(i=0; i<Node.childNodes.length; ++i){
DisplayString += DisplayNodes(Node.childNodes(i), Level+1);
}
//возврат результатов
return DisplayString;
}
//*************************************************************************************************
//функция отображает подробное сообщение об ошибке, если XML-документ не прошёл проверку на валидность
function DisplayError(){
if(doc.readyState != 4) return;
if(doc.parseError.errorCode){
mess =
"parseError.errorCode: " + doc.parseError.errorCode + "\n" +
"parseError.filepos: " + doc.parseError.filepos + "\n" +
"parseError.line: " + doc.parseError.line + "\n" +
"parseError.linepos: " + doc.parseError.linepos + "\n" +
"parseError.reason: " + doc.parseError.reason + "\n" +
"parseError.srcText: " + doc.parseError.srcText + "\n" +
"parseError.url: " + doc.parseError.url + "\n" +
"";
alert(mess);
}
}
</script>
</head>
<body>
<xml ID="dsoPROD" SRC="RAc4_Pr2.xml"></xml>
<h1>Стуктура XML DOM</h1>
<div id="ResultDiv"></div>
</body>
</html>
Людоговский Александр