DOM - Document Object Model

Модель объектов DOM. Динамический HTML

Концепция динамического HTML (DHTML) интерпретируется разработчиками основных браузеров по-разному. Для Netscape это тройка: JavaScript, загружаемые шрифты и стили. При этом предполагается расширение набора элементов разметки за счет элементов разметки стилей и элемента LAYER. Для Microsoft DHTML - это JScript, расширяющий возможности JavaScript. Он позволяет программировать стили, изменять содержимое документа без его перезагрузки и использовать другую схему обработки событий, которые, в свою очередь, жестко не привязываются к документу.

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

<style>
p {font-size:10pt}
kuku {color:red}
#blue {color:blue};
</style>
...
<script>
document.styleSheets[0].rules[0]
.style.fontSize=>10pt>;
document.styleSheets[0].rules[1]
.style.color=>red>;
document.styleSheets[0].rules[2]
.style.color=>blue>;
</script>
...
<a id=ref href=...>...</a>
<script>
document.all.ref.style.color=
<blue>;
document.all.ref.style.fontStyle=
<italic>;
document.all.tags(<a>).item(0)
.style.fontSize=>10pt>;
document.links[0].style
.backgroundColor=>black>;
</script>

Стоит отметить, что для использования идентификатора у элемента разметки в JScript совсем необязательно создавать связанный с ним селектор идентификатора в описаниях стилей - управлять через него стилями все равно нельзя.

Программирование стилей естественным образом приводит к переформатированию документа, что нарушает принципы неизменности загруженного документа JavaScript. В предыдущем примере это используется для изменения кегля гипертекстовой ссылки, к которой мы обращаемся как к элементу коллекции (встроенному массиву) гипертекстовых ссылок. Выбираем же этот элемент последовательно, применяя методы tags() и items(), либо обращаясь к массиву links[].

JScript позволяет поименовать любой элемент разметки документа, однако делается это не через атрибут name, а через атрибут id. При этом у поименованного таким образом объекта есть два свойства innerText и innerHTML. Свойства эти можно изменять. Первое из них позволяет изменить текст внутри элемента разметки, а второе - содержание HTML-разметки внутри элемента разметки, что дает возможность создавать новые объекты внутри документа.

<p id=kuku
onMouseover= <document.all.ref.style
.color='red';document.all.ref
.innerText='красная
гипертекстовая ссылка';>
onMouseout= <document.all.ref
.style.color='blue';
document.all.ref.innerText=
'гипертекстовая ссылка';>>
Здесь размещена
<a href=... id=ref
onClick= <document.all.kuku.innerHTML=
'Здесь нет гипертекстовой ссылки';
return false;>
style= <color:blue;>>
гипертекстовая ссылка
</a>
</p>

В последнем примере обработчики событий onMouseover и onMouseout применялись для обработки движения мыши над блоком текста, т.е. событий, связанных с пассивным элементом разметки. Здесь мы наблюдаем принципиальное отличие от первоначальной модели событий JavaScript.

Любое событие может быть связано с элементом разметки - это достигается указанием у этого элемента атрибута обработчика данного события. Другими словами, у всех элементов разметки определен весь перечень возможных событий и обработчики этих событий для каждого класса элементов. Программист через атрибут обработчика может переопределить действие, выполняемое по умолчанию.

В JScript применяется "пузырьковый" метод обработки событий. Это означает, что если для какого-то объекта происходит некоторое событие, то сначала вызывается обработчик события, связанный с этим объектом, а потом событие передается обработчику данного события для старшего объекта в иерархии объектов документа. Программист имеет возможность запретить передачу обработки события наверх.

Для поддержки совместимости со статическим HTML и JavaScript большинство обработчиков не выполняют никаких операций, хотя по умолчанию события всегда транслируются на верхний уровень.

И последний штрих к "портрету" JScript от Microsoft. Этот язык и его модель данных можно использовать для программирования Active Server Pages (ASP). Главное здесь не запутаться между директивами JScript, предназначенными для интерпретации на стороне сервера и JScript-кодом, который следует исполнять на стороне браузера.

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

Объектные модели данных JavaScript, JScript и Java предшествовали появлению Document Object Model - спецификации интерфейса прикладного программирования для HTML и XML. DOM наследует многие свойства этих моделей и творчески развивает их. DOM определяет логическую структуру документа, способы доступа к его элементам и манипулирования ими. При этом термин "документ" понимается широко - это единица информационного описания, которую можно закодировать на XML. Другими словами, XML-описание рассматривается в качестве документа, а DOM определяет способы манипулирования этим описанием.

В рамках DOM программист может создавать документы, получать доступ к их составным частям (элементам), добавлять, удалять элементы и изменять их содержание. Главным в DOM был универсальный, независимый от языка программирования, интерфейс прикладного программирования документов Web.

В спецификации DOM специально оговаривается вопрос о том, что применение DOM не подразумевает модель данных типа "дерево" или "лес деревьев". Авторы подчеркивают, что они оперируют структурной моделью данных (structured model), избегая формулировки "модель данных типа дерево или леса". XML, для которого разработана DOM, опирается на представление данных в виде леса деревьев, но для манипулирования структурами такого типа не обязательно использовать именно эту модель данных. Можно обойтись списками или другими моделями, которые однозначно отображаются на деревья. Авторы специально подчеркивают, что если две разных реализации DOM создают один и тот же документ, то они создают одну и ту же модель данных с одинаковыми объектами и отношениями между ними. О таких реализациях DOM говорят, что они изоморфны. Таким образом, DOM определяет:

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

Спецификация DOM состоит из двух частей: ядра DOM и применения DOM к HTML. Ядро обеспечивает функциональную полноту для обработки XML-документов, а также базис для DOM HTML.

Следует отметить, что, определяя объекты и методы манипулирования ими, спецификация DOM уровня 1 ничего не говорит о событиях и принципах их обработки. Это существенно ограничивает возможность быстрого применения DOM в современных средствах программирования Web, где обработка событий является одним из ключевых элементов технологии программирования. Строго говоря, DOM позволяет реализовать с точностью до обработки событий модель объектов JavaScript, но явно недостаточна для реализации модели объектов DHTML, хотя именно последняя концепция бралась авторами DOM за основу.

Ядро DOM позволяет определить документ как множество узлов, связанных между собой отношением "родитель-потомок", а ключевым объектом является Document. Отношение "родитель-потомок" определено в DOM следующим образом:

Document =: Element,
ProcessingInstruction, Comment,
DocumentType
DocumentFragment =: Element,
ProcessingInstruction, Comment,Text,
CDATASection,
EntityReference
DocumentType =: нет потомков
EntityReference =: Element,
ProcessingInstruction, Comment, Text,
CDATASection,EntityReference
Element =: Element,
ProcessingInstruction,
Comment, Text, CDATASection,
EntityReference
Attr =: Text, EntityReference
ProcessingInstruction =: нет потомков
Comment =: нет потомков
Text =: нет потомков
CDATASection =: нет потомков
Entity := Element, ProcessingInstruction,
Comment, Text, CDATASection,
EntityReference 

С другой стороны в DOM определен объект Node (узел), у которого определен интерфейс NodeList, устанавливающий порядок узлов потомков объекта Node.

Если вы ждете, что сейчас речь пойдет о дереве интерфейсов DOM, то вас придется огорчить - такого дерева в DOM нет. Каждый интерфейс описывает атрибут и методы, которые, в свою очередь, могут иметь тип другого интерфейса. Можно, конечно, попытаться построить такое дерево, но хочу сразу предупредить, что в графе появятся кольца.

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

В DOM рассматриваются два уровня интерфейсов: базовый, оперирующий узлами, ориентирован на применение в рамках Java или других языков разработки приложений; прикладной уровень, который оперирует объектами типа Document или Element, а в рамках DOM HTML конкретными классами объектов HTML. Последний тип интерфейсов ориентирован на скриптовые языки и может применяться более широким кругом программистов.

Авторы, подчеркивая языковую независимость DOM, для спецификации интерфейсов используют OMG IDL в том виде, в каком она определена в спецификации CORBA_2.2. Например, определение интерфейса Document в этой нотации будет выглядеть следующим образом:

interface Document : Node {
readonly attribute DocumentType	doctype;
readonly attribute
DOMImplementation implementation;
readonly attribute Element documentElement;
Element createElement(in DOMString tagName)
raises(DOMException);
DocumentFragment createDocumentFragment();
Text createTextNode(in DOMString data);
Comment createComment(in DOMString data);
CDATASection createCDATASection
(in DOMString data)
raises(DOMException);
ProcessingInstruction
createProcessingInstruction
(in DOMString target in DOMString data);
raises(DOMException);
Attr createAttribute(in DOMString name)
raises(DOMException);
EntityReference	createEntityReference
(in DOMString name) raises(DOMException);
NodeList getElementsByTagName
(in DOMString tagname);
};

Интерфейсы более высокого уровня, например, интерфейс HTMLFromElement раздела DOM HTML будет в данной нотации определяться следующим образом:

interface HTMLFormElement :
HTMLElement {
readonly 	attribute
HTMLCollection 	elements
readonly 	attribute long
                   length;
attribute DOMString
                 name;
attribute DOMString
                 acceptCharset;
attribute DOMString
                 acton;
attribute DOMString
                 enctype;
attribute DOMString
                 method
attribute DOMString
                 target
void
                 submit();
void
                 reset();
};

Обсуждать декларацию интерфейса Document не имеет смысла - при программировании на JavaScript с ним просто нельзя столкнуться, т.к. там нет таких возможностей. Типовое программирование на JScript также обходится без программирования свойств документа. Декларацию HTMLFormElement, напротив, стоит рассмотреть - это типовая задача при программировании передачи данных из формы при контроле ввода на стороне клиента.

Что мы видим в декларации HTMLFormElement? Атрибут elements - это коллекция в терминах DOM или встроенный массив в терминах JavaScript, причем массив неизменяемый. Добавить в него новые элементы нельзя. Атрибут length определен как неизменяемый. В комментариях к этому описанию в спецификации указано, что его значение равно числу элементов в форме. Name - это имя формы, и его можно менять. Атрибут acceptCharset определяет типы кодировки, которые поддерживает сервер. Остальные атрибуты имеют те же значения, что и в HTML. Методы submit и reset не возвращают значений и имеют тот же смысл, что и в JavaScript. Замечание по поводу типа кодировки сервера позволяет говорить о том, что DOM определяет интерфейс прикладного программирования, как на стороне клиента, так и на стороне сервера.

Важно отметить еще один момент. Когда программист работает с одним языком, например, с JavaScript или Java, вопрос о единстве описания переменных и методов объектов сводится к удобству и скорости адаптации при переходе от одного языка программирования к другому. Но современные браузеры в рамках технологий JavaScript, JScript, VBScript и Java позволяют организовать обмен данными между фрагментами кода, написанными на разных языках. Например, в JavaScript существует механизм LiveConnect, который определяет правила передачи данных и использование методов Java в JavaScript и наоборот. При таком положении дел стандартизация интерфейсов не только полезна, но и просто необходима.

Объектная модель документа должна послужить соединительным звеном между программированием и логической моделью документа, формой его представления на носителях. Логическая модель и форма представления описывается в рамках XML. Программирование Web - это языки Java, JavaScript, JScript. Стандарт DOM позволяет формально описать правила манипулирования структурой XML-документов и их содержанием в рамках объектно-ориентированного программирования, которое реализуют перечисленные языки.

Во многом усилия по разработчиков DOM напоминают попытки создания различных версий спецификаций HTML (версий 2.0 и 3.2). Первая версия языка и последняя четвертая версия скорее похожи на декларации о намерениях, чем на готовые к использованию спецификации. То же происходит и со спецификациями прикладного программирования. Первая версия DOM во многом уже отстает от языков программирования, реализованных в современных браузерах JScript в IE 5.0 или JavaScript браузера Gecko - новой версии Netscape Navigator. Первая версия спецификации DOM еще не реализована, а на подходе уже вторая, в которой планируется писать механизм обработки прерываний. Кроме того, ведутся работы над скриптовым языком ECMAScript, где будут обобщены возможности JavaScript и JScript, а также приняты во внимание особенности структуры данных XML-документов.

[an error occurred while processing this directive]