к библиотеке   к оглавлению   Банки данных Интернет   визуальные среды - 4GL   технологии программирования

Сценарии объектной модели документа DOM XML

Связывание XML-документа с HTML-страницей, структура DOM, свойства и методы

Объектная модель 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:

Тип узлаКомпонент XMLnodeNamenodeValue
Documentкорневой узел документа (весь XML-документ)#documentnull
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-документа (число). Возможные значения:
  • 0 - не инициализирован.
  • 1 - загружается.
  • 2 - загружен.
  • 3 - интерактивный режим.
  • 4 - готово.
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);

Пример отображения XML-документа на HTML-странице

Попробуем отобразить на 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 += "&nbsp;&nbsp;&nbsp; " + 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-документа на 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 += "&nbsp;&nbsp;&nbsp;&nbsp;";
	}
	//получение свойств текущего узла
	DisplayString += "<TR>" +
	"<TD>" + Indent + Node.nodeName + "</TD>" +
	"<TD>" + Node.nodeTypeString + "</TD>" +
	"<TD>" + Node.nodeValue + "</TD>"+
	"</TR>";
	//получение атрибутов текущего узла
	Indent += "&nbsp;&nbsp;&nbsp;&nbsp;";
	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>

Людоговский Александр

к библиотеке   к оглавлению   Банки данных Интернет   визуальные среды - 4GL   технологии программирования

Знаете ли Вы, что в 1974 - 1980 годах профессор Стефан Маринов из г. Грац, Австрия, проделал серию экспериментов, в которых показал, что Земля движется по отношению к некоторой космической системе отсчета со скоростью 360±30 км/с, которая явно имеет какой-то абсолютный статус. Естественно, ему не давали нигде выступать и он вынужден был начать выпуск своего научного журнала "Deutsche Physik", где объяснял открытое им явление. Подробнее читайте в FAQ по эфирной физике.

Bourabai Research Institution home page

Боровское исследовательское учреждение - Bourabai Research Bourabai Research Institution