ООП   XML   СУБД   ЯиМП   3GL   4GL   5GL   технологии прогр.

Язык XML. Объектно-ориентированное программирование

Типы парсеров XML

На сегодня существует два типа парсеров. Один из них базируется на событиях, а второй - на объектной модели представления документа. Рассмотрим их по порядку.

SAX2

Simple API for XML (SAX) - это API, позволяющий создавать приложения, читающие данные из XML-документов. Последняя версия этого API - SAX2.

Реализация SAX2, предоставляющая интерфейсы Visual Basic и Visual C++, предлагает простую и быструю альтернативу DOM. При использовании DOM файл считывается, разбивается на индивидуальные объекты (элементы, атрибуты и комментарии), и на этой основе в памяти строится древовидная структура документа. Выгода тут в том, что можно работать с каждым отдельным узлом. Но создание такой структуры для большого документа требует большого количества памяти.

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

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

SAX может оказаться полезен и при обработке, изменяющей структуру документа. Например, можно взять элементы высокого уровня (заголовки) из одного файла, и наполнить получившиеся секции содержанием (например, новостями) из других источников. С такой задачей SAX справится быстрее, чем DOM.

Однако эти преимущества сопровождаются не менее значимыми недостатками. Поскольку документ не хранится в памяти, с данными приходится работать в порядке поступления. В результате SAX малопригоден для работы с внутренними ссылками, например, атрибутами ID и IDREF.

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

И, наконец, наиболее распространенные сегодня браузеры (например, IE) не имеют встроенной поддержки SAX.

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

Здесь мы не будем подробно разбирать работу с SAX, но в дальнейшем, возможно, вернемся к этой теме.

XSL

Из того, что никто не может изобрести браузер, отображающий всё, что взбредет в голову разработчику, вытекает необходимость возложить создание интерпретатора (или хотя бы инструкций для некого общего интерпретатора) на разработчика же. То есть, сам написал - сам и читай. Так и возник XSL - Extensible Stylesheet Language, позволяющий привести XML к виду, не только доступному для понимания браузером, но и не оскорбляющему человеческий глаз общей корявостью. XSLT (XSL Transformations) - это развитие XSL, впрочем, различия между ними не принципиальны.

XSLT (его принято именовать списком стилей, style sheet - но к привычным любому Web-разработчику стилевым листам (CSS) он не имеет ни малейшего отношения, а названия XSL/XSLT являются простым недоразумением) содержит набор шаблонов, применяемых к элементам документа и создающих желаемую выходную структуру, и определяет данные исходного документа, к которым применяются эти шаблоны. Такая модель слияния данных и шаблона называется моделью, управляемой шаблоном (template-driven model), и лучше всего работает с однообразными повторяющимися данными. Эта модель должна быть знакома разработчикам ASP, вставляющим куски скриптов в HTML-шаблон для управления обработкой и генерацией данных.

Но XSLT предоставляет и возможности работы с крайне неоднородными данными, типичными для документов. Определяются фрагменты шаблона, и процессор XSLT объединяет результат работы этих фрагментов в конечное дерево, основанное на виде исходных данных. В каждом фрагменте шаблона объявляются тип и контекст исходных узлов, для которых предназначен этот фрагмент, что позволяет процессору XSLT сопоставлять исходные узлы с фрагментами шаблона. Такая модель известна, как модель, управляемая данными (data-driven model), так как именно вид данных управляет видом конечного результата.

Обе модели можно использовать в одном шаблоне, что делает XSLT применимым в широчайшем круге XML-приложений.

Говоря проще, содержимое конечного документа зависит как от содержимого исходного документа, так и от применяемых шаблонов.

Создание HTML-шаблона

Как мы уже говорили, XSL позволяет превратить один XML в другой. Но, поскольку HTML - это один из частных случаев XML, одно из типичных применений XSLT - создание HTML-представления XML-данных. HTML гораздо больше прощает разработчику, чем XML, поэтому не всякий HTML-документ является корректным с точки зрения XML. Но средствами XML нетрудно добиться полного соответствия результирующего документа синтаксису HTML. Рассмотрим следующий пример.

<?xml version="1.0"?>
<portfolio xmlns:dt="urn:schemas-microsoft-com:datatypes">
  <stock exchange="nyse">
    <name>zacx corp</name>
    <symbol>ZCXM</symbol>
    <price dt:dt="number">28.875</price>
  </stock>
  <stock exchange="nasdaq">
    <name>zaffymat inc</name>
    <symbol>ZFFX</symbol>
    <price dt:dt="number">92.250</price>
  </stock>
  <stock exchange="nasdaq">
    <name>zysmergy inc</name>
    <symbol>ZYSZ</symbol>
    <price dt:dt="number">20.313</price>
  </stock>
</portfolio>

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

<HTML>
  <BODY>
    <TABLE BORDER="2">
      <TR>
        <TD>Symbol</TD>
        <TD>Name</TD>
        <TD>Price</TD>
      </TR>
      <!-- повторяем следующие строки для каждой акции -->
      <TR>
        <TD><!-- место для символа --></TD>
        <TD><!-- место для имени --></TD>
        <TD><!-- место для цены --></TD>
      </TR>
    </TABLE>
  </BODY>
</HTML>

Чтобы заполнить эту таблицу данными из XML-файла, можно, конечно, вручную (например, через ASP) заменить комментарии данными из XML-файла, но для этой работы, собственно, и предназначен XSLT. Элементы из пространства имен XSLT используются для поиска данных в XML-файле и вставки их в HTML-шаблон.

<HTML>
  <BODY>
    <TABLE BORDER="2">
      <TR>
        <TD>Symbol</TD>
        <TD>Name</TD>
        <TD>Price</TD>
      </TR>
      <xsl:for-each select="portfolio/stock">
        <TR>
          <TD><xsl:value-of select="symbol"/></TD>
          <TD><xsl:value-of select="name"/></TD>
          <TD><xsl:value-of select="price"/></TD>
        </TR>
      </xsl:for-each>
    </TABLE>
  </BODY>
</HTML>

Элемент <xsl:for-each> находит в XML-данных набор элементов (элементы "stock" внутри элементов "portfolio") и применяет к каждому из них часть шаблона. В этом примере три элемента stock, поэтому создано будет три строки.

Атрибут select описывает, как найти набор элементов в исходном документе. Синтаксис этого атрибута зовется образцом (pattern), и подробнее о нем и ему подобных можно прочитать в разделе, посвященном XPath.

Внутри элемента <xsl:for-each> вы можете перебрать по очереди дочерние элементы каждого элемента "stock". Элемент <xsl:value-of> выбирает отдельный дочерний элемент и затем вставляет в шаблон его текстовое содержимое.

Теперь можно превратить предыдущий шаблон в настоящий XSLT-шаблон, поместив его в XML и заключив в элементы <xsl:stylesheet>.

<?xml version='1.0' encoding='windows-1251'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="/">
    <HTML>
      <BODY>
        <TABLE BORDER="2">
          <TR>
            <TD>Symbol</TD>
            <TD>Name</TD>
            <TD>Price</TD>
          </TR>
          <xsl:for-each select="portfolio/stock">
            <TR>
              <TD><xsl:value-of select="symbol"/></TD>
              <TD><xsl:value-of select="name"/></TD>
              <TD><xsl:value-of select="price"/></TD>
            </TR>
          </xsl:for-each>
        </TABLE>
      </BODY>
    </HTML>
  </xsl:template>
</xsl:stylesheet>

Поскольку этот шаблон сам является XML-файлом, он начинается с XML-декларации. Элемент <xsl:stylesheet> означает, что этот документ является шаблоном, и сообщает место объявления пространства имен XSLT. Microsoft Internet Explorer 5.0 поддерживает URL пространства имен XSL http://www.w3.org/TR/WD-xsl. Текущая версия MSXML поддерживает как http://www.w3.org/TR/WD-xsl, так и пространство имен XSLT с URL http://www.w3.org/1999/ XSL/Transform. Американцам, конечно, все равно, но нам с вами придется в обязательном порядке ввести в определение XML что-нибудь вроде "encoding='windows-1251'". Желающие могут ввести KOI-8 или что угодно другое - но сделать это нужно во избежание получения абракадабры в конечном результате.

Чтобы превращение произошло, необходимо заставить кого-нибудь выполнить соответствующие заклинания. В XML-файл можно добавить инструкции, показывающие, какой шаблон нужно использовать. Имя шаблона из предыдущего примера - "stock.xsl", стало быть, нужно вписать <?xml-stylesheet type="text/xsl" href="stock.xsl"?> сразу за <?xml version="1.0"?>. Это приведет к автоматическому преобразованию файла при его открытии браузером. Другим способом применения XSLT-шаблона является использование DOM, например, с помощью MSXML. Подробнее об этом сказано в разделе, посвященном DOM. На сегодня второй способ выглядит несколько более жизнеспособным, так как не все браузеры умеют работать с XSLT, а программную обработку можно встроить в скрипты на сервере.

Конечный результат работы XSLT будет выглядеть так:

<HTML>
  <BODY>
    <TABLE BORDER="2">
      <TR>
        <TD>Symbol</TD>
        <TD>Name</TD>
        <TD>Price</TD>
      </TR>
      <TR>
        <TD>ZCXM</TD>
        <TD>zacx corp</TD>
        <TD>28.875</TD>
      </TR>
      <TR>
        <TD>ZFFX</TD>
        <TD>zaffymat inc</TD>
        <TD>92.250</TD>
      </TR>
      <TR>
        <TD>ZYSZ</TD>
        <TD>zysmergy inc</TD>
        <TD>20.313</TD>
      </TR>
    </TABLE>
  </BODY>
</HTML>

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

А как быть, если этого нельзя знать заранее? Как говорилось выше, XSLT имеет механизмы для управляемых данными преобразований, которые формируют результат из фрагментов шаблона, основываясь на структуре обрабатываемого документа. Это особенно важно для XML, представляющего собой сложные структуры данных или документы. Если известно, какие типы элементов могут встретиться в исходном XML, но не их порядок, старшинство и взаимоотношения, придется использовать именно такую модель.

Это звучит сложно, но большинство документов оказываются именно такими.

XML Path Language, XPath

XML Path Language (XPath) - это язык, разработанный специально для использования с XML и применяемый для поиска узлов и наборов узлов XML-документа в таких технологиях, как DOM и XSLT. Он представляет собой некий гибрид между указанием пути в командной строке и регулярными выражениями. XPath представляет XML-документ в виде дерева из узлов различных типов - элементов, атрибутов и текста. Выражения XPath могут идентифицировать эти узлы по их типу, имени и значениям, а также по взаимоотношениям узлов в документе.

Например, запрос "найти элементы 'author' с атрибутом 'period' и значением 'classical', содержащиеся в элементе 'authors' в документе root" может быть записан как XPath-выражение "/authors/author[@period='classical']".

Эти выражения лежат в основе XSLT, позволяя ассоциировать найденные с помощью таких выражений ветви документа с XSLT-шаблоном. Выражения, использующие синтаксис XPath, могут использоваться напрямую в XML Document Object Model (DOM).

Важной разновидностью XPath-выражений являются location path:, выражения, выбирающие набор узлов, относящихся к узлу контекста. Результатом выполнения такого выражения является набор узлов, содержащий выбранные узлы.

Синтаксис XPath

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

Файловая система (URL)

XPath

Иерархия каталогов и файлов.

Иерархия элементов и других узлов XML-документа.

Файлы на каждом из уровней имеют уникальные имена. URL всегда идентифицирует один файл.

Имена элементов на каждом уровне могут быть неуникальны. Шаблоны XPath соответствуют набору всех соответствующих элементов.

Путь вычисляется относительно конкретного каталога, именуемого текущим каталогом.

Путь вычисляется относительно конкретного узла, в запросе именуемого контекстом.

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

<authors>
  <author>
    <name>Victor Hugo</name>
    <nationality>French</nationality>
  </author>
  <author period="classical">
    <name>Sophocles</name>
    <nationality>Greek</nationality>
  </author>
  <author>
    <name>Leo Tolstoy</name>
    <nationality>Russian</nationality>
  </author>
  <author>
    <name>Alexander Pushkin</name>
    <nationality>Russian</nationality>
  </author>
  <author period="classical">
    <name>Plato</name>
    <nationality>Greek</nationality>
  </author>
</authors>

При исполнении XPath-запроса всегда имеется так называемый контекст исполнения, то есть текущая ветка, относительно которой производится поиск. Это сходно с активным каталогом при выполнении команды CD файловой системы. Как контекст XPath-запроса может использоваться любой узел XML-документа. В XSLT контекстом для запроса является узел, в данный момент обрабатываемый элементами <xsl:template> или <xsl:for-each>. При использовании XPath непосредственно из DOM вы определяете контекст, выполняя запрос из конкретного узла. Приведенные ниже примеры используют контекст корневого элемента XML-документа.

Основным понятием XPath является путь в XML-иерархии. Если выполнить приведенный ниже запрос, начиная с корневого элемента приведенного выше примера, этот запрос проходит по иерархии вплоть до элемента <name>.

authors/author/name

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

Кроме описания пути, XPath может включать wildcards (групповые символы). Элемент с любым именем обозначается символом "*".

authors/*/name

Предыдущий запрос соответствует всем элементам name, но не требует, чтобы они находились в элементе <author>. Вот еще один пример, находящий элементы <name> и <nationality>.

authors/author/*

Ветвления пути могут быть описаны с помощью квадратных скобок. Следующий запрос ищет ветку элемента <author>, и означает, что рассматриваться должны только элементы <author> с дочерним nationality.

authors/author[nationality]/name

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

authors/author[nationality='Russian']/name

XML-атрибуты в запросе обозначаются символом "@" перед именем атрибута. Атрибут может проверяться как ветка основного пути, но запрос может и целенаправленно искать узлы атрибутов. Следующий пример возвращает авторов классического периода.

authors/author[@period="classical"]

Таблица 4.Операторы и специальные символы XPath

Оператор

Описание

/

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

//

Рекурсивный спуск; ищет указанный элемент на любой глубине. При использовании в начале шаблона означает рекурсивный поиск от корневого элемента.

.

Текущий контекст.

*

Wildcard, выбирает все элементы, независимо от имени.

@

Атрибут; префикс имени атрибута. При использовании без имени атрибута выбирает все атрибуты, независимо от их имени.

:

Сепаратор пространств имен. Отделяет префикс пространства имен от имени элемента или атрибута.

( )

Группирует операции для явного задания очередности.

[ ]

1. Накладывает фильтр.

2. Используется для индексации коллекции.

+

Сложение.

-

Вычитание.

div

Деление с плавающей точкой (согласно IEEE 754).

*

Умножение.

mod

Возвращает остаток при делении с остатком.

Коллекции XPath

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

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

Так, следующие примеры равнозначны:

./first-name
first-name

Индексация коллекций

Выражения XPath позволяют легко найти определенный узел документа. Нужно просто включить в выражение порядковый номер в квадратных скобках. Этот номер отсчитывается от нуля (номер первого элемента - ноль).

Квадратные скобки [] старше символов / и //. Выражение "//comment()[3]" интерпретируется как "//(comment()[3])", и выбирает все элементы comment с индексом 3 относительно его родителя по всему документу. Это отличается от выражения "(//comment())[3]", выбирающего третий comment из набора всех элементов comment относительно родителя. Первое выражение может вернуть несколько элементов comment, а второе вернет только один.

Например, следующее выражение находит первый элемент author.

author[0]

А это выражение найдет третий элемент author из имеющих дочерний элемент:

author[first-name][2]

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

<x>
  <y/>
  <y/>
</x>
<x>
  <y/>
  <y/>
</x>

Найдем первое y для каждого x.

x/y[0]

Найдем первое y из всего набора элементов y внутри элементов x.

(x/y)[0]

Найдем первое y от первого x.

x[0]/y[0]

Поиск последнего элемента коллекции

Функция last возвращает True для последнего элемента коллекции.

Например, следующее выражение найдет последнюю книгу:

book[last()]

Фильтрация

К любой коллекции можно применить ветвления и условия поиска с помощью наложения фильтра, [pattern]. Фильтр аналогичен SQL-выражению WHERE. Фильтр применяется последовательно ко всем элементам коллекции и выдает True/False в зависимости от того, удовлетворяет ли сравниваемый элемент фильтру. Любой элемент, не соответствующий фильтру, не включается в результирующую коллекцию.

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

Фильтры всегда применяются относительно контекста. Другими словами, выражение "book[author]" означает, что для каждого найденного элемента book будет выполнена проверка наличия дочернего элемента author. Сходным образом, "book[author = 'Bob']" означает, что для каждого найденного элемента book будет выполнена проверка наличия дочернего элемента author со значением "Bob". Можно также проверять значение контекста с помощью точки (.). Например, "book[. = 'Trenton']" означает, что для каждого элемента book, найденного в текущем контексте, проверяется, что его значение равно "Trenton".

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

Найти все книги, содержащие хотя бы один элемент [excerpt]:

book[excerpt]

Найти все названия книг, содержащие хотя бы один элемент [excerpt]:

book[excerpt]/title

Найти всех авторов книг, причем книги должны содержать хотя бы один элемент [excerpt], а у автора должна быть хотя бы одна степень:

book[excerpt]/author[degree]

Найти все книги с авторами, имеющими хотя бы одну степень:

book[author/degree]

Операторы

Фильтры могут содержать булевы выражения, выражения сравнения и выражения присвоения. В следующей таблице приведены символы, используемые в реализации XSLT фирмы Микрософт.

Оператор

Описание

and

Логическое "и"

or

Логическое "или"

not()

Отрицание

=

Равенство

!= *

Неравенство

< *

Меньше

<= *

Меньше или равно

> *

Больше

>= *

Больше или равно

|

Объединение, возвращает объединение двух наборов узлов

Метод расширенного XPath

Синтаксис W3C для операторов использует пробелы и другие разделители, а реализация Микрософт (версия 2.5)- знак доллара ($). В синтаксисе W3C, бинарные ключевые слова формы $xxx$ могут быть выражены как wsxxxws, где ws - ограничитель, которым может быть пробел, одинарные или двойные кавычки. Унарные операторы, например, not(), используют функциональную запись. Хотя реализация Микрософт и поддерживает оба синтаксиса, из соображений совместимости лучше использовать синтаксис W3C.

Порядок приоритетности (от высшего к низшему) для операторов сравнения и булевых операторов приведен в следующей таблице.

1

( )

Группировка

2

[ ]

Фильтрация

3

/ и //

Операции с путем

4

< <= > >=

Сравнения

5

= !=

Сравнения

6

|

Объединение

7

not()

Булево "нет"

8

and

Булево "и"

9

or

Булево "или"

Булевы выражения могут соответствовать всем узлам с конкретным значением или всем узлам со значениями в определенном промежутке.

Все операторы чувствительны к регистру ввода.

Булевы операторы and и or выполняют операции "логическое и" и "логическое или", соответственно. Эти операторы в сочетании с группирующими скобками можно использовать для создания замысловатых логических выражений.

Например, следующее выражение находит все элементы author, содержащие хотя бы по одному элементу degree и award.

author[degree and award]

А это - все элементы author, содержащие хотя бы один из элементов degree или award, и, по крайней мере, один элемент publication.

author[(degree or award) and publication]

Булев оператор not служит для отрицания значения фильтрующего выражения. Например, следующее выражение находит все элементы author, содержащие по крайней мере один элемент degree и не содержащие элементов publication.

author[degree and not(publication)]

Сравнения

Для операций сравнения применяются два операнда: вектор или скаляр (значение с левой стороны, или lvalue), который сравнивается со скалярным значением (значение с правой стороны, или rvalue). rvalue должно быть скалярным или приводимым к скалярному в процессе обработки выражения.

Если lvalue сравнения - это множество, для операторов сравнения применяется семантика "any". Таким образом, результат сравнения равен True, если хотя бы один из членов множества отвечает условию.

lvalue выражения не может быть литералом. Например, "3" = a недопустимо. Если rvalue - это атрибут, text(lvalue) сравнивается с text(rvalue).

Все элементы и атрибуты - это строки, но они автоматически приводятся к целочисленному виду для числовых сравнений. Числовые литералы при операциях сравнения приводятся к типам long или double, как показано в следующей таблице.

Тип литерала

Сравнение

Пример

String

text(lvalue) оператор text(rvalue)

a < GGG

Integer

(long) lvalue оператор (long) rvalue

a < 3

Real

(double) lvalue оператор (double) rvalue

a < 3.1

Для разделения строк в выражениях можно использовать одиночные или двойные кавычки. Это упрощает создание фильтров в скриптовых языках.

Например, следующее выражение находит все элементы author с именем Bob.

author[last-name = "Bob"]

Находит все элементы degree, у которых атрибут from не равен "Harvard".

degree[@from != "Harvard"]

Находит все элементы author, у которых значение "last name" такое же, как у элемента /guest/last-name.

author[last-name = /guest/last-name]

Находит все элементы author, содержащие текст "Matthew Bob".

author[. = "Matthew Bob"]

Логика преобразования данных при сравнениях

При сравнении операндов разных типов данных производятся следующие преобразования.

Бинарные операторы сравнения

Оператор"|"

Оператор "|", он же оператор объединения, возвращает объединенные результаты двух запросов. Можно использовать несколько операторов объединения для объединения результатов нескольких запросов. Оператор объединения сохраняет порядок документа и не возвращает дубликатов.

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

Как DOM определяет контекст для XPath-выражения

Парсер MSXML содержит методы, которые позволяют использовать строки XPath. Метод selectNodes, например, возвращает список узлов, как показано в следующем примере:

items = xmldoc.selectNodes("invoices/invoice/items/item");

Поиск по дереву всех узлов "item" мог бы потребовать приличного количества кода. Метод selectNodes в сочетании с выражением XPath позволяет выбрать эти узлы с помощью единственной строки кода.

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

function invoiceTotal(invoice)
{
  invoice = invoice.nextNode()
  items = invoice.selectNodes("items/item");
  var sum = 0;
  for (var item = items.nextNode(); item; item = items.nextNode())
  {
    var price = item.selectSingleNode("price").nodeTypedValue;
    var qty = item.selectSingleNode("qty").nodeTypedValue;
    if (qty >= 10)
      price = 0.9*price;
    sum += price * qty;
  }
  return sum;
}

Этот пример содержит два контекста запроса. Первый запрос выполняется в контексте элемента "invoice", и строка поиска отражает это, начинаясь с элемента "items". Цикл for проходит по найденным узлам и использует каждый из них как контекст дальнейшего поиска. Следующие запросы работают в элементах "item", и ищут в них дочерние элементы "price" и "qty". Это показывает, что узел, относительно которого выполняется selectNodes, определяет контекст поиска.

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

items = xmldoc.selectNodes("invoices/invoice");
items = xmldoc.selectNodes("*/invoice");
items = xmldoc.documentElement.selectNodes("invoice");

Метод selectSingleNode возвращает первый соответствующий запросу узел, что позволяет легко получить конкретный узел, не извлекая его из NodeList. Это эквивалентно "selectNodes(pattern).item(0)". Использование этого метода позволяет упростить код предыдущего примера.

{
  invoice = invoice.nextNode()
  items = invoice.selectNodes("items/item");
  var sum = 0;
  for (var item = items.nextNode(); item; item = items.nextNode())
  {
    var price = item.selectSingleNode("price").nodeTypedValue;
    var qty = item.selectSingleNode("qty").nodeTypedValue;
    sum += price * qty;
  }
  return sum;
}

В этом примере selectNodes по прежнему используется для выборки набора элементов "item". Если ожидается одиночный узел, например, элементы "price" и "qty", можно использовать selectSingleNode.

Введение в схемы XDR

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

Рассмотрим пример XML-документа, содержащего три элемента, <PGROUP>, <PERSONA>, и <GRPDESCR>.

<?xml version="1.0" ?>
<PGROUP>
  <PERSONA>MACBETH</PERSONA>
  <PERSONA>BANQUO</PERSONA>
  <GRPDESCR>generals of the king's army.</GRPDESCR>
</PGROUP>

Во всех документах этого класса корневым, верхним элементом будет <PGROUP>. Этот элемент не содержит текста, но содержит один или более дочерних элементов <PERSONA> и один элемент <GRPDESCR>. Элементы <PERSONA> и <GRPDESCR> содержат только текст и не содержат дочерних элементов.

Определение структуры XML-документа

В большинстве случаев не помешает определить структуру XML-документа и правила его построения. Это позволяет проверить соответствие экземпляра документа определению.

HTML, например, использует определение типа документа (document type definition, DTD), определяющее, что называть верным Web-документом. Одно из правил DTD для HTML - содержимое Web-страницы должно находиться в элементе <HTML>, а выводимый контент - в элементе <BODY>, содержащемся в родительском элементе <HTML>.

Сходным образом можно создать правила для XML-документа, и проверить их соблюдение.

XML Document Type Definition (DTD)

DTD - один из способов оговорить структуру XML-документа. DTD для предыдущего примера выглядит так:

<!DOCTYPE PGROUP [ 
<!ELEMENT PGROUP          (PERSONA+, GRPDESCR) >
<!ELEMENT PERSONA         (#PCDATA)  >
<!ELEMENT GRPDESCR        (#PCDATA)  >
]>

Первая строка, <DOCTYPE PGROUP [, указывает, что тип документа - PGROUP, что заодно является и именем корневого элемента. <!ELEMENT> используется для объявления элементов документа. Элемент <PGROUP> должен включать элементы <PERSONA> и <GRPDESCR>. Знак + означает, что элемент <PGROUP> может включать более одного элемента <PERSONA>.

Формальное описание синтаксиса DTD можно найти в спецификации XML 1.0 на Web-сайте W3C.

DTD имеет следующие недостатки:

Как альтернативу DTD можно использовать описание структуры XML-документов с помощью схем XML-Data.

Схемы XML-Data (XD) и XML-Data Reduced (XDR)

Как и DTD, XD можно применять для определения схемы, структуры или класса документа. XD и XDR лишены недостатков DTD.

Например, вот схема XML-Data для приведенного выше примера:

<?xml version="1.0"?>
<Schema name="schema_sample_1" 
    xmlns="urn:schemas-microsoft-com:xml-data" 
    xmlns:dt="urn:schemas-microsoft-com:datatypes">
  <ElementType name="PERSONA" content="textOnly" model="closed"/>
  <ElementType name="GRPDESCR" content="textOnly" model="closed"/>
  <ElementType name="PGROUP" content="eltOnly" model="closed">
      <element type="PERSONA" minOccurs="1" maxOccurs="*"/>
      <element type="GRPDESCR" minOccurs="1" maxOccurs="1"/>
  </ElementType>
</Schema>

Схемы XML-Data Reduced (XDR)

XDR - это подмножество идей, изложенных в спецификации XML-Data. Реализация схем в парсере MSXML основана на спецификации языка XML-Data Reduced.

Реализация XML-схемы в MSXML основана в первую очередь на XML-Data Note, выпущенном W3C в январе 1998 года, и Document Content Description (DCD) for XML. XML-схемы в Microsoft Internet Explorer 5.0 и более поздних версиях поддерживают подмножество XML-Data, соответствующее DCD. Как вы знаете, Микрософт выпускает такие же продукты, как у других, но другие. Поэтому XML в их реализации имеет слегка измененную грамматику.

Модель содержания, она же модель контента

Модель контента описывает структуру содержания элементов и атрибутов в XML-документе. Для этого используются различные атрибуты, например, model, minOccurs, maxOccurs, order, content, и так далее.

Сначала разберемся со структурой содержания элемента.

Задание модели контента элемента

Рассмотрим, например, XDR-схему (BookSchema.xml), описывающую модель контента различных элементов.

<s:Schema xmlns:s="urn:schemas-microsoft-com:xml-data">
<s:ElementType name="title" content="textOnly"/>
<s:ElementType name="authors" content="textOnly"/>
<s:AttributeType name="pages" content="textOnly"/>
<s:ElementType name="book" order="seq" content="eltOnly">
      <s:attribute type="pages" />
      <s:element type="title" />
      <s:element type="authors" />
</s:ElementType>
</s:Schema>

Модель элементов <title>, <author> и <pages> очень проста. Поскольку атрибут content определяет их как "textOnly", эти элементы не могут содержать ничего, кроме текста (то есть, не могут содержать дочерних элементов).

Модель элемента <book> сложнее. Атрибут content элемента <book> имеет значение "eltOnly". Это указывает, что элемент <book> может содержать только элементы, содержащиеся в схеме (<title>, <author> и <pages>). Более того, в каждом экземпляре элемента <book> дочерние элементы должны следовать в порядке, указанном в схеме.

Вот пример XML-документа, отвечающего этой схеме.

<x:book xmlns:x="x-schema:BookSchema.xml">
  <x:pages>474</x:pages>
  <x:title>Applied XML: A Toolkit for Programmers</x:title>
  <x:authors>Alex Ceponkus and Faraz Hoodbhoy</x:authors>
<x:/book>

Теперь рассмотрим различные атрибуты, используемые в модели контента.

Пример совместного использования ASP и XML-технологий**

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

Литература

  1. Андрей Колесов. Использование XML DOM в VB и MS Office/VBA. -
  2. Александр Печерский. Язык XML - практическое введение. - www.codenet.ru
  3. MSDN, April 2001 release
  4. Working with XML in the .Net Platform - Dan Wahlin, XML Magazine.
ООП   XML   СУБД   ЯиМП   3GL   4GL   5GL   технологии прогр.

Знаете ли Вы, что "тёмная материя" - такая же фикция, как черная кошка в темной комнате. Это не физическая реальность, но фокус, подмена.
Реально идет речь о том, что релятивистские формулы не соответствуют астрономическим наблюдениям, давая на порядок и более меньшую массу и меньшую энергию. Отсюда сделан фокуснический вывод, что есть "темная материя" и "темная энергия", но не вывод, что релятивистские формулы не соответствуют реалиям. Подробнее читайте в FAQ по эфирной физике.

Bourabai Research Institution home page

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