16 декабря 2019 года    
Понедельник | 06:37    
Главная
 Новости
Базы данных
Безопасность PC
Всё о компьютерах
Графика и дизайн
Интернет-технологии
Мобильные устройства
Операционные системы
Программирование
Программы
Связь
Сети
 Документация
Статьи
Самоучители
 Общение
Форум







Разделы / Интернет-технологии / XML

FAQ: интерфейс пользователя на XUL и построение преобразования по WXS

В: Как мне создать новую оболочку для браузера Mozilla?

Я создаю новый браузер на основе Mozilla для университетского проекта с целью облегчить пожилым людям путешествие по Сети. Вы не могли бы помочь мне в создании оболочек для Mozilla?

О: Может показаться, что этот вопрос несколько выходит за рамки применения XML. Однако, это не так.

Дело в том, что интерфейс пользователя Mozilla (а также браузеров, созданных на базе Mozilla - таких как последние версии Netscape) определяется тем, что можно назвать "файлы управления". Форматом этих файлов является XML, а в качестве словаря выступает язык описания интерфейса пользователя (XML-based User interface Language, XUL). Код XUL содержится в файлах с расширением .xul и соотносится с URI с помощью специальной схемы chrome://. (Почему "chrome"? Представьте металлический, сверкающий отделкой автомобиль 50-х годов. Это блестящий фасад, за которым начинается настоящая работа. Этот "хром" в случае Mozilla и составляет оболочку). Специальная форма XUL URI будет выглядеть так:

chrome://component/content/filename

где component - одна из стандартных функций браузера, а filename, очевидно, имя файла с расширением .xul. Например,

chrome://communicator/content/newbrowser.xul

Эта запись означает, что настройки оболочки для самого окна браузера (это часть коммуникатора (communicator)) находятся в файле newbrowser.xul.

Обычный документ XUL состоит из стандартной XML-декларации, ссылки на таблицу стилей CSS и корневого элемента window. Внутри последнего могут содержаться другие элементы XUL, представляющие различные элементы управления пользовательским интерфейсом (кнопки, ползунки, текстовые области и т.д.), а также привычные элементы XHTML.

Для примера рассмотрим следующий очень простой документ XUL:

<?xml version="1.0"?>
   <?xml-stylesheet href="chrome://global/skin/"
type="text/css"?>
   <window
      id="xul-demo"
      title="An Inert XUL Demonstration"
      xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
      xmlns:html="http://www.w3.org/1999/xhtml">
      <vbox id="mainbox">
         <menulist id="bookinfo-menu">
            <menupopup>
               <menuitem label="Title"/>
               <menuitem label="Author"/>
               <menuitem label="ISBN"/>
            </menupopup>
         </menulist>
         <box>
            <html:img src="xpathpointer.s.gif" />
         </box>
      </vbox>
   </window>

Несколько замечаний относительно этого примера:

  • Стиль, в котором будут отображаться текст и другие элементы управления, определяется в таблице стилей CSS и указывается с помощью инструкции по обработке xml-stylesheet. Если ни какого конкретного стилевого оформления не объявлено, будет использоваться стиль по умолчанию, "зашитый" внутри Mozilla.
  • Корневой элемент window содержит два объявления пространств имен:
    • Пространство имен по умолчанию (используется для элементов без указанного префикса пространств имен) ассоциируется с самим XUL.
    • Префикс html: используется для элементов из словаря XHTML.
  • Содержание находится в вертикальном поле (элемент vbox) - т.е. элемент menulist и элемент box (каждый из которых, согласно определению пространства имен по умолчанию, находятся в пространстве имен XUL) располагаются один над другим.
  • Элемент menulist и его потомки определяют раскрывающееся меню выбора с тремя вариантами: строки "Title", "Author" и "ISBN".
  • Элемент box содержит единственного потомка - XHTML элемент img, который, естественно, выводит на экран указанное изображение.

И если теперь вы откроете этот файл в Mozilla с помощью стандартной схемы file://, то вы сможете получить представление о том, как влияет документ XUL на то, что видит пользователь (и с чем взаимодействует):

Mozilla"s-eye view of an XUL document
Представление документа XUL в Mozilla

Этот короткий обзор дает лишь начальное представление о том, что вы можете сотворить с помощью XUL, вплоть до полной переделки самого окна браузера. Лучшая онлайновая ссылка для изучения XUL - это пособие XUL в примерах от XULPlanet. Это пособие так полно и ясно написано, что трудно вообразить кого-либо, прочитавшего его целиком и так ничего не понявшего. Если же вы предпочитате обучаться по оффлайновой литературе, то рекомендую обратиться к недавно изданной издательством O"Reilly книге Creating Applications with Mozilla (авторы: David Boswell, Brian King, Ian Oeschger, Pete Collins и Eric Murphy). В этой книге XUL рассматривается лишь в одной из 12 глав, так что вы получите гораздо больше, чем просто умение создавать вашу собственную оболочку.

В: Могу ли я привести произвольный документ к форме, определяемой схемой W3C XML Schema (WXS)?

Формализуем задачу:

  • Есть XML файл.
  • Есть схема WXS.
  • Я не хочу валидировать данные XML, но я хочу преобразовать их в форму, определяемую схемой.

Пусть, WXS для управления преобразованием содержит следующий фрагмент:

<xs:element name="note">
      <xs:complexType>
         <xs:sequence>
            <xs:element name="a" type="xs:string"/>
            <xs:element name="b" type="xs:string"/>
         </xs:sequence>
      </xs:complexType>
   </xs:element>

Здесь определяется note, имеющий двух потомков с именами a и b в заданном порядке.

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

<?xml version="1.0"?>
   <apple>
      <something>Hello</something>
      <from>Joe</from>
   </apple>

Мне хотелось бы иметь некое автоматическое преобразование, которое

  • проверяло бы, подходят ли вообще схема и данные (с точностью до замены имен элементов), и
  • выполняло трансформацию.

Результат для моего примера должен тогда выглядеть так:

<?xml version="1.0"?>
   <note>
      <a>Hello</a>
      <b>Joe</b>
   </note>

Не могли бы вы мне помочь?

А: Ваше определение первого шага в автоматическом преобразовании обманчиво просто: может ли подходить схема и исходное дерево вообще? Что означает "может" в данном контексте или "подходит" для данного случая? Практически невозможно запрограммировать универсальное преобразование любого исходного дерева в какое-то конкретное результирующее (если вы только точно не зададите, какие точно условия определяют, что значит "подходит").

После всего сказанного, позвольте мне написать вариант преобразования, возможно это поможет вам продвинуться. Допустим, что схема, указанная выше, находится в файле note.xsd, и что исходное дерево будет "подходить", если его корневой элемент имеет ровно столько дочерних элементов, что и корневой элемент, определенный WXS; нам не важно, какие имена у дочерних элементов (в исходном дереве, либо в документе, структура которого определена схемой).

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

<?xml version="1.0"?>
   <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:variable name="schema"
select="document("note.xsd")/." />
      <xsl:template match="text()" />
      <!-- ... -->

   </xsl:stylesheet>

(Зачем переопределять шаблонное правило по умолчанию? Потому что иначе текстовые узлы будут скопированы прямо в результирующее дерево, а это не совсем то, что нам нужно).

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

<xsl:variable name="xsd_root" select="$schema/xs:element/@name" />
<xsl:variable name="xsd_root_children"
select="count($schema/xs:element/xs:complexType/xs:sequence/xs:element)" />

Заметьте, что переменная $xsd_root получает свое значение из атрибута name важнейшего элемента схемы xs:element. (Как вы отметили, схема, которую вы предоставили, неполная; не хватает, как минимум, элемента xs:schema, чтобы соответствовать XML Schema 1.0 Recommendation. Любое изменение в структуре вашей схемы должно быть отражено в этом преобразовании).

Пока все хорошо. Но затем $xsd_root_children получает путем подсчета... (задержите дыхание) "правнуков" этого элемента xs:element. Поэтому это сработает только если (скажем) схема имеет точно такую же структуру как в примере, который вы привели: корневой элемент xs:element с единственным дочерним элементом xs:complexType, который в свою очередь имеет единственного потомка xs:sequence. Последний уже может иметь любое количество дочерних элементов xs:element. (В вашем примере схемы есть 2 таких "правнука").

Теперь мы можем приступить к построению исходного дерева. Нам нужно только одно шаблонное правило, соответствующее корневому узлу исходного дерева:

<xsl:template match="/">
      <xsl:choose>
         <xsl:when test="count(*/*) != $xsd_root_children"/>
         <xsl:otherwise>
            <xsl:element name="{$xsd_root}">
               <xsl:for-each select="*/*">
                  <xsl:variable name="i"
select="position()"/>
                  <xsl:variable
                     name="xsd_curr_elem"
                    
select="$schema/xs:element/xs:complexType/xs:sequence/xs:element[$i]/@name"/>

                  <xsl:element
name="{$xsd_curr_elem}"><xsl:value-of
select="."/></xsl:element>
               </xsl:for-each>
            </xsl:element>
         </xsl:otherwise>
      </xsl:choose>
   </xsl:template>

(Также, как и в случае с предыдущими объявлениями переменных, это шаблонное правило подразумевает, что выполнены некоторые условия. Эти условия заключаются в том, что исходное дерево состоит из единственного корневого элемента, с некоторым количеством дочерних. Опять, если ваше исходное дерево имеет другую структуру, вам должны внести соответствующие изменения в этот шаблон.)

Правило шаблона сначала проверяет, соответствует ли число дочерних элементов исходного документы значению глобальной переменной $xsd_root_children. Если нет - это пустая переменная xsl:when - наше преобразование ничего не делает. (В зависимости от используемого XSLT процессора вы можете поместить элемент xsl:message в эту переменную xsl:when, чтобы пользователь получал сообщение о несоответствии между двумя структурами). В вашем случае пустой xsl:when отвечает на вопрос: "Что, если структура исходного дерева не совпадает со структурой документа, определенного схемой?".

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

  • Объявляется переменная $i, которая просто хранит позицию текущего дочернего элемента внутри своего набора вершин.
  • Объявляется еще одна переменная $xsd_curr_elem. Значением этой переменной является строка со значением атрибута name для "$i-го" элемента xs:element, который является правнуком корневого элемента xs:element.
  • Создается в результирующем дереве элемент с именем из значения переменной $xsd_curr_elem. В качестве содержания этого элемента вставляется текстовый узел со значением, взятым из значения текущего узла, обрабатываемого в цикле xsl:for-each.

Хотелось бы обратить внимание на тот факт, что это ненадежный способ обработки. Хотя он является "общим" в том смысле, что не требуется ни какого знания имен элементов в двух документах (исходное дерево и определяемый WXS), он полностью зависим от соответствующих структур двух документов. И все же, возможно, написанное выше даст вам какое-то представление о том, как можно подходить к решению подобных проблемы.

FAQ: интерфейс пользователя на XUL и построение преобразования по WXS
Лента новостей


2006 (c) Copyright Hardline.ru