Глава 7. Семейства элементов документа



Объектная модель динамического HTML представляет структуру документа посредством набора семейств, которые используются объектом document. Семейства обеспечивают доступ ко всем элементам HTML, содержащимся внутри документа. Понимание взаимоотношений семейств с исходным кодом HTML и способов доступа к ним является ключом к программированию HTML-документа. В данной главе будет показано, как манипулировать семействами элементов документа, а также как Microsoft Internet Explorer 4.0 анализирует документ.

Рассмотрим приведенный ниже короткий HTML-код:

<HTML>
<HEAD>
<TITLE> Структура документа </TITLE>
</HEAD>
<BODY>
<H1>Overview</H1>
<P>Examining an HTML document</P>
</BODY>
</HTML>

Объектная модель обеспечивает возможность доступа к элементам HTML, Head, Title, Body, H1 и Paragraph и, соответственно, возможность изменения их атрибутов. Доступ к разметке, так же как и другим аспектам документ осуществляется посредством объекта document, введенного в главе 6. Объект document представляет семейство all, которое содержит все элементы документа и несколько выбранных семейств, которые представляют подмножество элементов документа. Например, семейство forms содержит только элементы Form. Кроме того, разработчики могут сами создавать семейства элементов документа.

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

В данной главе рассмотрены следующие темы:



Использование семейств

В этом разделе внимание сфокусировано на использовании семейства all для доступа к элементам на странице. Семейство all в объекте document содержит все элементы, находящиеся в файле HTML. Манипулирование данным семейством осуществляется посредством набора свойств и методов, которые поддерживаются всеми семействами элементов. Свойства и методы определяют число элементов в семействе, обеспечивают доступ к индивидуальным элементам и предоставляют возможность выбора элементов по типу из семейства.

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



Размер семейства

Первой и наиболее фундаментальной операцией в семействе является определение числа элементов в семействе. Число элементов возвращается свойством length. Так, пример документа в начале этой главы содержит шесть элементов:


alert(document.all.length); // 6 элементов



Доступ к элементам

Доступ к элементам в семействах осуществляется посредством метода item. Метод item использует в качестве аргумента порядковое положение или идентификатор строки, которые представляют атрибут name или id элемента. Когда вы указываете порядковый номер, помните, что во всех семействах отсчет начинается с нуля. Поэтому приведенный ниже код пересчитывает элементы в семействе all:


// Отображение имени тега для всех элементов.
for (var i = 0, i < document.all.length, i++)
alert(document.all.item(i).tagName);

Примечание: В цикле, подобном этому, который обращается к элементам семейства, выражение условия должно проверять, что значение индекса меньше, чем число элементов в семействе. Поскольку первый элемент в семействе имеет нулевой номер, то отсутствует элемент, индекс которого равен числу элементов семейства.

В VBScript item является методом по умолчанию в семействах. Определение метода item необязательно при обращении к элементам. В JavaScript методы по умолчанию не поддерживаются. Однако все объекты представляют связанные массивы, что позволяет обращаться ко всем именованным элементам как к обычным элементам массивов. Это означает, что все элементы в семействе также представлены как свойства в объекте, что позволяет обращаться к элементам по их порядковому номеру в основном массиве или по их символьному имени, или идентификатору (ID). Приведенный выше код может быть переписан следующим образом:


// Отображение имени тега для всех элементов.
for (var i = 0, i < document.all.length, i++)
alert(document.all[i].tagName);

Примечание: В JavaScript ссылка на массив осуществляется с использованием квадратных скобок ([ ]). В VBScript, где вместо массива используется метод по умолчанию, в ссылках используются круглые скобки:
msgbox(document.all(i).id) ' VBScript


Атрибуты id u name

Выше была продемонстрирована ссылка на элемент только по его порядковому номеру. Ссылка на элементы может также осуществляться непосредственно, путем использования атрибутов id или name, между которыми существует несколько различий. Атрибут id уникальным образом определяет элемент внутри документа. Атрибут name может быть совместно использован множеством элементов. Данный атрибут используется определенными элементами и обычно имеет определенное значение. Например, для элемента в блоке формы атрибут name используется в указываемом имени, а в кнопках-переключателях атрибут name используется для группирования кнопок.

При назначении имен для программного доступа следует использовать атрибут id. Атрибут name должен быть зарезервирован для своего истинного использования на основании контекста элемента. Атрибут name может потребоваться программе для Netscape Navigator, поскольку данный браузер в настоящее время не распознает атрибут id в элементах, которые не позиционированы с помощью CSS (Cascading Style Sheets - каскадные таблицы стилей). Атрибут name поддерживается в Netscape Navigator для доступа к элементу Form, фреймам и всем встроенным элементам управления.

Примечание: Для упрощения терминологии, начиная с этого момента термин именованный элемент будет обозначать элемент, который имеет установленное значение атрибута id или name.


Ссылка на именованные элементы

В JavaScript атрибуты id или name используются для ссылки на элемент тремя способами: используя метод семейства item, прямо, как свойство семейства или косвенно, как просмотр массива. Приведенные ниже примеры иллюстрируют способы ссылок на элемент, значение атрибута id или name которого равно myElement:


document.all.item("myElement")
document.all.myElement
document.all["myElement"]

Ссылаясь на элементы, при помощи метода item или по индексу массива в семействе all, можно запросить элемент путем передачи переменной. Данный метод полезен, поскольку не требуется заранее знать и вносить в программу атрибуты id или name. Ниже приведен пример общего кода с переменной, которая содержит атрибут id:


// Получение имени тега для элемента с определенным значением атрибута id.
var retValue = window.prompt("Enter an ID:");
if (retValue != null)
alert(document.all[retValue].tagName);


Использование метода item для возвращения семейства

Атрибут элемента name в документе не обязательно должен быть уникальным. Кнопки-переключатели в группе обычно совместно используют одно значение name, как показано в приведенном ниже примере:

<HTML>
<HEAD>
<TITLE> Группа кнопок-переключателей </TITLE>
</HEAD>
<BODY>
<FORM>
Name: <INPUT TYPE=TEXT NAME="YourName"><BR>
<INPUT TYPE=RADIO NAME="Gender" VALUE="Male">Male
<INPUT TYPE=RADIO NAME="Gender" VALUE="Female">Female
</FORM>
</BODY>
</HTML>

Поскольку значение атрибута name не обязательно должно быть уникальным, то значение name, которое используется для поиска элемента семейства, может совпадать более чем в одном элементе. При наличии нескольких совпадений результатом просмотра является подсемейство, содержащее все элементы с данным значением атрибута name. Приведенные ниже примеры являются обращением к именованным элементам в приведенном выше коде:


document.all["YourName"] // Окно ввода информации Input box // (не является семейством)
document.all["Gender"] // Семейство из двух элементов
document.all["Gender"].length // 2
document.all["Gender"].item(0) // Кнопка-переключатель Male

Подсемейство строится на тех же принципах, что и все остальные семейства. В частности, оно представляет свойство length и метод item. Элементы в подсемействе находятся в том же порядке, в котором они находились в исходном семействе.

Когда метод item возвращает подсемейство, можно передать второй параметр для выбора элемента в подсемействе. Например, обратиться к кнопке-переключателю Male можно следующим способом:


document.all.item("Gender", 0)

VBScript и JavaScript поддерживают ярлыки для доступа к элементам в подсемействе без использования метода item. Например, приведенные ниже фрагменты кода обращаются к кнопке-переключателю Male:


' В VBScript метод item используется по умолчанию.
document.all("Gender", 0)
// JavaScript использует доступ как к массиву.
document.all["Gender"][0]

Документы с дублирующимися значениями id являются технически недействительными, но разработчик может их использовать, а сценарии, которые обращаются к неизвестным документам в других фреймах или окнах, могут обнаружить их. Приведенный ниже пример кода содержит несколько элементов со значением атрибута id, равным test:

<HTML>
<HEAD>
<TITLE> Дублирующиеся ID </TITLE>
</HEAD>
<BODY>
<H1 ID="test">Header 1</H1>
<P ID="test">This is a paragraph.
<P ID="test">This is another paragraph.
<INPUT ID="test" NAME="foo">This is a named Input box.
</BODY>
</HTML>

Атрибуты id с дублирующимися значениями обрабатываются как дублирующиеся имена. Если сценарий ищет элемент по значению id и обнаруживает несколько совпадений с искомым id, то все элементы будут возвращены как семейство. Приведенные ниже выражения обращаются к элементам в приведенном выше коде, которые имеют значение атрибута id, равное test:


document.all["test"].length // 4
document.all.test.length // 4 (просмотр непосредственно // по значению id
document.all.test.tags("P").length // 2
document.all.test.item("test").length // 4 (избыточный код)

Окно Input в приведенном выше коде интересно тем, что является частью семейства, возвращаемого по атрибуту item ("test"), и представлено индивидуально в качестве элемента item ("foo"). Доступ к окну Input можно получить посредством семейства элементов со значением атрибута id, равным test:


document.all.test.item("foo").tagName // INPUT
document.all.foo.tagName // Также INPUT

Если значения атрибутов name и id элемента совпадают, то элемент, тем не менее, появляется в семействе элементов со значением name или id только один раз. Элемент может существовать в семействе только в одном экземпляре.


Различие между семейством и элементом

Когда программа обращается к элементу по значению name или id, то может быть возвращено семейство или элемент. Поэтому программа должна уметь различать, является ли возвращаемый объект элементом или семейством. В JavaScript свойство length возвращает null для отдельных элементов и число элементов для семейств. Свойство length возвращает null для отдельного элемента, поскольку оно в действительности не существует для объекта - JavaScript автоматически добавляет свойство length в объект со значением null по умолчанию.

Приведенный ниже код позволяет проверить, что было возвращено - семейство или элемент:


// Использование length
if (null == document.all["Gender"].length) {
// Одиночный элемент
}
else {
// Семейство }

Примечание: Нельзя использовать length в VBScript для выявления различия между индивидуальными элементами и семействами. Если вы попытаетесь это сделать, то VBScript сгенерирует ошибку, потому что данное свойство не существует для объекта элемента.


Ссылка на неизвестные имена элементов

Если метод item вызывается с использованием атрибутов name или id, которые не существуют в документе или еще не были загружены, то метод возвращает объект null:


var el = document.all.item("foo");
if (null == el) alert("Please try again when the page is loaded.");
else {
// Операции с элементом foo.
}


Прямой доступ к именованным элементам

Доступ к именованным элементам возможен посредством семейств. Kpoме того, некоторые именованные элементы также представляют собой свойства документа или окна. Такие элементы добавляются в документ и окно исключительно в целях обратной совместимости. Рекомендуемым способом доступа к данным элементам является использование семейства all.

При наличии атрибута name или id в документ добавляются элементы следующих типов: Form, IMG и Applet. Кроме того, все элементы с атрибутом id за исключением элементов ввода в форме добавляются прямо в окно, что позволяет обращаться к ним без использования семейства all документа:

<H1 ID="myH1">Welcome to My Page</H1>
<FORM ID="form 1">
<INPUT TYPE=TEXT ID="text1">
</FORM>
<SCRIPT LANGUAGE="JavaScript">
// Доступ к myH1 как свойству окна.
alert(myH1.id); // Output the id.
// Доступ к myH1 посредством семейства all.
alert(document.all.myH1.id);
// Элементы ввода в форме доступны посредством форму.
alert(form1.text1.id);
</SCRIPT>



Встроенные семейства

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

Таблица 7.1. Семейства и теги их элементов


Семейство Теги Описание

all All tags Все элементы в документе, в исходном порядке
anchors <A NAME=…> Закладки
applets <APPLET>; <OBJECT> Внедренные объекты и апплеты Java
forms <FORM> Формы
frames <IFRAME> Встроенные фреймы
images <IMG> Изображения
links <A HREF=…>; <AREA> Ссылки. Если элемент Anchor содержит атрибуты NAME и HREF, то он будет представлен в семействах links и anchors
scripts <SCRIPT> Сценарии

Вместо расширения данного списка произвольными тегами, семейства представляют метод tags для создания нового семейства, элементы которого выбраны по определенному тегу. Метод tags исключает необходимость смешения объектной модели с семейством для каждого типа элемента и позволяет разработчику определять интересующие его элементы.



Метод tags

Кроме метода item, все семейства элементов документа представляют метод tags. Метод tags использует параметр, представляющий тег как строку и возвращает семейство всех элементов с данным тегом, как показано в приведенном ниже коде:


<HTML>
<BODY>
<H1>My Header</H1>
<P>This is <STRONG>strong text</STRONG> and more <STRONG>strong</STRONG> text.</P>
<H1>Another Header 1</H1>
</BODY>
</HTML>

Приведенные ниже выражения используют метод tags для создания семейств элементов из предыдущего кода:


document.all.tags("H1") // Семейство всех элементов H1
document.all.tags("STRONG") // Семейство всех элементов Strong
document.all.tags("STRONG")[0] // Первый элемент Strong
document.all.tags("P").length // 1

В отличие от метода item метод tags всегда возвращает семейство, даже если на странице находится только один элемент. Например, вызов метода tags в элементе Body будет возвращать семейство, даже если существует только один элемент Body:


document.all.tags("Body") // Семейство с одним элементом Body
document.all.tags("Body")[0] // Первый элемент в семействе

Метод tags всегда возвращает семейство, поскольку он был разработан с одной целью - для отбора элементов из семейства и создания сокращенного семейства. Метод item возвращает одиночный элемент, который совпадает с идентификатором. Там, где обнаруживаются дублирующиеся элементы, метод возвращает семейство, а не ошибку.


Пустые семейства

Если метод tags вызывается для тега, который отсутствует в документе, то будет возвращено пустое семейство с нулевыми элементами:


;if (0 == document.all.tags("H1").length)
alert("There are no H1 elements in this document.");

Чтобы обеспечить возможность запроса и отбора неизвестных элементов, метод tags не возвращает ошибку, когда анализирует недействительный тег.


Индивидуальные семейства

Большинство встроенных семейств документа совпадают с семействами, которые можно создать, используя метод tags на основе семейства all. Например, семейство forms совпадает с семейством, созданным при вызове метода tags с параметром form. Приведенный ниже код создает семейство, эквивалентное семейству forms:


document.myforms = document.all.tags("form");

Можно создать индивидуальные семейства и добавить их в объект document, используя аналогичный метод, как показано в следующем примере:


// Create a tables collection on the document.
document.tables = document.all.tags("TABLE");

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

В приведенном выше коде продемонстрировано, что многочисленные семейства часто ссылаются на одинаковый набор элементов. Поэтому ссылка на элемент в любом семействе представляет собой то же самое, что и ссылка на элемент в семействе all. Например, приведенный ниже фрагмент кода возвращает значение true, поскольку на один объект была установлена ссылка из двух различных семейств:


// Both expressions point to the same object.
document.forms[0] == document.all.tags("FORM")[0];



Семейство all в документе с набором фреймов

Документ, который содержит набор фреймов, также поддерживает объект document и представляет то же семейство all. Элемент Frameset заменяет элемент Body в семействе all, поскольку документ может содержать традиционное содержание тела документа (body) или набора документов (frameset). Все элементы Frameset и Frame в документе приведены в порядке исходного кода, что полезно для определения расположения фреймов на экране:


<HTML>
<HEAD>
<TITLE> Демонстрация набора фреймов </TITLE>
</HEAD>
<FRAMESET ROWS="60, *"> <FRAME SRC="a.htm">
<FRAME SRC="b.htm">
</FRAMESET>
</HTML>

Семейство all для данного документа содержит элементы в следующем порядке: HTML, Head, Title, Frameset, Frame, Frame.

Кроме того, все атрибуты элементов Frameset и Frame представлены посредством семейства all. Большей части атрибутов могут быть присвоены новые значения, но в некоторых случаях значения атрибутов не пересчитываются. Например, когда граница набора фреймов не может быть изменена после воспроизведения набора фреймов на экране. Однако набор фреймов будет корректно обновляться, если изменить значения его атрибутов row и col, или значения атрибутов src или name одного из фреймов.

Семейства в документах с набором фреймов отличаются от семейств в других документах по отношению к включению нераспознаваемых элементов. В объектной модели представлены только те нераспознаваемые элементы, которые появляются перед первым тегом <FRAMESET>. При обнаружении тега <FRAMESET> все элементы, которые отличаются от Frameset и Frame, игнорируются и не учитываются в объектной модели. Игнорируются даже элементы NoFrames. Если элемент NoFrames находится перед элементом Frameset, то он представлен в семействе all, но содержание данного элемента является недоступным. Данное ограничение может быть снято в будущей версии Internet Explorer.



Структура и семейства HTML

В этом разделе внимание сосредоточено на образовании семейств документа во время анализа документа. Предполагается, что HTML-документы удовлетворяют правилам, установленным в определении типа документа (document type definition, DTD) HTML. Объектная модель HTML основана на этих правилах с учетом некоторых исключений, гарантирующих корректность построения структуры документа. Далее вводятся взаимоотношения между DTD и семействами, представленными в документе.



Построение семейства all

Семейство all непосредственно соотносится с деревом HTML-документа. Приведенный ниже HTML-документ демонстрирует данное отношение:


<HTML>
<HEAD>
<TITLE> Мой документ </TITLE>
</HEAD>
<BODY>
<H1>Welcome to My Page</H1>
<P>This is an <STRONG>important document.</STRONG></P>
</BODY>
</HTML>

На рис. 7.1 показаны связи между элементами в данном документе.

Рис. 7.1. Взаимосвязи между элементами в HTML-документе

Семейство документа all, которое содержит все элементы документа, представляет данное дерево. Семейство содержит элементы дерева в том порядке, в котором они встречаются в исходном коде. Анализатор создает семейство all, выполняя операцию, которая известна как прямое прослеживание (preorder traversal) дерева. Содержание и порядок элементов в семействе all в исходном состоянии в данном примере перечислены ниже: HTML, Head, Title, Body, H1, Paragraph, Strong.

Cемейство all всегда представляет текущее состояние документа. Можно изменить элементы в семействе all путем манипулирования динамическим содержанием, но семейство all всегда поддерживает порядок элементов, даже когда сценарии изменяют содержание. Манипулирование динамическим содержанием подробно обсуждается в главе 13.



Область действия

Дерево HTML содержит информацию, которую трудно получить в семействе all. А именно, область действия (scope) каждого элемента. Область действия элемента представляет собой набор содержащихся в нем элементов. Например, в предыдущем документе элемент Paragraph содержит элемент Strong, так что элемент Strong находится внутри области действия элемента Paragraph. Вы можете определить область действия элемента путем анализа свойств parentElement и children каждого элемента в семействе all. Эта процедура описана в главе 8.

Примечание: Семейство all, так же как и все семейства элементов, представляет элемент как одиночный объект. Элементы, а не индивидуальные открывающие и закрывающие теги, необходимы для манипулирования структурой документа. Поскольку представлены элементы, а не индивидуальные теги, то легче понимать и работать с семействами. Исключением из данного правила являются нераспознаваемые теги. В данном случае, любой нераспознаваемый тег, независимо от того, является тег открывающим или закрывающим, добавляется в семейство. Нераспознаваемые теги не имеют области действия и дочерних элементов. Данное ограничение очень подробно обсуждается ниже в разделе "Нераспознаваемые элементы" данной главы.



Неявные элементы

DTD для HTML определяет, что теги для элементов HTML, Head, Body и TBody являются необязательными в HTML-документе, поскольку данные элементы могут быть выведены из контекста документа, как показано в примере ниже:


<TITLE> Добро пожаловать в Мой документ </TITLE>
<H1>Welcome to My Page</H1>
<P>This is an <STRONG>important document.</STRONG></P>

Данный документ эквивалентен предшествующему документу. Деревья, и поэтому содержание семейств all, совпадают. Семейство all всегда представляет элементы HTML, Head и Body для каждого документа, независимо от того, указаны они явно или нет.



Разделение между Head и Body

В документе без тегов <HEAD> и <BODY> разделение между заголовком и телом документа определяется правилами HTML, как указано в DTD. Элемент Head содержит определенный набор элементов, которые отличаются от набора в элементе Body. Поэтому после обнаружения первого элемента Body (например, H1) область действия автоматически изменяется с заголовка на тело.

Приведенный ниже фрагмент кода представляет DTD для заголовка документа. Проверив данное DTD, можно более ясно проследить отличие между заголовком и телом документа:


<!ENTITY % head.misc "SCRIPT|STYLE|META|LINK"
-- повторяемые элементы заголовка -->
<!ENTITY % head.content "TITLE & ISINDEX? & BASE?">
<!ELEMENT HEAD O O (%head.content) +(%head.misc)>

Данный код показывает, что может быть не более одного элемента IsIndex и один элемент Base, что должен быть один элемент Title и любое число элементов, определенных компонентом head.misc. С учетом двух исключений, элементов Style и Script, наборы компонентов, доступных в заголовке и теле документа, различны. Поэтому анализатору легко определить, когда область действия переключается от заголовка к телу.

Элементы Style и Script неоднозначны, поскольку они существуют в заголовке и теле. Если элементы Style или Script обнаруживаются в документе до раздела тела, то элемент считается содержанием заголовка. Данное правило не влияет на воспроизведение или поведение документа, но его важно понимать, поскольку оно определяет область действия элементов Head и Body.


Необязательные завершающие теги

Для некоторых элементов в HTML не требуются закрывающие теги. Например, тег <Р> не требует наличия завершающего тега </Р> для обозначения его области действия. Для определения завершения параграфа (Paragraph) или других элементов используется определение DTD. Когда встречается элемент, который не может находиться в данной области, то его область действия считается завершенной. Как показано в следующем примере, если после тега <Р> следует тег <Н2>, то элемент paragraph заканчивается на теге <Н2>, поскольку элемент Н2 не может быть дочерним элементом элемента Paragraph.


<HTML>
<H1>Scott's Home Page</H1>
<P>Welcome to my page.<H2>New Cool Stuff</H2>
</HTML>

Дерево на рис. 7.2 представляет документ HTML. Обратите внимание, что элемент Н2 является дочерним элементом Body, а не элемента Paragraph.

Рис. 7.2. Диаграмма дерева документа с неявными тегами завершения

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



Нераспознаваемые элементы

Важность анализа нераспознаваемых элементов в HTML-документе увеличивается по мере развития браузеров. Представьте себе введение тега <Н7>. Новые браузеры будут интерпретировать <Н7> как тег контейнера блока, но браузеры предыдущих версий не будут его распознавать. В сочетании с правилами HTML теги начала и завершения <Н7> игнорируются при воспроизведении документа гипотетическим браузером низкого уровня, поскольку для нераспознаваемых тегов недоступна информация определения DTD для установки правил и области действия тега.

Поскольку отсутствует определение типа документа (DTD) для нераспознаваемых элементов, то нераспознаваемые открывающие и закрывающие теги представлены в семействе all. В отличие от правил HTML, в которых установлено, что нераспознаваемые элементы должны быть проигнорированы, объектная модель включает нераспознаваемые теги для того, чтобы обеспечить разработчику полную информацию о документе.

Представлен также нераспознаваемый закрывающий тег, поскольку отсутствует способ точного определения, является ли документ контейнером. Даже если открывающие и закрывающие теги появляются в документе последовательно, то нет гарантии, что их использование согласуется с правилом DTD, если оно существует для данного элемента. Например, элемент может быть не определен в DTD как элемент-контейнер. Поэтому оба нераспознаваемых открывающих и закрывающих тега всегда представлены как конечные узлы (leaf nodes) в дереве:


<HTML>
<P>Welcome to my <FOO><B>cool</B> document.</FOO></P>
</HTML>

Дерево на рис. 7.3 демонстрирует, как внутренний анализатор представляет данный документ с нераспознаваемыми элементами.

рис. 7.3. Диаграмма дерева с нераспознаваемыми тегами начала и конца <FOO>

Семейство all в предыдущем примере содержит следующие элементы: HTML, Head, Body, Paragraph, <FOO>, Bold, </FOO>. Обратите внимание, что элемент Bold считается дочерним элементом элемента Paragraph, а не элемента Foo. Поскольку информация DTD об элементе Foo недоступна, то отсутствует способ надежного определения, является ли элемент Foo контейнером. Для нераспознаваемых элементов открывающие и закрывающие теги позволяют разработчику рассчитать область действия элемента путем просмотра семейства all вручную.

Если в будущей версии Internet Explorer элемент Foo станет действительным элементом HTML и сможет содержать текст, то изменится дерево документа. Новое дерево показано на рис. 7.4.

Порядок элементов будет согласован в различных реализациях, но число элементов и дерево документа могут сильно отличаться в зависимости от поддержки элемента Foo. Данное различие может привести к возникновению проблем, если ваша программа учитывает порядковое положение элементов в семействе, поскольку число представленных элементов может изменяться от браузера к браузеру. Напротив, код, который обращается к определенному элементу, должен всегда использовать идентификатор ID или идентифицировать элемент в более явном контексте.

Все нераспознаваемые закрывающие теги также представлены в объектной модели, поскольку объектная модель не пытается связать недействительные открывающие и закрывающие теги и принимает их в семейство так, как они определены в документе. Поэтому если тег </BAR> находится в середине документа, то он будет представлен в семействе all, даже если отсутствует открывающий тег <BAR>.

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



Непарные закрывающие теги

При обнаружении непарного закрывающего тега, который распознается анализатором, HTML устанавливает, что закрывающий тег должен игнорироваться. Однако так же как и для нераспознаваемых тегов, непарные закрывающие теги представлены в семействе all. В приведенном ниже примере закрывающий тег </В> представлен в объектной модели:


<HTML>
This is not bold.</B>
</HTML>

Закрывающий тег представлен в модели, поскольку объектная модель пытается поддерживать точное представление документа.



Перекрывающиеся элементы

Перекрытие элементов возникает, когда в документе не поддерживается действительная иерархия контейнеров. Приведенный ниже пример показывает перекрытие элементов Strong и ЕМ:


<HTML>
<BODY>
<P>This is a <STRONG>demonstration of
<EM>overlapping</STRONG> elements.</EM></P>
</BODY>
</HTML>

Элементы перекрываются, но не влияют на расположение или порядок семейства all. Семейство all состоит из следующих элементов: HTML, Head, Body, Paragraph, Strong, ЕМ. Дерево данного документа, показанное на рис. 7.5, не показывает перекрытия элементов или реальную область действия каждого элемента.

Рис. 7.5. Диаграмма дерева документа с перекрывающимися элементами

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


<HTML>
<BODY>
<P>This is a <STRONG>demonstration of
<EM>overlapping</EM></STRONG><EM> elements.</EM>
</P>
</BODY>
</HTML>

Перекрытие элементов имеет незначительное влияние на большинство семейств, но семейство элемента children может быть некорректным.

Взаимоотношения между перекрывающимися элементами и содержанием документа являются строгими и обсуждаются в главе 13.



Содержание без тегов

Содержание без тегов - это текст, который не содержится ни в одном элементе. Такой текст часто появляется внутри тела документа:


<HTML>
<BODY>
В данной строке отсутствуют теги.
<P> Данная строка находится в элементе Paragraph. </P>
Данная строка находится после элемента Paragraph и не содержит тегов.
</BODY>
</HTML>

Семейство all этого HTML-документа будет содержать только элементы HTML, Head, Body и Paragraph. Отсутствуют элементы, которые представляют текст за пределами контейнеров. В строгом HTML считается, что данный текст находится внутри элемента Paragraph. Однако тег <Р> не может быть синтезирован в данном случае, поскольку явно определенные параграфы имеют несколько отличную схему воспроизведения.



Недействительный HTML

Динамический HTML разработан для работы с действительным HTML. Поэтому теги, которые помещены за пределами их области действия, обычно обрабатываются как нераспознаваемые элементы. Данное правило не является зафиксированным, однако в некоторых случаях HTML может быть исправлен в ходе анализа документа. Например, в коде находится приведенное ниже неправильное определение таблицы:


<HTML>
<BODY>
<TD> Ячейка таблицы за пределами таблицы. </TD>
</BODY>
</HTML>

В данном документе ячейка таблицы появляется в области, к которой она не принадлежит, - за пределами таблицы. Во время обработки документа ячейка таблицы не распознается и обрабатывается как нераспознаваемый элемент. Поэтому открывающие и закрывающие теги считаются анализатором недействительным. Семейство all представляет элементы данного документа HTML в следующем порядке: HTML, Head, Body, <TD>, </TD>.

He следует писать документы, полагаясь на данное поведение. Браузеры могут исправить код HTML или не вносить никаких изменений и проигнорировать неправильно помещенные элементы. Единственной гарантией того, что семейство элементов построено согласованно, является создание действительных элементов HTML.

Существует несколько известных исключений, для которых дерево документа не будет соответствовать определению типа документа HTML. Данные Исключения существуют, поскольку они появляются в большом числе документов в Internet. Здесь обсуждаются далеко не все исключения, но они часто встречаются в HTML-документах.



Списки

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

Первое исключение было разрешено в Netscape Navigator 2.0 для создания маркированных списков без отступа. Второе исключение возникло вследствие общей некорректной практики создания вложенных списков.

При обнаружении первого исключения Netscape Navigator 2.0, реализация которого была поддержана в Internet Explorer 3.0, воспроизводит элемент списка без отступа. Хотя определения типа документа для элементов LI запрещают их существование за пределами списков, определение DTD, которое используется для создания показанного в следующем коде дерева, является неопределенным и не осуществляет автоматический переход на новую строку элементов LI.


<HTML>
<BODY>
<LI> Данный элемент LI находится за пределами списка. </LI>
</BODY>
</HTML>

Элементы в семействе all данного документа располагаются в следующем порядке: HTML, Head, Body, LI.

Второе исключение, в котором вложенные списки используются целиком для увеличения отступа маркера списка, продемонстрировано ниже:


<HTML>
<BODY>
<UL>
<UL>
<LI> Элемент маркированного списка с большим отступом. </LI>
</UL>
</UL>
</BODY>
</HTML>

Этот код HTML нарушает правила DTD, поскольку элементы UL могут содержать только элементы LI, а не другие элементы UL. При обнаружении данной ситуации исправление кода не производится. Порядок элементов в семействе all для данного документа таков: HTML, Head, Body, UL, UL, LI.


Элементы форм в таблицах

Также общепринято использовать формы в таблицах (за пределами ячеек) для создания формы, которая охватывает многочисленные строки или ячейки, как показано ниже:


<HTML>
<HEAD>
<TITLE> Формы в таблицах </TITLE>
</HEAD>
<BODY>
<TABLE>
<FORM NAME="Form1">
<TR><TD>Form1-related fields</TD></TR>
<TR><TD>More Form1-related fields</TD></TR>
</FORM>
<FORM NAME="Form2">
<TR><TD>Form2-related fields</TD></TR>
</FORM>
</TABLE>
</BODY>
</HTML>

В этом документе формы будут поддерживаться с корректной областью действия внутри таблицы.

Дерево для данного документа представлено на рис. 7.6.

Рис. 7.6. Диаграмма дерева для документа с элементами Form внутри элемента Table

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