eXtensible Markup Language 2

eXtensible Markup Language Продолжение. Начало в КГ №27
В прошлый раз мы остановились на описании спецификации DTD для XML-документов. Это очень важный момент, так как правильно составленный DTD позволяет гарантировать структурированность XML-документа и выявление всех неточностей. В этой статье мы продолжим знакомство с XML и его расширениями.

Поговорим о пространствах имен в XML. Эта заслуживающая внимания тема имеет место не только в XML, но и во многих языках программирования, таких, как, например, C++. По мере того, как появляются все новые и новые XML-совместимые языки разметки, разработчики предпочитают использовать уже созданные, нежели создавать свой собственный, с нуля. Однако, имена некоторых элементов могут совпадать в двух разных языках разметки. И анализатор не сможет понять, к какому языку отнести данный элемент. Решению таких неоднозначностей и служат пространства имен (namespaces).
Приведем пример XML-документа, в котором используются пространства имен.
<nsp1:root xmlns:nsp1 = "http://www.litvinuke.hut.ru/test-ns1"
xmlns:nsp2 = "http://www.litvinuke.hut.ru/test-ns2">
<nsp1:node>
<nsp1:element> Элемент 1</nsp1:element>
<nsp1:element> Элемент 2</nsp1:element>
<nsp1:element> Элемент 3</nsp1:element>
</nsp:node>

<nsp2:node>
<nsp2:element> Элемент 1</nsp2:element>
<nsp2:element> Элемент 2</nsp2:element>
<nsp2:element> Элемент 3</nsp2:element>
</nsp2:node>

</nsp1:root>
Как видно из этого примера, пространства имен определяются внутри корневого элемента. xmlns:nsp1 = "http://www.litvinuke.hut.ru/test-ns1" определяет пространство имен c идентификатором nsp1. "http://www.litvinuke.hut.ru/test-ns1" наделяет каждое из пространств имен уникальностью, нет необходимости в указании валидного (существующего) URL. Главное, чтобы он был уникален. Это сродни именованию пакетов в Java.
После того как вы определили необходимые пространства имен, каждый элемент, принадлежащий определенному пространству, должен помечаться как таковой. Как это делать, показано на приведенном примере. В первом случае элемент <node> </node> принадлежит пространству имен nsp1, а второй — nsp2. Это же относится и к элементам <element> </element> . Таким образом мы решили проблему неопределенности для анализатора XML-документа и подчеркнули уникальность этих элементов.
Попытаемся определить DTD для нашего примера. По спецификации в DTD мы также вправе использовать необходимые префиксы пространств имен. Вот как это будет выглядеть:
<!DOCTYPE nsp1:root
[
<!ELEMENT nsp1:root (nsp1:node, nsp2:node)*>
<!ATTLIST nsp1:root
xmlns:nsp1 CDATA #FIXED "http://www.litvinuke.hut.ru/test-ns1"
xmlns:nsp2 CDATA #FIXED "http://www.litvinuke.hut.ru/test-ns2">
<!ELEMENT nsp1:node (nsp1:element)*>
<!ELEMENT nsp1:element (#PCDATA>
<!ELEMENT nsp2:node (nsp2:element)*>
<!ELEMENT nsp2:element (#PCDATA>
]>
Вот так могло бы выглядеть определение DTD для нашего XML-документа.
Для того чтобы определить пространство имен, используемое по умолчанию (написание элементов без префиксов), нужно задать значение атрибута xmlns в корневом элементе, например:
<root xmlns = "http://www.litvinuke.hut.ru/ test-ns1"
xmlns:nsp = "http://www.litvinuke.hut.ru/ test-ns2">

<node>
<element> Элемент 1</element>
<element> Элемент 2</element>
<element> Элемент 3</element>
</node>

<nsp:node>
<nsp:element> Элемент 1</nsp:element>
<nsp:element> Элемент 2</nsp:element>
<nsp:element> Элемент 3</nsp:element>
</nsp:node>
</root>
Так мы избавились от необходимости использовать несколько префиксов. Пространство имен по умолчанию применяется ко всем элементам XML-документа без префикса. Использование пространств имен не является обязательным, и многие их игнорируют. Но если вы рассчитываете на то, что вашими разработками будут пользоваться другие, то лучше принять правила хорошего тона и включить в свои XML-документы namespaces.
Поговорив о пространствах имен, плавно переходим к следующей спецификации — XLink. Из названия можно догадаться, что эта спецификация предназначена для стандартизации связывания XML-документов друг с другом. Казалось бы, зачем нужен XLink, когда уже существуют гиперссылки HTML? На самом деле HTML-гиперссылка является одним из видов ссылок, определяемых с помощью XLink. Потом, обычные гиперссылки не могут позволить осуществлять связи "один-ко-многим" и прочее. Давайте рассмотрим, как и какие виды ссылок мы можем описывать при помощи XLink. Для начала один нюанс. Для использования xlink необходимо объявить в XML-документе соответствующее пространство имен:
<root xmlns:xlink = http://www.w3c.org/ 2002/xlink/namespace/ >
</root>
Только после этого вы можете объявлять ссылки XLink. Рассмотрим существующие типы ссылок. Их всего семь.
simple — представляет собой обыкновенную ссылку, полный аналог гиперссылки в HTML.
extended — для ссылок этого типа возможны разнообразные связи: один-ко-многим, двусторонняя связь и пр.
locator — ссылка этого типа унифицирует элемент, ссылающийся на удаленный ресурс.
arc — используется совместно с exten-ded-ссылкой и определяет различные атрибуты переходов, поведение и пр.
resource — указывает на локальные ресурсы. Используется совместно с extended.
title — определяет заголовки ссылок.
none — не ссылка. Используется для условных конструкций.
Атрибуты ссылок разделяются на четыре группы: местонахождения удаленного ресурса или локального, направления ссылок и атрибуты поведения. Атрибуты поведения определяют, каким образом ссылка будет активироваться. В случае с HTML все очень статично: переход осуществляется по нажатию на область ссылки (только с использованием различных скриптовых вставок, например на JavaScript, мы можем немного изменить это условие, но это уже будет ссылка, объявленная не средствами HTML).
К первой группе относится атрибут href. Он определяет ресурс, на который указывает ссылка, в формате URI.
Ко второй — атрибуты to и from. В основном предназначены для выдачи контекстно-зависимой помощи. За дополнительной информацией по этим атрибутам обращайтесь к спецификации XLink по адресу http://www.w3c.org/TR.
К третьей show и actuate. show — определяет действие, которое будет выполнено при переходе по ссылке, а actuate — условие, по которому будет выполнен этот переход.
Атрибут show может принимать следующие значения:
embed — ресурс будет загружен в тело текущего документа (откуда была вызвана ссылка), с позиции месторасположения этой ссылки.
replace — ресурс будет загружен вместо текущего документа.
new — ресурс должен быть открыт в новом окне.
undefined — не определено. Власть переходит в руки анализатора либо программы, обрабатывающей этот документ.
Значения атрибута actuate:
onLoad — переход по загрузке текущего документа.
onRequest — переход по внешнему прерыванию (например, нажатие клавиши мыши).
undefined — аналогично, как и у show.
Приведем несколько примеров ссылок в соответствии со спецификацией XLink:
<my_link xlink:type = "simple" xlink: show = "replace" xlink:actuate = "onRequest" xlink:href = "http://www.litvinu-ke.hut.ru/articles/aboutxml2.rtf">
eXtensible Markup Language (2)</my_link>

<new_link xlink:type = "simple" xlink: show = "new" xlink:actuate = "onLoad" xlink:href = "http://www.w3c.org/"> WWW Consortium</new_link>
Указывая атрибуты ссылок Xlink, необходимо использовать префикс определенного вами пространства имен. В нашем случае это xlink. По активации первой ссылки путем внешнего прерывания текущий документ будет заменен на удаленный ресурс, определенный атрибутом xlink:href. Во втором случае ссылка активируется сразу по загрузке текущего документа, и ресурс будет загружен в новом окне.
Было бы нечестно не рассмотреть пример использования расширенных ссылок. Они используются в основном для того, чтобы указывать на несколько ресурсов одновременно.
<ext_link xlink:type = "extended">
<element xlink:type = "locator" xlink: href = "http://www.litvinuke.hut.ru/in-dex.php" xlink:role = "main"/>
<element xlink:type = "locator" xlink: href = "http://www.litvinuke.hut.ru/ lnk101.html" xlink:role = "about"/>
</ext_link>
Новый атрибут xlink:role предназначен для описания ссылки. Он относится к группе семантических атрибутов ссылок. В эту группу также входит атрибут title.
Столь же плавно перейдем к рассмотрению очередной и, наверное, последней спецификации на этот раз — это XPointer. Предназначена она для стандартизации описания путей месторасположения в самом XML-документе. Эта спецификация намного сложнее и объемнее, нежели Xlink, и здесь очень бы пригодились знания в организации DOM (Document Object Model) дерева. Но об этом мы поговорим намного позже. Сейчас на горизонте XPointer. Эта спецификация фактически целиком основана на спецификации XPath. XPointer, равно как и XSLT, использует язык XPath для описания URL на элементы DOM-дерева (части XML-документа).
Путь к какой-либо определенной части XML-документа разбивается на несколько этапов (шагов), разделяемых символами / (прямой слэш). Например:
/node::element
За двойным двоеточием следует шаблон, по которому мы адресуем наш указатель. В контексте данного примера мы ссылаемся на все элементы element, находящиеся в элементе node. Начальный / означает абсолютное местонахождение корневого элемента. Вместо или совместно с именами обычных элементов можно использовать специальные ключевые слова:
child — определяет вложенные узлы;
descendant — определяет любые узлы, которые находятся ниже уровня текущего узла;
parent — определяет родительский узел для текущего элемента;
ansector — любые узлы, которые содержат текущий узел;
preceding — любые из узлов, расположенных выше текущего;
following — любые из узлов, распложенных ниже текущего;
preceding-sibling — предыдущий узел, у которого общий родитель с текущим узлом (брат);
following-sibling — следующий узел-брат;
attribute — определяет атрибут текущего узла;
namespace — определяет пространство имен текущего узла;
self — определяет сам текущий узел;
descendant-or-self — текущий узел либо все остальные узлы-потомки;
ancestor-or-self — текущий узел либо все остальные узлы-родители.
Существуют также некоторые параметры для более гибких фильтров на выборки узлов. Помимо этих параметров, для того чтобы ограничить круг возвращенных узлов, существуют предикаты. Приведем пример:
<root>
<node>
<element type = "type1"> Элемент 1</element>
<element type = "type2"> Элемент 2</element>
</node>
</root>
Для того чтобы выбрать элемент <element/>, у которого значение атрибута type == "type1", мы можем использовать следующую конструкцию:
/node::element[attribute::type = "type1"]
Как видно, предикаты заключаются в квадратные скобки. Для придания функциональности предикатам в них можно использовать набор предопределенных функций. Я не буду приводить их полный список по той причине, что он довольно объемный, но вот самые широко используемые из них:
number position() — возвращает число, соответствующее месторасположению текущего узла;
node-set id(object) — выбирает узлы по его уникальному идентификатору (атрибут ID);
number count(node-set) — возвращает количество узлов в node-set;
boolean start-with(string, string) — возвращает истину, в случае если в начале первой строки содержится вторая строка. Или ложь, если это не так;
boolean contains(string, string) — возвращает истину, если в первой строке есть вхождение второй строки, иначе ложь;
boolean not(boolean) — возвращает результат выполнения операции NOT над выражением;
number round(number) — округляет число до наиболее близкого целого значения.
Я привел список некоторых из существующих функций лишь для того, чтобы вы могли видеть, что они могут вам дать. Для более детального ознакомления с полным списком обратитесь к спецификации по XPointer и XPath.
Также желательно знать, что после оператора :: не обязательно должно идти имя выбираемых узлов. Например, если мы хотим выбрать текст из определенного элемента, то можно воспользоваться типом проверки text(), если комментарии, то — comment() и пр. Например:
/node::text()[attribute::type = "type1"]
В этом случае в результате мы имеем "Элемент 1".
Указатель XPointer выглядит, как обычная функция, которой передается в качестве параметра выражение XPath:
xpointer(/node::element[attribute::type = "type1"])
Приведем пример использования функций в предикатах:
<root>
<node id = "1">
<element type = "type1"> Элемент 1 </element>
<element type = "type2"> Элемент 2 </element>
</node>
<node id = "2">
<element type = "type2"> Элемент 3 </element>
<element type = "type2"> Элемент 4 </element>
</node>
</root>

xpointer(id("1")/child::element[position() = 2])
Будет выбран "<element type = "type2"> Элемент 2 </element> "
xpointer(id("1")/child::text()[attribute::type = "type2"])
Будут выбраны следующие строки: "Элемент 2, "Элемент 3", "Элемент 4".
На этом все. В следующий раз мы затронем не менее важные темы, касающиеся XML и его спецификаций.

Алексей Литвинюк


Компьютерная газета. Статья была опубликована в номере 30 за 2002 год в рубрике программирование :: разное

©1997-2024 Компьютерная газета