В этой лекции рассказывается о том, как определить контент XUL
документа, используя поток
Система шаблонов Mozilla - это подмножество XUL тегов. Эти теги используются, чтобы создать документ, содержание которого не определено. Исходный документ служит основой для представления меняющихся со временем данных, либо в результате воздействия пользователя, либо в результате изменения самих исходных данных. Это также основа для создания приложений, чей графический интерфейс зависит от внешней информации. Внешняя информация может быть проста, как файл, или сложна, как база данных, и находиться где угодно в сети. В любом случае, вид такого документа меняется в зависимости от ситуации.
Система шаблонов позволяет создавать многие виды приложений. Когда информация в шаблоне меняется согласно показаниям датчиков, документ ведет себя как телеметрическое приложение, например центр управления сетью или система контроля состояния окружающей среды. Когда информация изменяется конечным пользователем, документ превращается в приложение для работы с данными. В частности, система шаблонов соответствует приложениям для исследования данных, таких как категориальный анализ и анализ бизнес-процессов, системам контент- и документ-менеджмента, визуализации сетевых схем. Ее можно использовать и для обычных систем ввода данных.
При традиционной web-разработке динамически изменяемый документ
HTML может быть сконструирован двумя способами. HTML может
генерироваться на стороне web-сервера (чем-то вроде CGI-программы),
или HTML на стороне клиента может иметь многочисленные скрипты
(динамический HTML). В любом случае, мы должны работать с кодом
третьего поколения (
Система шаблонов Mozilla не требует
Контент File | . Это дерево
описывает текущие открытые окна.
Понимание системы шаблонов означает понимание системы правил
шаблонов. Последовательность правил может быть простой или сложной. В
самом простом случае правила лишь подразумеваются и не выражены явно.
В сложных случаях правила подобны или запросу к базе данных или
оператору switch в языке JavaScript. В обоих случаях приходится
использовать специальные переменные шаблонов.
Как и во многих других случаях XUL, система шаблонов начинается с простого и ясного синтаксиса:
<template> <rule> ... </rule> <rule> ... </rule> </template>
Шаблоны так же сложны, как и деревья, и простой базовый синтаксис скоро усложнится, поскольку есть множество подробностей.
Шаблоны не имеют собственного содержания: нет никаких блокоподобных
тегов шаблонов. Теги шаблонов больше похожи на макро-инструкции и
оператор # препроцессора языка C. Эти теги всегда используются
внутри других XUL тегов; они не могут быть тегами верхнего уровня,
наподобие тега <window>.
На схеме в начале этой лекции показана область, затрагиваемая
системой шаблонов в платформе. Из нее видно, что шаблоны - маленькая,
компактная система, отделенная от остальной платформы Mozilla. Их
работа - последний этап в процессе формирования документа при его
загрузке. Шаблоны никак не затрагивают систему отображения XUL
контента. Поскольку шаблоны работают в паре с
Листинг 14.1 XUL-документ, содержащий простейший шаблон, выводящий "hello, world" один или несколько раз.
<?xml version="1.0"?> <window xmlns="http://www.mozilla.org/keymaster/ gatekeeper/there.is.only.xul"> <vbox datasources="test.rdf" ref="urn:test:seqroot"> <template> <label uri="rdf:*" value="Content: rdf:http://www.example.org/Test#Data"/> </template> </vbox> </window>
Как видно из листинга, система шаблонов состоит из собственных
тегов, подобных тегу <template>, и специальных атрибутов для
других тегов, таких, как атрибут ref.
Mozilla предоставляет несколько типов синтаксиса правил, образующих
систему запросов в шаблонах. В данном примере использовался простейший
синтаксис: только одно правило, причем подразумеваемое. Оно гласит:
обработать все сообщения конкретного контейнера , а контент, представляющий сообщения, определяется
тегом <label>. Обратите внимание, что и внутри, и снаружи тега
шаблона <template> могут быть теги обычного типа, не относящиеся
к системе шаблонов.
В листинге 14.2 приведен
<?xml version="1.0"?>
<RDF xmlns:Test="http://www.example.org/Test#"
xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
<Description about="http://www.example.org/">
<Test:Container>
<Seq about="urn:test:seqroot">
<li resource="urn:test:welcome"/>
<li resource="urn:test:message"/>
</Seq>
</Test:Container>
<Description about="urn:test:welcome" Test:Data="hello, world"/>
<Description about="urn:test:message" Test:Data="This is a test"/>
</RDF>
Данный файл <Seq>,
имя ресурса которого использовалось в коде XUL-шаблона в листинге
14.1. Это унифицированное имя ресурса (Test - пространство имен xmlns. Data и Container -
специальные свойства (предикаты) имен в этом пространстве имен. Имена
Data также присутствует в теге <label> листинга 14.1, где оно указано со своим полным URL.
Если сохранить эти два листинга в файлы и загрузить первый, то мы увидим картинку, приведенную на рисунке 14.1. Диагностические стили включены, чтобы выявить структуру окна, полученного в результате.
На рисунке видно, что в финальном XUL были сгенерированы два тега <label>. Значения каждого тега определяются и фиксированным
значением ("Content: "), и строкой, определяемой одним из
двух фактов <Description> в документе , напротив,
появляется лишь один раз. Структуру финального документа можно
исследовать с помощью приложения DOM Inspector. На рисунке 14.2
приведен вид DOM Inspector, соответствующий рисунку 14.1.

(рис 14.2) XUL-документ, созданный по шаблону и двум фактам.(рис 14.1) Тот же документ в DOM Inspector.На снимке видно, что система шаблонов добавила два тега в финальный
документ, по одному на каждый факт в файле <label> - метка из исходного файла шаблона, другие два тега <label> - контент, сгенерированный шаблоном. Таким образом,
финальный документ содержит два поддерева - одно для спецификации
шаблона, а другое для сгенерированного контента. Поддерево,
начинающееся тегом <template>, никак не отражается на внешнем
виде документа. Когда система шаблонов генерирует теги для другого
поддерева, она присваивает им
XUL этого шаблона можно сделать гораздо сложнее, используя свойства системы правил шаблонов.
Перед тем, как углубиться в синтаксис XUL системы шаблонов, нам
следует отступить далеко назад, чтобы увидеть, что все это означает с
точки зрения фактов. В конце концов, шаблону для работы нужен
Система шаблонов Mozilla затрагивает все стандартные отличительные
черты приложений Mozilla: XUL, JavaScript и
Система шаблонов XUL - это система запросов. Она осуществляет поиск
в массиве данных и возвращает элементы массива, соответствующие
Запросы, выполняемые XUL-шаблоном, часто описываются как система
сравнивания с образцом. В самом общем смысле слова
"образец", принятого в
Шаблоны XUL не являются фильтрами и не выполняют сравнение с
образцом в этом каждодневном смысле слова. Если документ
В отличие от простой фильтрации, запросы в шаблонах выполняют унификацию. Унификация имеет место тогда, когда множество элементов данных комбинируется в конечный результат. Пример из реальной жизни - собирание паззла. Когда все кусочки паззла собраны вместе, решение найдено (получена картинка). Если дано больше элементов, чем нам понадобилось (предположим, было перемешано несколько наборов паззлов), часть элементов будут отброшены, как незначащие. Унификация может дать больше, чем один результат. Если элементов головоломки достаточно, можно собрать несколько картинок. Если элементы имеют подходящую форму, то несколько результатов может быть получено даже из одного набора.
В Mozilla элементы головоломки это подлежащие, сказуемые и
дополнения набора
Это кажется знакомым. Инструкция SELECT в SQL ведет себя точно так
же, когда выполняет запрос join - то есть выбирает данные из двух или
более таблиц. Данные в полученных колонках не соответствуют данным ни
в одной из исходных строк, они соответствуют информации в строках
разных таблиц. Этим способом может быть обнаружено более одной
строки.
Фактически, запросы XUL-шаблонов являются примерами реляционных
вычислений, так же как
Синтаксис шаблонов XUL необычен и лучше начинать не с него. Чтобы
разобраться в структуре запросов шаблонов, давайте вернемся к примеру
с мальчиком, собакой и мячиком из лекции 11, "
Вспомним, что этот пример использовался для описания
"чистой" системы сообщений, без
<- 1, is-named, Tom -> <- 1, owner, 2 -> <- 1, plays-with, 5 -> <- 2, is-named, Spot -> <- 2, owned-by, 1 -> <- 2, plays-with, 5 -> <- 5, type-of, tennis -> <- 5, color-of, green ->
Эта информация моделирует сообщение "Том и его собака
В лекции 11, "
<- 1, owner, ??? ->
Поскольку дополнение (объект) в этом триплете неизвестно, это не основной факт. Его нельзя использовать как данные, но можно - как стартовую точку для запроса о других фактах. Используем переменную для неизвестной части. Переменная начинается с символа вопросительного знака, точно как переменные в DOS начинаются и заканчиваются знаком '%', а переменные в оболочке UNIX начинаются со знака '$'. Переменная не может быть в основном состоянии, иначе она не переменная, а литерал. Будем называть процесс перевода переменной с неизвестным значением в переменную с известным - обоснованием переменной.
<- 1, owner, ?dogId ->
При выполнении запроса унификация означает, что все переменные из множества доступных фактов будут преобразованы в литералы. Причудливым образом можно сказать так: "Обоснуй-ка мне все переменные, пожалуйста". Для нашего простого примера данному перегруженному переменными запросу отвечает второй факт из листинга 14.3.
<- 1, owner, 2 ->
Переменная ?dogId не имеет значения, и если значение 2 заменит ее,
будет получен факт, соответствующий существующему факту. Таким
образом, переменная ?dogId может быть обоснована значением 2. Это
тривиальный пример запроса, возвращающего один результирующий факт.
Предположим, у Тома есть вторая собака, по кличке Фидо. Значит, есть
дополнительный факт:
<- 1, owner, 3 -> <- 3, is-named, Fido ->
Если факт, содержащий переменную ?dogId, снова использовать как
запрос, ему будут соответствовать уже два факта:
<- 1, owner, 2 -> <- 1, owner, 3 ->
?dogId может быть обоснована либо значением 2, либо 3, так что
теперь есть два решения. Мы можем говорить, что результирующее
множество содержит два факта, две строки, или два элемента.
Предшествующий факт, используемый как запрос, также может быть расширен. Его можно указать так:
<- ?personId, owner, ?dogId ->
В этом случае соответствие требует комбинации значений,
удовлетворяющих обеим переменным одновременно (обосновывается и ?personId, и ?dogId ). Если мы используем существующие факты,
результирующее множество также будет иметь две строки: ( ?personId
обосновывается 1 и ?dogId обосновывается 2) даст один факт, а
( ?personId обосновывается 1 и ?dogId обосновывается 3) даст
второй. Увеличение количества переменных не всегда означает увеличение
количества результирующих фактов. Это лишь означает, что нужно найти
соответствие большему количеству предметов.
Предположим, что Джейн (чей person id = 4) также владеет Фидо, но не Спотом. Фидо, таким образом, принадлежит двум хозяевам, но Спотом владеет только Том. В списке фактов добавятся два новых:
<- 4, is-named, Jane -> <- 4, owner, 3 ->
Если последний запрос выполнить вновь, мы получим три результата:
?personId обосновывается 1 (Tom) and ?dogId обосновывается 2 (Spot) ?personId обосновывается 1 (Tom) and ?dogId обосновывается 3 (Fido) ?personId обосновывается 4 (Jane) and ?dogId обосновывается 3 (Fido)
Хотя ?personI может иметь значение 4 (Джейн), а ?dogId - 2 (
Наконец, заметим, что информация, которую нужно обосновать в
последнем простом запросе, имеет иную нотацию. Она может быть записана
как набор неизвестных, которые нужно найти. Этот набор можно записать
как
<- ?personId, ?dogId ->
Этот INTO в SQL запросе SELECT. Если кто-то другой писал запрос,
такая информация - все, что вам нужно, чтобы понять полученный
результат.
В последнем примере три строки соответствуют этому
<- 1, 2 -> <- 1, 3 -> <- 4, 3 ->
Если процессору запросов не дать достаточно информации, он не будет знать, что ему делать. Недостаточно сказать, "компьютер, умница, найди-ка мне эти переменные". Запрос должен указать процессору, на что смотреть. В случае простого запроса предписание может быть очень простое: "комп, тупица, просмотри-ка все триплеты данных и найди все, соответствующие этому триплету-запросу".
Система шаблонов Mozilla поддерживает простые (single-
Слегка заглядывая вперед, скажем, что в запросе о единичном факте
тег < должен быть записан одним из двух способов.
Если искомый факт содержится в , и так далее, то в теге < должны содержаться <content> и <. Если же искомый факт содержит хорошо
известные предикаты, < должен содержать теги <content> и <triple>. Простые запросы шаблонов обсуждаются
далее в разделе "Распространенные образцы запросов".
Система XUL шаблонов поддерживает комплексные (multifact) запросы.
Комплексные запросы напоминают SQL запрос join и также напоминают
навигацию по древообразной структуре данных.
Комплексные запросы - это вопросы, требующие для ответа, чтобы два
или более реальных факта были скомбинированы. Другими словами,
требуется некая
Используя пример о мальчике и собаке, предположим, что нужно задать запрос: "Как зовут собаку, которой владеет Том"?
<- ?personId, is-named, Tom -> <- ?personId, owner, ?dogId -> <- ?dogId, is-named, ?dogName ->
Формулирование комплексных запросов требует некоторой практики. Это
тот же вид практики, который требуется, чтобы освоить SQL запросы join
для нескольких таблиц или регулярные выражения с несколькими
переменными. Ключевая проблема состоит в том, что запрос приходится
писать сразу, усилием воли, с чистого листа.
Данный запрос был построен следующим образом. Сначала было
установлено уже нам известное ("Том"). Затем мы определили
то, что нам не известно, но мы хотим узнать: dogName. Мы просмотрели
доступные нам кортежи, чтобы узнать, каким из них могут
соответствовать известные и неизвестные нам элементы. Это дало нам два
is-named
используется в обоих personId и dogId. Мы добавили их в список неизвестных. Мы заметили,
что эти два personId и dogId. Итак, мы получаем список
кортежей, где все неизвестные присутствуют, и все они соединены, так
что этот список образует единый запрос.
Если эти три факта, как единый запрос, направить в процессор
запросов, то, чтобы решение нашлось, все неизвестные должны быть
обоснованы одновременно. Поскольку каждая из переменных ?personId и ?dogId присутствует в двух
<- 1, is-named, Tom -> <- 1, owner, 2 -> <- 2, is-named, Spot ->
Сравните эти три факта с запросом. Решение ставит в соответствие неизвестным переменным
<- ?personId, ?dogId, ?dogName ->
единственную возможность:
<- 1, 2, Spot ->
Как процессор запросов в Mozilla ищет решение? Существует много возможных техник. Простейшая - перебирать все комбинации из трех реальных фактов и сравнивать каждую комбинацию с запросом. Это решение проблемы "грубой силой", оно очень неэффективно. Так в Mozilla не делается. Mozilla использует более тонкий метод, заключающийся в исследовании части графа структуры фактов. Скоро мы сможем в этом убедиться.
Если снова поместить в список исходных фактов Фидо и Джейн, тот же самый запрос даст два решения:
<- 1, is-named, Tom -> <- 1, owner, 2 -> <- 2, is-named, Spot -> <- 1, is-named, Tom -> <- 1, owner, 3 -> <- 3, is-named, Fido ->
Здесь значения, обосновывающие неизвестные переменные, следующие:
<- 1, 2, Spot -> <- 1, 3, Fido ->
Обратите внимание, как конструируется запрос для сравнения с
фактами списка. Подлежащие и дополнения соответствуют переменным,
таким как ?personId. Результат, напротив, просто набор обоснованных
переменных в
Этот пример эквивалентен SQL запросу join из трех таблиц. Листинг
14.4 показывает воображаемый SELECT запрос, выполняющий ту же работу,
что и наш последний запрос. Каждая из трех воображаемых таблиц
соответствуют одному факту из нашего списка.
SELECT p.personId, d.dogId, d.dogName FROM persons p, owners o, dogs d WHERE p.personName = "Tom" AND p.personId = o.personId AND o.dogId = d.dogId
Точно как join в personId в двух типах запросов, и вы увидите
подобие, несмотря на абсолютно разный синтаксис.
В общем случае этот пример демонстрирует, как большой массив фактов
может быть исследован с помощью правильно сконструированных запросов,
содержащих переменные. Если массив фактов - это
Система шаблонов поддерживает комплексные шаблоны двумя способами.
Простой синтаксис шаблона автоматически выполняет запрос по двум
фактам, при условии, что <content>, любое количество
тегов < и <triple>, и любое количество тегов <. Каждый из этих тегов (за исключением тега <content> ) представляет в запросе один факт.
В лекции 11, "<Seq>. Mozilla использует комбинацию
С точки зрения прикладного программиста, Mozilla использует
"бурящий" (
Когда начальная точка выбрана, процессор запроса Mozilla двигается
из нее по графу
Систему запросов можно проиллюстрировать
На рисунке 14.3 все факты принадлежат списку фактов. Иллюстрируемый
запрос состоит из двух фактов (two-
(рис 14.3) Уточненный граф "мальчик и собака" и путь запроса.Мы можем поэкспериментировать немного с этим примером.
(рис 14.4) На Рисунке 14.4 показан другой запрос на том же графе.
Снова мы имеем запрос из двух фактов, но на этот раз он начинается с идентификатора Спота (2). Снова три решения. Заметим, что путь 2-1- Том не является решением. Потому что стрелка указывает в противоположную сторону. Вовсе не 2 - подлежащее факта, и 1 - дополнение, а наоборот. Запрос не может двигаться в обратном порядке. Но даже для возможных решений наш второй запрос все же вряд ли имеет смысл. Слишком разные обнаруживаются предикаты на этих путях. Если все же нужно найти в этом запросе смысл, лучше предположить, что либо реальные данные плохо описываются фактами, либо запрос был недостаточно хорошо продуман.
Минус этой системы в том, что не все факты из исходного списка
просматриваются. Теоретически, система может пропустить некоторые
решения. Но ее достоинство - скорость. На практике, если
Этот "сверлящий" алгоритм - приближение. В реальности система шаблонов работает сложнее. Однако это достаточно хорошее приближение и рекомендуемая интерпретация способа работы системы шаблонов XUL.
Способ организации <Seq>, < или <Alt>.
Известная стартовая точка - либо
Листинги 14.5 и 14.6
показывают фрагмент
<Description about="http://www.example.org/"> <NS:Owns> <Bag about="urn:test:seq"> <li resource="urn:test:seq:fido"/> <li resource="urn:test:seq:spot"/> <li resource="urn:test:seq:cerebus"/> </Bag> </NS:Owns> </Description> <Description about="urn:test:seq:fido" NS:Tails="0"/> <Description about="urn:test:seq:spot" NS:Heads="1"/> <Description about="urn:test:seq:cerberus" NS:Heads="3"/>
NS в листинге 14.5 означает некоторое пространство имен,
предположительно, объявленное в коде где-то ранее. Пространство имен
должно иметь NS для идентификации экземпляров фактов,
эквивалентных применяемым в листинге 14.5. Использование NS в
листинге 14.6 не имеет никакого конкретного смысла, поскольку факты в этом
листинге не являются ни XML, ни кодом вообще.
<- http://www.example.org/, NS:Owns, ?bag -> <- ?bag, ?index, ?item -> <- ?item, NS:Heads, ?heads ->
В запросе первый обосновываемый факт спускается ( ( - неупорядоченное < ).
Второй обосновываемый факт спускается далее до элементов множества
(множество из трех элементов <li resource= ...). Третий факт спускается до фактов о количестве голов у
каждого элемента (в результате ноль или один ответ на каждую строку
запроса, в зависимости от наличия головы у элемента множества (Фидо -
ноль хвостов,
<- ?bag, ?index, ?item, ?heads ->
а два найденных решения так:
<- urn:test:seq, rdf:_2, urn:test:seq:spot, 1 -> <- urn:test:seq, rdf:_3, urn:test:seq:cerberus, 3 ->
Вспомним, что ,каждому потомку в контейнере. Первый NS: вместо NS:Heads.
Поддержка такого типа запросов - первоочередной приоритет системы запросов Mozilla. Это самый надежный и плодотворный способ работы с системой шаблонов.
В предыдущем примере переменная ?index использовалась для описания
предиката факта. Система запросов Mozilla не может использовать
переменную в запросе для предиката, но она имеет тег <,
который достигает почти той же цели (с некоторыми ограничениями).
Итак, набор фактов запроса обнаруживает подходящие записи в
аккуратно упорядоченной коллекции и строит
Запросы XUL шаблона живут столько же, сколько и содержащий их документ. Они не запускаются однажды, а затем отбрасываются. Они используются, пока не закроется их отображающее окно.
Список
Когда данные изменяются, каждый запрос шаблона также меняет свое мнение о том, какие существуют решения этого запроса. Если новые решения возможны, они будут добавлены ко множеству решений. Если некоторые решения стали невозможны, они будут удалены. Возможны и изменения в ранее найденных решениях.
Ближайшее следствие этого - то, что множество решений может со
временем изменяться. Шаблонный запрос - не всегда "событие
согласованного чтения" (если использовать жаргон
Живой отклик запроса требует от прикладного программиста некоторой активности. Ведь запрос должен непрестанно сверяться со списком фактов, чтобы решения были актуальны. Чтобы это делалось эффективно, и только тогда, когда нужно, должны быть написаны определенные скрипты.
XUL документы используют шаблонные запросы повсеместно.
Бурящую стратегию шаблонных запросов Mozilla можно применять
рекурсивно. Каждую конечную точку бурения можно использовать как
следующую начальную точку для того же самого запроса. Это позволяет
запросу продвигаться глубже по
Рекурсивное использование запросов очень плодотворно на
древообразных структурах данных. Такие структуры могут иметь
произвольную глубину, что соответствует произвольному числу связей в
В XUL документе шаблонные запросы внутри тега <tree> выполняют и добавочную работу.
Система запросов Mozilla позволяет объединить несколько запросов в список.
Когда начинается обработка запросов, все запросы списка обрабатываются одновременно. Любое решение, удовлетворяющее сразу нескольким запросам, будет поставлено в соответствие лишь одному. А именно - ближайшему к началу списка.
Метод, которым это достигается, прост: на каждом шагу вниз по
Такая система позволяет оценить ряд фактов одним набором критериев
(одним запросом), а если решение найти не удалось, вновь оценить
другим набором критериев (другим запросом). Это очень похоже на
булевские условные выражения if ... else if.
Списки запросов в Mozilla позволяют порождать несколько различных подмножеств одного множества фактов. Каждый запрос порождает одно такое множество решений.
На этом мы закончим рассмотрение запросов шаблона. После выполнения запроса нужно обработать найденные решения.
В обычном случае все, что XUL шаблон делает с полученными данными - это выводит их на экран.
Шаблон делает это, совмещая полученные данные с обычным XUL- контентом. Он действует так же, как программа для печати информации в наглядной форме, или заготовка для написания отчета, "рыба". Выводимые данные интегрируются в XUL-документ и выводятся на экран, как любой иной XUL-контент.
Если шаблон содержится в теге XUL, таком как <menupopup>, <listbox>, <, <tree> или даже <box>,
то контент тега XUL (элементы меню, кнопки панели инструментов, строки
списка или дерева) могут порождаться шаблоном. Это означает, что сами
интерактивные интерфейсы могут описываться
Проиллюстрируем процесс такого порождения простым примером. В
листинге 14.7 -
<?xml version="1.0"?>
<RDF xmlns:Test="http://www.test.com/Test#"
xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<Description about="urn:test:top">
<Test:TopSeq>
<Seq about="urn:test:seqroot">
<li resource="urn:test:message1"/>
<li resource="urn:test:message2"/>
</Seq>
</Test:TopSeq>
</Description>
<Description about="urn:test:message1" Test:Foo="foo"/>
<Description about="urn:test:message2" Test:Bar="bar"/>
</RDF>
Два свойства могут быть извлечены из этого файла и выведены на
экран с помощью шаблона. Рисунок 14.5 показывает два набора
сгенерированного XUL-контента из данного
(рис 14.5) Вывод двух шаблонов, использующих одни RDF данные.На снимке оба шаблона располагаются бок о бок. Мы видим конечный
результат процесса порождения XUL контента. Шаблон слева генерирует
теги <description> с рамками, заданными стилем. Теги находятся в
теге <. Шаблон справа генерирует теги <treeitem>,
каждый из них содержит <treerow> и <treecell>. Все они
находятся в тегах <tree> и <treechildren>. Очевидно, что
содержание, извлеченное из
В итоге можно сказать, что шаблоны объединяют данные, полученные в результате обработки запроса, с иным контентом, определяющим, как эти данные должны быть представлены.
Теги XUL, относящиеся к системе шаблонов, не отражены в конечном, видимом документе. Отображены теги, генерируемые системой. Оба типа тегов присутствуют в XUL документе одновременно, но теги шаблонов имеют такие стили, что не отображаются.
Теги шаблона формируют одно DOM поддерево XUL документа. После того, как шаблон генерирует свой контент, эти теги могут использоваться только для ссылок. Система шаблонов может перечитать такой тег, если прикладной программист добавит соответствующий скрипт.
Сгенерированные теги формируют поддерево DOM для каждого решения, найденного шаблонным запросом. Три решения дадут три поддерева. Эти поддеревья скажутся при любом обращении к ним пользователя или события, вызванного скриптом.
Каждое из сгенерированных поддеревьев имеет тег верхнего уровня.
Этот тег получит уникальный id атрибут, равный id используется как
Пример "hello, world", приводившийся в начале лекции, показывает эти поддеревья на снимке.
Шаблоны могут изменяться во время работы. Генерируемый ими контент тоже может меняться. Оба эффекта требуют применения JavaScript, и оба могут требовать очередного выполнения шаблонного запроса. Шаблоны могут и задерживать результат ("ленивое" порождение контента).
Для пересчета шаблона необходима одна строка на JavaScript. Не нужно перегружать никаких документов. Часть XUL документа, содержащая шаблон, и результат его работы изменяются "на лету". Окружающий контент не будет затронут, за исключением, возможно, оформления. Вот типичная строчка, выполняющая эту работу:
document.getElementByTagName('tree').builder.rebuild();
Теги шаблона также можно изменять, используя операции DOM 1, такие
как removeChild() и appendChild(). Однако если так сделать, выведенное
на экран содержание будет изменено при пересчете шаблона.
Если шаблон не изменит результатов запроса, выведенное на экран
содержание все равно изменится, когда изменятся
XUL документы не только задействуют шаблоны повсеместно, но и могут использовать их вновь и вновь в любое время.
Порождение контента может быть отложено. Это возможно только для
"Ленивое" вычисление работает, только если теги шаблона,
имеющие атрибут - следующие:
<menu> <menulist> <menubutton> <toolbarbutton> <button> <treeitem>
Дочерние теги этих тегов, такие как тег <menu> в <menulist> строятся "лениво".
Шаблоны, использующие <tree> или <menu>, могут
откладывать часть работы на более позднее время.
Два или большее количество шаблонов могут использовать одни и те же
Это очень мощное и полезное свойство шаблонов. Оно позволяет по-
разному взглянуть на одно и то же множество данных одновременно, и при
этом своевременно отображать изменения. Это используется, в частности,
в тех приложениях, где применяется метафора рабочего стола. Например,
в дизайнерских инструментах или Integrated
Чтобы увидеть эффект одновременного изменения контента в нескольких шаблонах, выполним следующий тест:
Менеджер Закладок содержит шаблон, основанный на теге <tree>.
Персональная Панель инструментов - на теге <. Элемент
меню "Уничтожить" запустит скрипт, который уничтожит факт,
содержащий информацию о новой закладке. Этот же скрипт предписывает
обоим шаблонам пересчитать содержание. Части контента, ассоциируемые с
этим уничтоженным фактом, ( <treeitem> в одном случае, и <toolbarbutton> в другом) исчезнут из списка найденных
результатов.
Система шаблонов добавляет объекты к AOM XUL-документа. Она
использует также несколько XPCOM компонентов и интерфейсов, в
частности,
database AOM-объекта, управляя фактами и исходными builder AOM-объекта, управляя процессом построения шаблона.<tree> - и <listbox> -образных шаблонов.Эти задачи будут описаны в разделе "Скриптинг". Они часто
требуют работы с компонентами XPCOM, поддерживающими
Последний технический аспект шаблонов - источники данных.
Данные
Шаблоны Mozilla могут извлекать факты из более чем одного источника
одновременно. Это значит, что, например, факты из более чем одного
Источники данных подробно рассматриваются в лекции 16, "Объекты XPCOM". Здесь же мы только отметим, что выбор источника данных для шаблона критичен. Если неправильно выбрать источник, вряд ли будет много толку. Необходимо знать свои источники данных.
Вот краткий обзор основных моментов. Каждый шаблон имеет
комплексный источник данных. Чтобы воздействовать на источник данных
шаблона из скрипта, зачастую необходимо найти и использовать один из
конкретных источников данных, вносящих свой вклад в результирующий
комплексный источник. Этот конкретный источник - список . Так часто
поступают, когда конструируют пользовательский снимок дерева
данных.
Раздел этой лекции, посвященный скриптам, описывает некоторые распространенные манипуляции с источниками данных. Рекомендуется изучить также лекцию 16, "Объекты XPCOM".
В данном разделе обсуждается, как шаблон собирается из составляющих
его частей, и рассматриваются конкретные теги. Общая конструкция
шаблона приведена в листинге 14.8. Это
<top>
<stuff/>
<template>
<rule> ... simple or extended rule info goes here ... </rule>
... zero or more further <rule> tags go here ...
</template>
<stuff/>
</top>
Здесь тегом, названным <top>, может быть любой обычный XUL
тег - <top> не реальный тег. Хотя собственно шаблон начинается
тегом <template>, некоторые атрибуты шаблонов могут быть
добавлены и к тегу <top>. Другой XUL-контент может
предшествовать или окружать тег <top>. Типичные кандидаты для
тега <top> - это <tree>, <, <menulist>, и <listbox>, но <top> может быть и <box> или даже <button>.
Тег, названный здесь <stuff>, тоже может быть обычным XUL
тегом, это не реальный тег. Эти теги опциональны и их может быть любое
число. Теги между <top> и <template> копируются и
генерируются лишь однажды для каждого шаблона и отображаются
графически также единожды перед содержанием шаблона.
Тег <template> - реальный XUL тег. Любой XUL-контент внутри
этого тега генерируется один раз для каждого решения, найденного
запросом. Тег <template> окружает весь контент, который должен
повторяться.
Тег <rule> - также реальный XUL-тег. Это единственный
контент, разрешенный внутри тега <template>. Может быть один или
более тегов <rule>, и предусмотрена также сокращенная запись,
позволяющая не писать ни одного. Каждый тег <rule> отвечает за
один запрос шаблона, как описывалось раньше, в разделе "Списки
запросов". Каждый тег <rule> также содержит контент. Этот
контент воспроизводится каждый раз, когда запрос находит решение.
Система шаблонов имеет несколько разных синтаксисов тега <rule>.
Наиболее гибкий и мощный - расширенный синтаксис шаблона. Этот
синтаксис требует, чтобы переменные запроса были определены в одном
месте, а применялись впоследствии в другом. Такие переменные
называются расширенными. Расширенный синтаксис требует, чтобы каждый
тег <rule> содержал ряд специальных тегов шаблона как часть его
контента.
Удобный и краткий синтаксис - простой синтаксис шаблона. Этот
синтаксис реализован для специального, но широко распространенного
случая, когда запрос обращается к контейнеру <rule>
содержал только простой XUL контент. Этот контент может содержать
простые переменные. Когда запрос шаблона находит решение, переменная
замещается найденными данными факта.
Если шаблон имеет только один тег <rule>, то простой
синтаксис имеет еще и краткую запись. Теги <rule> и </rule> можно отбросить. Краткая запись - иной способ записи
простого синтаксиса.
См. детальное описание тега <rule>.
Система XUL шаблонов имеет несколько специальных имен. Переменные
шаблонов не используются нигде, кроме как внутри тега <template>.
Расширенные переменные шаблонов Mozilla - это переменные,
используемые для простых (single
Расширенные переменные шаблона начинаются со знака вопроса ("?") и могут содержать любые символы. Регистр букв имеет значение. Они заканчиваются либо пробелом, либо знаком шляпки, или циркумфлекса ("^"), либо концом той строки, в которой они нам встретились. Пробел или шляпка не являются частью переменной. Если встречается пробел, он считается первым знаком контента, не относящимся к переменной. Если шляпка, она просто игнорируется.
Следующие имена переменных идентичны. Третий пример содержит XML сущность, означающую пробел.
"?name " "?name^" "?name #x20;"
Следующие примеры - тоже правильные имена. Мы рекомендуем, однако, всегда использовать значащие имена.
"?name_two" "?nameThree" "?name-four" "?name66" " ?66name" "?$%@$z+"
Простая запись для правил (см. тег " <rule> ") имеет
свои "переменные". Эти переменные - попросту
Простые переменные имеют формат:
rdf:URI
Такие переменные также оканчиваются пробелом (" ") либо шляпкой ("^"), либо заканчиваются вместе с содержащей их строкой. Пробел и шляпка не являются частью переменной. Пробел считается первым символом контента, не являющимся переменой, шляпка просто игнорируется.
Часть простой переменной, являющаяся
Примеры содержательных
"rdf:urn:test:example:more" "rdf:http://www.test.com/Test#Data"
И расширенные, и простые переменные используются только в значениях XUL атрибутов. Когда контент генерируется шаблоном, переменные замещаются найденными значениями.
Когда запрос находит решение, генерируется контент. Когда это
случается, имена переменных в содержащих их строках просто замещаются
их значениями. Если при этом переменная не имеет обосновывающего ее
значения (это возможно, если используется тег < ), то она
замещается строкой длины ноль.
Система шаблонов использует несколько специального вида " используется для
представления данных, генерируемых самой платформой Mozilla. Вот
список
rdf:addressdirectory rdf:bookmarks rdf:charset-menu rdf:files rdf:history rdf:httpindex rdf:internetsearch rdf:ispdefaults rdf:local-store rdf:localsearch rdf:mailnewsfolders rdf:msgaccountmanager rdf:msgfilters rdf:smtp rdf:subscribe rdf:window-mediator
Есть два специальных вида такого типа
rdf:null
означает использование источника данных, не содержащего фактов.
Такой источник данных, как правило, получит данные позднее из
JavaScript.
rdf:*
специфичная только для Mozilla запись, означающая
"соответствует любому предикату". Использование звездочки
("*") навеяно ее применением в
...
Эта запись идентична , но теперь ее не следует
использовать.
В таблице 11.3 приведены пространства имен, применяемые Mozilla для
работы с фактами
В XML часто используют атрибут xmlns, чтобы заменить длинный URL
пространства имен коротким алиасом. В системе шаблонов практически
всегда следует использовать полный URL, а не <rule>. В
этом случае
Тег верхнего уровня шаблона - родительский тег <template>. Он
называется базовым тегом шаблона. Это обычный XUL-тег, наподобие <tree> или <box>. Этот тег должен содержать часть
конфигурационной информации шаблона.
Специальные атрибуты, которые могут быть добавлены к такому тегу верхнего уровня:
datasources flags coalesceduplicatearcs allownegativeassertions xulcontentgenerated ref containment
Атрибут означает, что в шаблоне будут использоваться
.
Поскольку атрибут может иметь один или более
аргументов, он всегда является комплексным источником данных (имеющим
интерфейс nsIRDFCompositeDataSource ).
Если XUL-документ инсталлирован в . Этот
источник добавляет информацию о конфигурации
Атрибут flags используется для оптимизации выполнения шаблонного
запроса. Он применим только для
dont-build-content. Это ключевое слово относится к шаблонам
деревьев. Оно предписывает стандартному конструктору шаблона передать
ответственность по выводу на дисплей найденного контента встроенному
конструктору дерева. Конструктор шаблона по-прежнему генерирует
контент, основанный на
dont-test-empty. Это ключевое слово предписывает запросу не
обследовать контейнер, чтобы узнать, не пуст ли он. Это оптимизация,
которая позволяет не выполнять тест, который может оказаться весьма
дорогим. Она также позволяет системе шаблонов справиться с
динамическими иерархическими данными, где такой тест вообще
невозможен. Например, исследование сети может привести к такой
ситуации. В этом случае ответить на вопрос "не пусто ли множество
элементов сети?" невозможно, потому что код может ожидать, пока
придет ответ "нет" бесконечно. dont-test-empty - удачный
выбор для шаблонов, основанных на источнике данных .
coalesceduplicatearcs, allownegativeassertions, и xulcontentgenerated также несколько улучшают быстродействие и
модифицируют запрос.
Атрибут coalesceduplicatearcs, когда он указан, затрагивает факты,
которые могут быть извлечены из нескольких источников данных шаблона.
Большинство флагообразных атрибутов в Mozilla считаются
установленными, когда их значение равно true. Не так устроен этот
атрибут, его значение должно быть false. Он воздействует на то, каким
образом JavaScript обращается с фактами, а не с результатами запроса.
Если этот атрибут не установлен, идентичные данные из различных
источников данных шаблона будут обнаружены лишь единожды, а не по
одному результату на копию. Если он имеет значение false, все факты
будут обнаружены, независимо от того, дублируются они или нет. Запросы
выполняются быстрее, если этот атрибут установлен.
Атрибут allownegativeassertions, когда он установлен, также
затрагивает факты, которые могут быть извлечены из нескольких
источников данных шаблона. Большинство флагообразных атрибутов в
Mozilla считаются установленными, когда их значение равно true. Но
этот атрибут также может быть установлен в значение false. Он
воздействует на то, как JavaScript обращается с фактами, а не с
результатами запроса. Если этот атрибут не установлен, факт, который
утверждается и позитивно, и негативно, никогда не будет обнаружен,
поскольку два факта "погасят" друг друга.
Атрибут xulcontentgenerated применим к любому тегу в шаблоне, и к
любому тегу, сгенерированному шаблоном. Он приведен в данном списке
атрибутов, поскольку он также влияет на оптимизацию. Начинайте
экспериментировать с этим атрибутом только после того, как полностью
разберетесь с шаблонами. Атрибут xulcontentgenerated может иметь
значение true. Он сказывается в тот момент, когда запрос еще
выполняется, а контент генерируется. Если шаблон строится лениво, то в
каждый момент часть контента уже порождена, а часть нет. Если мы
обращаемся к тегу с какой-либо DOM операцией (наподобие добавления
дочернего тега), а тег имеет неполный, ленивый контент, может
возникнуть неясность. Куда добавить дочерний тег, если множество
дочерних тегов еще только предстоит вычислить? Mozilla решает эту
проблему, просто заставляя шаблон породить необходимый контент перед
выполнением DOM операций. Атрибут xulcontentgenerated отменяет эту
работу, чтобы ничего не пересчитывалось в данный момент в XUL дереве.
Это ускоряет DOM операции и отменяет ненужные вычисления.
Атрибут ref определяет начальную точку запроса. Он содержит полный
<Seq>, <Alt>, или < контейнера.
Атрибуты ref и containment обсуждаются в следующем разделе.
Атрибуты ref и containment можно использовать, чтобы определить
стартовую точку запроса, который не задействует официальный <Seq>, <, или <Alt>. Эти псевдоконтейнеры нуждаются в дополнительном
комментарии.
Рассмотрим обычный
<Description about="urn:eg:ownerA">
<prop1>
<Seq about="urn:eg:ContainerA">
<li>
<Description about="urn:eg:item1" prop2="blue"/>
</li>
</Seq>
</prop1>
</Description>
Предикаты в этом примере умышленно выбраны простыми. Листинг 14.9 эквивалентен трем фактам:
<- urn:eg:ownerA, prop1, urn:eg:containerA -> <- urn:eg:containerA, rdf:_1, urn:eg:item1 -> <- urn:eg:item1, prop2, blue ->
Первый факт в качестве подлежащего имеет item1 - член этого контейнера. В третьем факте записана некоторая
полезная информация о цвете данного item1. Это все обычный <Seq> листинга 14.9.
Предположим, программа имеет информацию об этих трех фактах, а не
исходный , чтобы понять,
что container A и есть ), но в этом примере достаточно
заметить .
Теперь предположим, что в эти три факта внесено единственное
изменение. Пусть предикат был заменен на (или что-
нибудь еще). Тогда три факта будут выглядеть так:
<- urn:eg:ownerA, prop1, urn:eg:containerA -> <- urn:eg:containerA, rdf:member, urn:eg:item1 -> <- urn:eg:item1, prop2, blue ->
В Листинге 14.10. показан фрагмент
<Description about="urn:eg:ownerA"> <prop1> <Description about="urn:eg:ContainerA"> <rdf:member> <Description about="urn:eg:item1" prop2="blue"/> </rdf:member> </Description> </prop1> </Description>
Есть ли по-прежнему контейнер в этих трех фактах? В конце концов,
оба случая так похожи. Можно утверждать, что контейнер действительно
существует. Во-первых, способ организации трех фактов не изменился.
Во-вторых, выбор в качестве предиката предполагает, что item1 принадлежит чему-то. В-третьих, любой запрос, построенный с
тегом <Seq>, может работать с новым предикатом точно так же, как
он работал со старым.
Суть в том, что рассматривая container, но продолжать рассматривать
Здесь нам придется снова рассмотреть атрибут ref. Он может быть
установлен в значение ", и этот ресурс
может служить начальной точкой запроса, независимо от того, выглядит
ли листинг исходного <Seq>, <, или <Alt> необязательны.
При данном гибком использовании ref есть одна хитрость. Mozilla
нужно определить, можно ли использовать данный ref ref
<Seq>, <Bag >, или <Alt> теги.Для Mozilla проверка на эти условия эквивалентна проверке на .
Если вы не хотите использовать предикаты или Folder в своих
фактах, вы не обязаны это делать. Вы можете использовать ваши
собственные предикаты. Чтобы это сделать, создайте containment к
основному тегу шаблона.
Атрибут containment может содержать список предикатов, разделенных
пробелами. Эти предикаты будут добавлены к списку тестов контейнера.
Эти предикаты будут тестироваться точно так же, как тестировались
элементы в предыдущем списке. Например, запись
containment="http://www.test.com/Test#member"
означает, что <Description> будет рассматриваться
Mozilla как контейнер, при условии, что xmlns:Test="http://www.test.com/ Test#"
было декларировано где-либо ранее:
<Description about="urn:foo:bar"> <Test:member resource="urn:foo:bar:item1"/> <Description>
Итак, запрос шаблона будет работать, даже если не существует
стандартных container. В этом случае необходимо указать
системе шаблонов, какие предикаты должны быть использованы для
реализации данного нестандартного контейнера.
Если для шаблона используется тег <tree>, применимы
добавочные атрибуты:
flex="1" statedatasource flags="dont-build-content"
Деревья не имеют значения атрибута height по умолчанию. Если шаблон <tree> не имеет атрибута , содержание шаблона
зачастую может не появиться на экране вообще. Всегда используйте
в шаблоне <tree>.
Атрибут statedatasource - устанавливается для именованного
источника данных, используемого для сохранения текущего состояния
дерева. Если пользователь откроет или закроет ряд поддеревьев на
экране, информация о том, какие поддеревья открыты, а какие закрыты,
будет сохранена в этом именованном источнике данных. В настоящее время
это используется только в
Если атрибут statedatasource не установлен, используется источник
данных, названный в атрибуте .
Значение "dont-build-content" атрибута flags также
используется только для деревьев. Оно описывается в разделе
"Основные теги".
Система шаблонов позволяет сортировать колонки данных. Это свойство реализовано для XUL меню, списков и деревьев.
Процесс сортировки использует несколько атрибутов. Они могут быть
установлены для базового тега шаблона, либо для конкретных тегов <listcol> или <treecol>. Это следующие атрибуты:
resource resource2 sortActive sortDirection sortResource sortResource2
Атрибут resource содержит переменную шаблона. Автор XUL-документа
указывает его для колонки, которая должна быть отсортирована. Этот
атрибут указывает ключ, содержащий данные, которые должны
сортироваться. Переменная шаблона, который он именует, представляет
предикат/свойство факта, дающего решение запроса для каждой строки.
Данные, используемые как ключ для сортировки, являются
дополнением/значением этого предиката. Другими словами, данный атрибут
указывает свойство, чье значение для каждой строчки должно
сортироваться.
sort - resource. Его также
применяют, чтобы указать сортируемую колонку в списке или дереве.
Используйте resource и sortActive, но не этот атрибут.
resource2 - вторичный предикат для сортирующего механизма.
Сортировка по значениям, указанным в resource, нестабильна. Это
означает, что после выполнения сортировки вторая колонка информации
может быть неупорядочена. Вторичный предикат используется, чтобы
отсортировать значения во второй колонке, если значения в первой
одинаковы. Тем не менее, третья и последующие колонки могут быть не
отсортированы.
sortActive может принимать значение true и указывать тем самым,
была ли произведена сортировка. Mozilla автоматически устанавливает
этот атрибут на нужную колонку списка или дерева. Его может указать и
программист приложения. Его можно использовать для доступа к колонке,
которая должна сортироваться, то есть его следует указывать всегда,
если не использован атрибут sort.
sortDirection может принимать значения , , или . Он может быть установлен автором XUL документа или Mozilla
автоматически после сортировки. Mozilla установит его одновременно и
на рассматриваемую колонку, и на базовый тег.
sortResource и sortResource2 - то же самое, что и resource и resource2. Эти атрибуты устанавливает Mozilla. Вторичный критерий
сортировки может быть установлен программистом с помощью JavaScript,
но не прямо в XUL.
sortSeparators может принимать значение true. Если он установлен,
закладки сортируются особенным образом. Сортировка не перемещает
элементы за границы разделителей закладок, если этот атрибут
установлен и используется источник данных .
Тег <template> содержит все детали информации о шаблоне,
которые не были указаны в базовом теге. Он содержит набор правил,
каждое из которых - пара запрос-контент. Тег <template> не имеет
собственных атрибутов. Единственный тег, который он может содержать -
тег <rule>. Зато он может содержать произвольное их число.
Если тегов <rule> нет, но есть иной контент, этот контент
считается единственным правилом с синтаксисом для простых правил.
Тег <template> может содержать простые и расширенные
правила.
Тег <rule> определяет единичный запрос шаблона и контент,
генерируемый для оформления вывода результатов запроса. Несколько
тегов <rule> формируют
Правила могут быть записаны с помощью простого и расширенного
синтаксисов. Если первый дочерний тег тега <rule> - это тег <, правило должно быть записано в расширенном
синтаксисе. В любом другом случае применим простой синтаксис. Тег <rule> может быть единственным тегом без какого-либо
контента.
Все запросы с простым синтаксисом и многие с расширенным
основываются на фактах в
Это стандартное устройство также эквивалентно
JavaScript: var container = {item1:{p1:v1,p2:v2}, item2:{p1:v1,p3:v3}}
В этой строке контейнер содержит два элемента. item1 и item2 - это
объекты, каждый из которых имеет множество свойств pN. Каждое свойство
имеет значение vN. Может быть любое число элементов, каждый с любым
числом свойств. Суть такой структуры - дать легкий доступ ко множеству
объектов и интересующим нас свойствам. Листинги 14.2,
14.5, 14.7, и
14.9 являются корректными примерами этой структуры в
<Seq about="container"> <li resource="item1"/> <li resource="item2"/> </Seq> <Description about="item1" p1="v1" p2="v2"/> <Description about="item2" p1="v1" p3="v3"/>
Чтобы сделать <Seq> обычно
заворачивают в тег <Description>, не показанный в
листинге 14.11. <Seq> может быть, кроме того, заменен на <
или <Alt>. Вместо них можно использовать тег <Description>
в роли контейнера.
Все факты, которые обрабатываются запросом с простым синтаксисом, должны иметь это стандартное устройство.
Простой синтаксис тега <rule> не имеет специальных
тегов.
Весь контент тега <rule> генерируется каждый раз, когда
запрос находит решение. Контент тега <rule> может содержать
простые переменные шаблона, помещенные в любое значение атрибута XML.
Контент генерируется так же, как для тега <action>, за
исключением двух незначительных отличий: простой синтаксис требует,
чтобы атрибут имел значение , и простой синтаксис не может
использовать тег <textnode>.
Когда применяется простой синтаксис, тег <rule> имеет
несколько специальных атрибутов:
type iscontainer isempty predicate="object" parsetype
Все эти атрибуты определяют, будет ли запрос правила успешен. Часть
запроса определяется предположением, что
Атрибут type взят из официального пространства имен
Его обычно записывают как , включая это пространство имен
ранее где-либо в документе XUL с помощью xmlns. Можно указать и с полным именем предиката, как
http:// home.netscape.com/NC-rdf#version.
Этот атрибут используется для проверки существования предиката. То
есть проверяет, существует ли в
Атрибут iscontainer может иметь значение true или false.
Значения по умолчанию нет. Он проверяет, является ли подлежащее данного факта
контейнером, используя "тесты контейнера", описанные ранее в
разделе "Атрибуты ref и containment: Тесты контейнера". Если
тесты не проходят, правило отвергает данного кандидата на решение.
Атрибут может иметь значение true или false. Значения по
умолчанию нет. Он проверяет, содержит ли данный true он проверяет, имеет ли
подобный контейнеру
Атрибут означает любую пару имен
предиката и дополнения. Поскольку имена предикатов зачастую длинны, их
сокращают, добавляя xmlns-декларацию в начале XUL документа. Если это
сделано, пара наподобие
NC:version="0.1"
проверяет, существует ли предикат version в пространстве имен NC
(вероятно, http://home.netscape.com NC-rdf#) и имеет ли он дополнение
со значением "0.1" - иными словами, имеет ли объект в контейнере
свойство version со значением "0.1". Следующие
зарезервированные имена не могут применяться для предиката, поскольку
они используются иным образом:
property instanceOf id parsetype
Эти три атрибута, плюс любое число тестов ,
могут содержаться в одном теге <rule>. Они
соединены между собой булевым AND и относятся ко всем запросам
правила. Если никакой из них не указан, то любой факт в контейнере
является решением для запроса. Если любой из них присутствует, запрос
не найдет решения, если хоть какой-то из этих атрибутов не
удовлетворяется.
Последний атрибут, parsetype, может иметь значение Integer. Если
это указано, во всех парах часть
"объект" будет интерпретироваться как целое. Любое нецелое
значение приведет к тому, что весь запрос будет проигнорирован. Если
атрибут не используется, объектные части пар интерпретируются как
строки. Система запросов не имеет встроенной математики для, например,
складывания целых. Она лишь выясняет, целое перед ней или строка.
Запрос в простом правиле обычно может быть выражен и как расширенное правило. Листинг 14.12 - пример простого синтаксиса, использующего некоторые из специальных атрибутов.
<rule iscontainer="true" isempty="false" rdf:type="http://home.netscape.com/NC-rdf#version" NC:title="History" >
Эквивалентный расширенный синтаксис приведен в листинге 14.13.
<rule>
<conditions>
<content uri="?uri"/>
<member container="?uri" child="?item"/>
<triple subject="?item
predicate="http://home.netscape.com/NC-rdf#version"
object="?version"/>
<triple subject="?item"
predicate="http://home.netscape.com/NC-rdf#title"
object="History"/>
</conditions>
Расширенный синтаксис может делать все то же, что и простой, за
исключением опций iscontainer="false" и
(значения, противоположные приведенным в примере в
листинге 14.12). Эти две опции в расширенном синтаксисе невозможны.
Расширенный синтаксис может проверить существование факта, но не его
отсутствие. Эти простые проверки все же можно осуществить в
расширенном синтаксисе, указывая два правила, а не одно. Первое
правило проверяет наличие конкретного факта, но не генерирует
контента, второе отбирает оставшиеся случаи, в которых контент
отсутствует, и генерирует требуемый.
Когда используется расширенный синтаксис, тег <rule> не имеет
специальных атрибутов. Этот синтаксис - наиболее гибкий и мощный из
всех синтаксисов шаблонов. В разделе "Часто встречающиеся образцы
запросов" приведены рецепты для наиболее распространенных
случаев. В данном же разделе описываются опции синтаксиса.
Расширенный синтаксис правил состоит из тега <rule> с двумя
или тремя дочерними тегами. Тег < должен быть первым
из дочерних тегов и должен содержать запрос правила. Тег < - необязательный средний тег, позволяющий создавать
дополнительные переменные. Тег <action> содержит тот контент,
который следует генерировать при каждом обнаружении решения. Эти теги
рассматриваются каждый в своем подразделе.
Расширенный синтаксис правил использует расширенный синтаксис
переменных, и эти переменные могут использоваться в дочерних тегах
тега <template>. Обычно их помещают в теги определения колонок в
списках и деревьях.
<.
Тег < содержит запрос шаблона, описанный
расширенным синтаксисом. Этот тег не имеет собственных атрибутов.
Если он присутствует, он должен быть первым тегом <rule>.
Рекурсивность <.
Этот тег может содержать теги <content>, <triple> и <. Первым дочерним тегом должен быть <content>, и
этот тег должен быть ровно один. Тег <content> должен также
содержать по крайней мере один тег < или <triple>.
Тег < может содержать тег <treeitem>. Если
шаблон основан на теге <tree>, то вместо тега <content>
можно использовать <treeitem>. В этом случае он записывается и
ведет себя точно так же. Нет никаких особенных причин поступать именно
так, это всего лишь память "давно минувших дней". <treeitem> считается устаревшим, лучше использовать <content>, однако на старых версиях платформы следует
использовать <treeitem>.
Когда эти теги используются, их порядок должен соответствовать порядку перебора ("бурение" данных), используемому процессором запроса. То есть это тот же порядок, что и иерархический порядок самих исследуемых данных.
Тег <content> должен быть первым дочерним тегом тега <. Он имеет единственный специальный атрибут:
uri
Это атрибут расширенной переменной шаблона. Данная переменная затем
обосновывается значением атрибута ref базового тега шаблона. Это
значение является стартовой точкой запроса. Если запрос рекурсивен,
вместо атрибута ref используется атрибут родительского запроса.
Тег <content> всегда имеет одну и ту же форму, так что обычно он
выглядит вот так:
<content uri="?uri"/>
Атрибут также используется в дочерних тегах тега <action>. Переменная, употребленная как атрибут тега <content>, никогда не должна употребляться как значение
атрибутов , появляющихся в контенте тега <action>. Если ее
использовать таким образом, запрос в шаблоне не обнаружит решений, и
никакого контента не будет порождено. Переменная, используемая в
атрибуте тега <content>, может появляться в любом другом
месте контента тега <action>.
Если шаблон основан на дереве, в версиях платформы младше 1.5
используется тег <treeitem>, вот так:
<treeitem uri="?uri"/>
Тег <treeitem> также может быть частью порождаемого контента.
В этом случае он может присутствовать в теге <action>, но любой
атрибут в качестве значения должен иметь переменную, отличную от ?.
Тег <triple> представляет один шаг (одну арку в графе <triple> увеличивает
число шагов на единицу, и также на единицу увеличивает число фактов,
требуемых для решения. Тег <triple> используется для связи
фактов с переменными и для обнаружения фактов. Тег <triple>
имеет следующие специальные атрибуты, которые должны всегда
присутствовать.
subject predicate object
может принимать значение расширенной переменной шаблона или
может принимать значение
object может принимать значение расширенной переменной шаблона,
В атрибутах предиката нельзя использовать переменные.
Можно сконструировать последовательность тегов <triple> так,
что они образуют <triple> с нулевыми
переменными бесполезен.
Тег < используется для поиска элементов, содержащихся
в теге-контейнере. Он имеет специальные атрибуты
container child
Атрибут container - это
сравнивается с дополнениями фактов, имеющими подлежащим
<member container="?uri" child="?item"/>
Поскольку искомые связи внутри или что то подобное в качестве
предиката), обычный тег <triple> может быть использован для
поиска этих элементов. Тег < - попросту
специализированная версия тега <triple>.
Преимущество, которое имеет тег < перед тегом <triple> состоит в том, что можно вообще не указывать предикат.
Тег < может применять тесты контейнера, описанные ранее в
разделе "Атрибуты ref и containment: тесты контейнера".
Чтобы выполнить ту же работу с тегом <triple>, придется
задействовать добавочный запрос, указывающий
Хотя атрибут контейнера тега < часто содержит
Тег < - необязательная часть расширенного синтаксиса
запроса. Он не имеет специальных атрибутов, и может содержать только
теги <. Теги < и <
постоянно используются в Mozilla, особенно в XBL. Между их применением
в шаблонах и где угодно еще нет прямой связи. В терминах SQL, они
являются реализацией инструкции " и нулевых
значений.
Тег < следовало бы называть <, поскольку это вовсе не "привязка" в смысле
XBL (или XPConnect или -переменная это просто
добавочная переменная, которая может быть обоснована добавочным
запросом. Это же значение имеет и тег <.
Раздел правила < - это место, где можно поместить
добавочные переменные, не ограничивая результатов <
запроса. Сделать это очень просто. В секции < все
переменные должны быть обоснованы, чтобы было найдено решение. Это
решение передается в секцию . Далее процессор запроса пытается
обосновать все переменные, перечисленные в секции <.
Если лишь некоторые из них удается обосновать, процессор просто
присваивает остальным нулевые значения. Это значит, что решения < никак не ограничиваются переменными <. Фактически, секция < подобна - если что-то подходит, об этом сообщается, в
противном случае вы получаете только то, что найдено по запросу.
Переменные в секции < должны быть расширенными
переменными шаблона. Переменные из раздела < можно
использовать здесь, но не наоборот. Чтобы секция <
имела смысл, должна быть использована по крайней мере одна из
переменных секции <.
Тег < идентичен тегу <triple> по атрибутам и
способу использования. Он отличается от <triple> только в
правилах, применяемых для обоснования его переменных, как описано в
разделе <.
Тег <action> используется в <rule> с расширенным
синтаксисом запроса. Он дает контент, который будет генерироваться
для каждого результата данного запроса. Контент правила <rule> с
простым синтаксисом генерируется точно так же, как контент тега <action>. Здесь описывается система генерации.
Контент тега <action> состоит из обычных XUL тегов и
расширенных переменных запроса. Система шаблонов замещает значение
каждой переменной при генерации контента. Таким образом, переменные
используются в теге <action>, хотя определяются и обосновываются
в теге < (они определяются и обосновываются
автоматически при простом синтаксисе). Система шаблонов добавляет
атрибут id каждому тегу каждый раз, когда генерируется контент. Тег <action> не может включать тег <script>.
Контент тега <action> должен быть организован так, как
показано в листинге 14.14
<action> // simple syntax:
<rule>
<box id="A">
<box id="B">
<box id="C" uri="?var"> // simple syntax: uri="rdf:*"
<box id="D"/>
<box id="E">
<box id="F"/>
</box>
</box>
</box>
</box>
</action>
Мы используем этот пример, чтобы объяснить, что и как
здесьработает. В общем случае теги могут вкладываться на произвольную
глубину внутри <action>, и может быть использован любой XUL-код.
Специальный случай шаблонов, основанных на деревьях, обсуждается
отдельно.
Контент тега <action> делится на тег, содержащий атрибут ,
порождающие его теги и наследующие ему теги. В листинге 14.14 С
содержит ; A и B - теги-предки; D, E и F - дочерние теги.
Теги-предки A и B порождаются лишь однажды, независимо от того, как
много решений обнаружит запрос. Если переменные запроса (расширенные
для контента <action>, простые для контента <rule> )
используются в A и B, они будут иметь значения, найденные в первом
решении запроса. Если A и B имеют дочерние теги, эти теги могут быть
неадекватны. Рекомендуется их избегать.
Тег C - начало повторяющегося контента, поскольку он имеет атрибут . И С, и его контент могут генерироваться как целое ноль и более
раз. Чтобы контент был сгенерирован хоть один раз, должны быть
выполнены два условия. Во-первых, запрос должен обнаружить хоть одно
решение. Во-вторых, значение атрибута тега C в этом обнаруженном
решении должно быть другим. Самый простой способ удостовериться, что
это именно так - установить его в значение переменной, упоминаемой как
дополнение в некотором тега <. В этом случае необходимо использовать ?item:
<member container="?seq" child="?item"/>
В наиболее общем случае, атрибуту должно быть присвоено
значение подлежащего или дополнения, разные для каждого решения,
обнаруженного запросом. Атрибут id принимает данное уникальное
значение для каждого тега C во время генерации контента. Тег C не
должен иметь дочерних тегов, это может привести к ошибке.
Рекомендуется в данном случае дочерних тегов избегать.
Если требуется построение контента с задержкой
("ленивое"), тег C должен быть одним из следующих
XUL-тегов:
<menu> <menulist> <menubutton> <toolbarbutton> <button> <treeitem>
Теги D, E, и F - обычные теги, генерируемые один раз на каждое
найденное решение запроса. Они могут иметь дочерние теги и обширный
собственный контент. Если эти теги имеют переменные шаблона, такие
переменные будут замещены найденными решениями.
Контент шаблонов, основанных на теге <tree>, может нарушать
правило, согласно которому теги-родители
Если шаблон основан на теге <tree>, каждый <treeitem> в
финальном дереве может иметь тег <treechildren> как свой второй
дочерний тег. Этот тег может содержать любое число поддеревьев. К
счастью, контент тега <action> должен представлять единственную
строку дерева. Конструктор шаблона, обрабатывающий тег <tree>,
достаточно разумен, чтобы скопировать этот контент в каждое поддерево.
Другими словами, он достаточно разумен, чтобы определить необходимость
<action> нужно прописать
достаточно аккуратно, чтобы такая конструкция работала. Она показана в
Листинге 14.15.
<action>
<treechildren> //simple syntax: use <rule>
<treeitem uri="?var"> //simple syntax: use uri="rdf:*"
<treerow>
... any normal treerow content ...
</treerow>
</treeitem>
</treechildren>
</action>
Все теги в этой конструкции могут иметь добавочные атрибуты. Не
следует использовать атрибут id для тега <treeitem>.
Переменная ?var обычно соответствует переменной в дополнении тегов < или <triple>.
Данный синтаксис можно слегка изменить, и даже использовать такой
шаблон внутри другого шаблона. Например, так, что тег <treeitem> порождается из одного источника <treechildren> - из другого. Подобные вложения следует
тщательно тестировать, потому что они не используются широко и,
следовательно, не являются достаточно надежными.
Шаблоны, основанные на деревьях, используют <action>
перед <treechildren>, см. листинг 14.15. Эта новая копия становится
затем отправной точкой для всех решений, найденных новым запросом.
И простые, и расширенные переменные могут появляться только в
значениях атрибутов XML. Некоторые теги XUL порождают текстовое
содержание между их открывающей и закрывающей частями. Например, тег <Description>.
Тег <textnode> предоставляет способ поместить переменную в
контент, не являющийся атрибутом. Предположим, переменная ?var в
некоторый момент содержит строку "red". Тогда строка
<tag> <textnode value="big ?var truck"/> </tag>
будет эквивалентна строке
<tag>big red truck</tag>
Тег <textnode> можно поместить в любое место внутри тега <action>. Тег <textnode> не может быть использован, если
запрос задействует простой синтаксис. На данном теге мы завершим
рассмотрение тегов шаблона.
В шаблонах широко используются следующие запросы.
Наиболее очевидные запросы шаблонов используют стандартную
организацию фактов, а это означает применение
Запросы одного факта (см. предыдущее обсуждение) можно
сконструировать лишь с использованием расширенного синтаксиса
запросов. Простой синтаксис использовать нельзя. Запросы одного факта
могут возвратить ноль или более решений. Единственное неизвестное
может быть лишь дополнением запрашиваемого факта. Подлежащее и
предикат должны быть известны и вдобавок буквально указаны в запросе.
Подобный запрос можно реализовать лишь с тегами < или <triple>. Если использовать тег <, это выглядит
так:
<rule>
<conditions>
<content uri="?uri"/>
<member container="?uri" child="?data"/>
</conditions>
<action>
<description uri="?data" value="?uri ?data"/>
</action>
</rule>
В данном случае, если предикат единичного факта не является фактом,
содержащимся в контейнере (то есть , или некоторым специфичным
для Mozilla значением, например ), то этот предикат должен быть
указан в атрибуте containment. В данном атрибуте можно перечислить
несколько альтернативных предикатов. В случае <triple> код
выглядит так:
<rule>
<conditions>
<content uri="?uri"/>
<triple subject="?uri" predicate="predURI" object="?data"/>
</conditions>
<action>
<description uri="?data" value="?uri ?data"/>
</action>
</rule>
Предикат - "predURI", выраженный литералом. Если
требуется указать несколько предикатов, используйте несколько правил rule.
Набор свойств - это запрос, чьей целью является получение ряда
элементов информации, связанных с подлежащим факта. Типичный пример,
когда мы рассматриваем подлежащее как объект JavaScript и хотим
получить значения свойств этого объекта. Другой пример - считать
подлежащее факта идентификатором записи в базе данных и получить все
элементы данной записи. Эти аналогии не противоречат обычному
использованию терминов "свойство" и "значение" в
Если подлежащее и его свойства являются членами
<rule> <box uri="rdf:*"> <label value="rdf:http://www.test.com/Test#Prop1"/> <label value="rdf:http://www.test.com/Test#Prop2"/> <label value="rdf:http://www.test.com/Test#Prop3"/> <label value="rdf:http://www.test.com/Test#Prop4"/> </box> </rule>
Если подлежащее и его свойства не являются элементами контейнера,
следует использовать расширенную запись запроса. В этом случае
стартовая точка та же, что и в запросе единичного факта, с
использованием тега <triple>. Должно быть известно, что по
крайней мере одно свойство существует.
<rule>
<conditions>
<content uri="?uri"/>
<triple subject="?uri" predicate="p1" object="?v1"/>
<triple subject="?uri" predicate="p2" object="?v2"/>
<triple subject="?uri" predicate="p3" object="?v3"/>
<triple subject="?uri" predicate="p4" object="?v4"/>
</conditions>
<action>
<description uri="?data" value="?v1 ?v2 ?v3 ?v4"/>
</action>
</rule>
Здесь p снова означает полный <triple>. Если некоторые свойства могут
не существовать (или имеют значение null ), соответствующий
тег <triple> можно заменить тегом < и переместить в
секцию <.
Если запрос находит ровно одно решение, оно называется единственным решением. Обычно это бывает, если прикладной программист знает, что решение всегда существует, и единственно. Этот случай не требует специального синтаксиса, это просто следствие устройства фактов.
Здесь есть, однако, некоторая хитрость. Она возникает, когда мы
используем атрибут в теге <action>. Поскольку речь идет о
теге <action>, значит, это расширенный синтаксис. Здесь
возникает случай, когда запрос найдет множество решений, но построит
контент лишь для одного. Это возможно только для комплексных запросов.
Приведенный ниже пример иллюстрирует этот случай. Предположим, что у
нас есть следующий контент
<Description about="urn:example:root">
<link1>
<Description about="urn:example:child">
<link2 resource="urn:example:X"/>
<link2 resource="urn:example:Y"/>
</Description>
</link1>
</Description>
Все ресурсы этих фактов можно обнаружить таким запросом:
<rule>
<conditions>
<content uri="?uri"/>
<triple subject="?uri" predicate="p1" object="?child"/>
<triple subject="?child" predicate="p2" object="?res"/>
</conditions>
<action>
<description uri="?res" value="?uri ?child ?res"/>
</action>
</rule>
В этом запросе p1 и p2 нужно заменить подходящими link1 и link2. Поскольку переменная ? принимает свое значение для каждого
решения (одно X и одно Y), будут порождены две копии контента тега <action>. Если, однако, тег <description> заменить
следующей строкой, будет порождена лишь одна копия:
<description uri="?child" value="?uri ?child ?res"/>
Здесь порождается лишь одна копия, потому что переменная ?
может быть обоснована лишь одним значением. Обычно найденное решение
соответствует первому найденному в документе
Все запросы шаблонов эквивалентны навигации по дереву данных, поскольку система запросов использует стратегию "сначала вниз". Запросы шаблонов кажутся сложными, потому что (а) зачастую они рекурсивны, (б) требуется расширенный синтаксис. Сложный синтаксис маскирует тот факт, что на самом деле они очень просты. Листинг 14.16 иллюстрирует это положение.
<tree flex="1" datasources="test.rdf"
ref="http://www.example.com/test.rdf">
<treecols>
<treecol id="colA" primary="true"/>
</treecols>
<template>
<rule>
<conditions>
<content uri="?uri"/>
<member container="?uri" child="?item"/>
</conditions>
<action>
<treechildren>
<treeitem uri="?item">
<treerow>
<treecell label="?item"/>
</treerow>
</treeitem>
</treechildren>
</action>
</rule>
</template>
</tree>
В листинге 14.16 приведена прямолинейная минимальная комбинация
шаблона и дерева. Темным выделена разметка шаблона, светлым - разметка
дерева. Несмотря на то, что конструируется общий случай, разметка
собственно шаблона очень проста. Секция <rule> есть не что иное,
как запрос единичного факта. Результат запроса используется ровно в
одном месте. Код кажется сложным, потому что перегруженная разметка
дерева смешивается с перегруженной разметкой шаблона. Если тег <tree> заменить на <box> а порождаемый контент
минимизировать до тега <description>, шаблон сведется к
листингу 14.17.
<box datasources="test.rdf" ref="http://www.example.com/test.rdf">
<template>
<rule>
<conditions>
<content uri="?uri"/>
<member container="?uri" child="?item"/>
</conditions>
<action>
<description uri="?item" value="?item"/>
</action>
</rule>
</template>
</box>
Здесь видно, что он несложен.
Эту запись можно упростить и дальше, если
Оба факта должны повторяться вниз по дереву, поскольку каждый шаг запроса требует обоих фактов. Это значит, что дерево, исследуемое запросом с простым синтаксисом, должно быть вдвое больше, нежели дерево, запрашиваемое более экономичным расширенным. В листинге 14.17 требуется только один факт на каждый шаг вниз по дереву.
Есть несколько способов получить решения объединений двух или более запросов.
Атрибут может указывать на несколько
Атрибут containment может добавить к запросу несколько
разных предикатов container.
Можно использовать несколько тегов <rule>, чтобы найти более
одного решения на данном множестве фактов.
Можно использовать несколько тегов <, чтобы получить
несколько поддеревьев данного запроса.
Следующий запрос не будет обработан:
<rule> <conditions> <content uri="?uri"/> <triple subject="?uri" predicate="a" object="?v1"/> <triple subject="?v1" predicate="b" object="?v2"/> <triple subject="?v2" predicate="c" object="?v3"/> <triple subject="?v4" predicate="d" object="?v3"/> </conditions> </rule>
В данном запросе последний тег <triple> не использует
переменную ?v3 как подлежащее, а пытается двигаться по дереву в
обратную сторону. Это уменьшает глубину проникновения в дерево на шаг,
вместо того чтобы двигаться вглубь. Такое поведение запроса не
реализовано, все условия < должны продвигать запрос в
одну сторону.
Рассмотрим те шаги, которые последовательно проходит запрос шаблона. Первая часть процесса - начальное порождение контента XUL.
observers ), эти наблюдатели отслеживаются в процессе поиска.Вторая часть процесса касается взаимодействия пользователя и шаблона после завершения первоначального порождения контента.
<listbox> или <tree>, должны откликнуться на эти действия,
возможно даже обновляя содержание источника фактов. Перетаскивание
мышкой контента шаблона требует от прикладного программиста написания
дополнительных скриптов.nsIRDFRemoteDataSource.Рассмотрим, как улучшать шаблоны из скриптов и управлять ими, и как
использовать продвинутые свойства деревьев, обсуждавшиеся в лекции 13,
"Списки и деревья". Лекция 16, "Объекты XPCOM",
содержит подробное описание
Шаблоны на чистом XUL относительно просты, поскольку неизменны и порождают контент лишь однажды. Шаблоны с использованием XUL, JavaScript, AOM и XPCOM - это достойная задачка, потому что полная функциональность в этом случае скорее исключение, чем правило. Вот некоторая трансцендентная мудрость о динамических шаблонах:
dont-build-content, и другие флаги, сказывающиеся на
производительности, не работают, когда шаблон должен быть перестроен
как целое. Они воздействуют лишь на производительность обработки любой
рекурсивной части запроса шаблона, и на способ слияния множественных
источников данных.ref шаблона может быть изменено в любое
время, и порождаемый контент будет автоматически перестроен.ref, требуют
вызова метода rebuild () вручную.nsIRDFCompositeDataSource, содержащий все источники
данных шаблона, не следует использовать для добавления новых фактов
(ни методом Assert () ни любым другим). Всегда работайте с конкретным
источником данных.in-memory-datasource (изначально пустые источники данных, в дальнейшем
заполняющие значение rdf :null атрибута datasources ) и xml-datasource
(xml-datasource можно лишь с помощью схемы file:. С использованием
схем chrome : или resource:, или любой иной, этого делать не
следует.beginBatchUpdate() для
деревьев в Таблице 13.3.Flush () поддерживается лишь для источников данных,
основанных на URL типа "file:".Refresh() поддерживается для URL типа "file:" и "http:". Используя этот метод для получения файла с
web-сервера, проследите, чтобы получаемые данные нигде не кешировались,
это может привести к некорректному поведению системы.Система шаблонов добавляет свойства JavaScript к объектам, представляющим теги шаблона. Свойства добавляются и к тегам, определяющим шаблон, и к порождаемым тегам. Такие свойства добавляются к стандартным свойствам тегов шаблона. Эти свойства указаны в Таблице 14.1.
| Свойство | Полезность | Тег <template> |
Теги правил | Порожденные теги |
|---|---|---|---|---|
database |
+ | - | - | - |
builder |
Иногда + | - | - | - |
resource |
+ | + (содержит id тега) |
- | + (содержит значение null ) |
|
+ | Пустая строка | Пустая строка | Пустая строка |
ref |
+ | Пустая строка | Пустая строка | Пустая строка |
В этой таблице, "+" означает, что свойство приобретает некоторое полезное значение; "-" значит, что свойство приобретает значение null; "Пустая строка" означает, что свойство содержит строку длины нуль.
Свойство database - это объект, содержащий ссылки на источники
данных, используемые шаблоном. Он реализует интерфейс nsICompositeDataSource XPCOM. Он существует даже если единственный
источник данных . Для шаблонов, получающих данные из .
Свойство builder - это объект, управляющий запросом и процессом
порождения контента шаблона. Его можно рассматривать как
высокоспециализированный (и очень ограниченный) инструмент верстки и
рендеринга шаблона. Он реализует интерфейс nsIXULTemplateBuilder. Он
используется лишь для шаблонов на основе тегов <listbox> и <tree>.
Свойство resource - это объект, содержащий <template>, он содержит id шаблона, как
не-, он
содержит значение указанной расширенной переменной шаблона. Объект
реализует интерфейс nsIRDFResource.
Свойство содержит значение XUL атрибута .
Свойство ref содержит значение XUL атрибута ref.
Объект database имеет методы AddDataSource(), RemoveDataSource(), и GetDataSources(), используемые для управления источниками данных
шаблона.
Объект builder имеет метод , используемый для полного
пересчета и обновления содержания шаблона.
Объект resource и атрибуты и ref существуют лишь для
удобства. Ни один из этих объектов не может быть замещен прикладным
программистом.
В дополнение к данным объектам AOM, существуют объекты-наблюдатели, объекты-снимки и объекты-делегаты конструкторов шаблонов. Они рассматриваются ниже.
Конструкторы шаблонов - это конструкторы, то есть код внутри платформы Mozilla, порождающий контент дерева. Конструкторы не могут быть реализованы прикладным программистом, но могут модифицироваться.
Простейшее использование конструктора - пересчет и обновление дерева в шаблоне. Требуется лишь одна строка кода:
treeElement.builder.rebuild()
Здесь нет опций. Эта техника работает только для шаблонов,
построенных на тегах <tree> или <listbox>. не
работает на шаблонах, построенных на иных тегах.
Во время перестройки дерева состояния open и closed всех
поддеревьев сохраняются, если указано ленивое построение дерева. Чтобы
этого не случилось, используйте атрибут statedatasource тега <tree>, и затем удалите источник данных перед перестройкой.
Чтобы его удалить, удалите источник данных из свойства databases,
затем удалите атрибут tree, используя операцию DOM, после чего
вызовите метод .
Вспомним, что в Mozilla используется два конструктора; конструктор контента XUL и конструктор шаблонов. Мы здесь обсуждаем последний. Конструктор шаблона основан на XPCOM-компоненте и интерфейсе:
@mozilla.org/xul/xul-template-builder;1 nsIXULTemplateBuilder
Данный интерфейс содержит метод . Данный конструктор не
может быть модифицирован или замещен прикладным программистом.
XUL конструктор имеет частный случай для деревьев:
@mozilla.org/xul/xul-tree-builder;1 nsIXULTreeBuilder
Этот конструктор также не может быть замещен прикладным
программистом. Но он может быть улучшен. С помощью интерфейса nsITreeBuilderObserver можно зарегистрировать новый объект. Хотя этот
интерфейс и напоминает объект-наблюдатель, он также очень похож и на
объект-делегат. Чем его считать - дело вкуса.
Интерфейс nsITreeBuilderObserver - подмножество интерфейса nsITreeView, применяемого для создания пользовательских снимков
дерева. Его можно использовать для улучшения способов взаимодействия
пользователя и дерева, такого как кликанье мышкой по колонкам и
перетаскивание мышкой контента. В приложениях Mozilla можно найти два
примера применения этого интерфейса: одно в менеджере закладок и одно
в
Эти интерфейсы применяются для реализации
Если используется объект с интерфейсом nsITreeBuilderObserver, его
нужно реализовать как наблюдатель DOM-объекта дерева с помощью метода addObserver() интерфейса nsITreeView.
Все конструкторы Mozilla также поддерживают интерфейс nsIRDFObserver, а это означает, что все дерево целиком может
действовать как наблюдатель. Этот интерфейс может быть добавлен
объекту источника данных (интерфейс nsIRDFDataSource ), и он будет
опрашиваться каждый раз, когда появляются новые факты, значимые для
запроса шаблона.
Если шаблон основан на дереве, то также доступны свойства снимков. В лекции 13, "Списки и Деревья", объяснялось, что снимки - это автоматически создаваемые объекты, используемые конструктором дерева или списка для генерации актуального в каждый момент контента.
Созданный программистом объект-снимок полностью заменяет контент,
который будет показан шаблоном как часть данных из файла <tree> - , то созданный
программистом снимок делает всю работу по наполнению дерева данными.
Простейший способ это реализовать - использовать тег <tree> с
нормальной секцией <treecols>, плюс одна из трех следующих
опций для остающегося контента:
<children/> <template> <treechildren/> </template> <template> ... normal set of template rules ... </template>
Подобное дерево сначала построит свой обычный контент, затем, когда
снимок изменится и дерево будет перестроено, начинает действовать
снимок, который определяет дальнейший контент. Если использован
атрибут-флаг "dont-build-content", обычный контент вообще не
будет построен и показан.
Объекты-делегаты - это очень обобщенный термин в объектно-ориентированном программировании, и множество структур имеют делегато-подобные свойства.
В платформе Mozilla объекты-делегаты - это объекты, связывающие
URIs фактов
В этой лекции нет места и времени для подробного обсуждения
объектов-делегатов. Как стартовую точку изучения можно рекомендовать
интерфейсы nsIRDFResource и nsIRDFDelegateFactory, а также следующие
компоненты XPCOM:
@mozilla.org/rdf/delegate-factory;1?key=
Ниже приведен краткий список стратегий решения часто встречающихся
задач. Программируемые и другими внутренними
источниками данных.
Чтобы сменить источник данных, используйте databases.getDataSources(), шаг за шагом по доступному списку
источников, чтобы найти нужный, задействуйте databases.removeDataSource() с этим источником в качестве аргумента, и
затем перестройте шаблон. Либо удалите этот источник и перестройте
шаблон.
Чтобы сменить корневой setAttribute("ref",newURI) для базового тега. Шаблон будет
перестроен автоматически. Установка свойства ref даст тот же
эффект.
Чтобы сменить правила запроса, используйте операции DOM или
innerHTML чтобы изменить теги прямо в XUL, и затем перестройте шаблон
с помощью . Лучшее решение - создать все возможные правила и
затем запретить ненужные. Это можно сделать, поместив перед правилами,
которые нужно запретить, правило "catch-all". Правило "catch-all" - это такое правило, которое находит решения
всех доступных ему данных, так что до оставшихся правил дело не
доходит.
Чтобы изменить факты в источнике данных, выберите нужный источник с
помощью databases.GetDataSources(). Используйте методы или Change() интерфейса nsIRDFDataSource. В некоторых случаях шаблон будет
перестроен автоматически. Чтобы перестроить его наверняка, используйте .
Чтобы изменить результаты запроса, следует немного отступить назад.
Вы не можете изменить результаты, найденные запросом, потому что они
порождаются им. Необходимо изменить запрос или исходные @mozilla.org/
и другие чтобы
установить значение факта true. Затем перестройте шаблон.
Чтобы изменить порожденный контент, применяются обычные DOM
операции. (Эти изменения будут потеряны, если шаблон перестроить).
Чтобы сделать изменения постоянными, измените часть правила <content>, а не порожденный контент, и перестройте шаблон.
Система шаблонов не имеет специальных стилевых усовершенствований, но и с существующими стилями можно использовать несколько удачных приемов.
Контент шаблона можно оформлять стилями, и в атрибутах style и class использовать переменные шаблона. Таким образом стилевая
информация может предоставляться самими
Стили можно применять, используя теги <rule> как селекторы,
Наконец, стили можно применить к порожденному контенту, используя операции JavaScript DOM. Если шаблон будет перестроен, это стилевое оформление может потеряться.
Данный раздел "Практика" описывает использование шаблонов нашего приложения, работающих с реальными данными.
В этом разделе мы заменим часть нашего кода шаблоном и затем протестируем приложение на реальных данных.
Для начала, у нас есть модель
chrome://notetaker/contents/notetaker.rdf
Шаблоны нам понадобятся три раза:
Edit также должен загружаться с существующими ключевыми словами текущей заметки.Edit должно загружаться со всеми ключевыми словами, связанными с текущими ключевыми словами.Последний пункт требует специальной техники; содержание дерева, грубо говоря, должно уточнять содержание списка, а это требует координирования их работы.
Данные также появляются в HTML-записи на текущей web-странице. HTML
не поддерживает шаблонов, так что мы должны извлечь необходимые нам
данные из
Для того чтобы построить шаблон, нам нужны некоторые данные.
Создадим
В листинге 14.18 приведены данные для этих двух записей и связи ключевых слов.
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmnls:NT="http://www.mozilla.org/notetaker-rdf#">
<Description about="urn:notetaker:root">
<NT:notes>
<Seq about="urn:notetaker:notes">
<li resource="http://saturn/test1.html"/>
<li resource="http://saturn/test2.html"/>
</Seq>
</NT:notes>
<NT:keywords>
<Seq about="urn:notetaker:keywords">
<li resource="urn:notetaker:keyword:checkpointed"/>
<li resource="urn:notetaker:keyword:reviewed"/>
<li resource="urn:notetaker:keyword:fun"/>
<li resource="urn:notetaker:keyword:visual"/>
<li resource="urn:notetaker:keyword:cool"/>
<li resource="urn:notetaker:keyword:test"/>
<li resource="urn:notetaker:keyword:breakdown"/>
<li resource="urn:notetaker:keyword:first draft"/>
<li resource="urn:notetaker:keyword:final"/>
<li resource="urn:notetaker:keyword:guru"/>
<li resource="urn:notetaker:keyword:rubbish"/>
</Seq>
</NT:keywords>
</Description>
<!-- details for each note -->
<Description about="http://saturn/test1.html">
<NT:summary>My Summary</NT:summary>
<NT:details>My Details</NT:details>
<NT:top>100</NT:top>
<NT:left>90</NT:left>
<NT:width>80</NT:width>
<NT:height>70</NT:height>
<NT:keyword resource="urn:notetaker:keyword:test"/>
<NT:keyword resource="urn:notetaker:keyword:cool"/>
</Description>
<Description about="http://saturn/test2.html">
<NT:summary>Good place to list</NT:summary>
<NT:details>Last time I had a website here, my page also appeared on Yahoo </NT:details>
<NT:top>100</NT:top>
<NT:left>300</NT:left>
<NT:width>100</NT:width>
<NT:height>200<NT:height>
<NT:keyword resource="urn:notetaker:keyword:checkpointed"/>
<NT:keyword resource="urn:notetaker:keyword:reviewed"/>
<NT:keyword resource="urn:notetaker:keyword:fun"/>
<NT:keyword resource="urn:notetaker:keyword:visual"/>
</Description>
<!-- values for each keyword -->
<Description about="urn:notetaker:keyword:checkpointed" NT:label="checkpointed"/>
<Description about="urn:notetaker:keyword:reviewed" NT:label="reviewed"/ >
<Description about="urn:notetaker:keyword:fun" NT:label="fun"/>
<Description about="urn:notetaker:keyword:visual" NT:label="visual"/>
<Description about="urn:notetaker:keyword:breakdown" NT:label="breakdown"/>
<Description about="urn:notetaker:keyword:first draft" NT:label="first draft"/>
<Description about="urn:notetaker:keyword:final" NT:label="final"/>
<Description about="urn:notetaker:keyword:guru" NT:label="guru"/>
<Description about="urn:notetaker:keyword:rubbish" NT:label="rubbish"/>
<Description about="urn:notetaker:keyword:test" NT:label="test"/>
<Description about="urn:notetaker:keyword:cool" NT:label="cool"/>
<!--sufficient related keyword pairings -->
<Description about="urn:notetaker:keyword:checkpointed">
<NT:related resource="urn:notetaker:keyword:breakdown"/>
<NT:related resource="urn:notetaker:keyword:first draft"/>
<NT:related resource="urn:notetaker:keyword:final"/>
</Description>
<Description about="urn:notetaker:keyword:reviewed">
<NT:related resource="urn:notetaker:keyword:guru"/>
<NT:related resource="urn:notetaker:keyword:rubbish"/>
</Description>
<Description about="urn:notetaker:keyword:fun">
<NT:related resource="urn:notetaker:keyword:cool"/>
</Description>
<!-- single example of a cycle -->
<Description about="urn:notetaker:keyword:cool">
<NT:related resource="urn:notetaker:keyword:test"/>
</Description>
</Description>
</RDF>
К сочетанию
Сначала мы напишем шаблоны для панели инструментов NoteTaker. Для панели инструментов потребуется два значения, по одному для каждого поля ввода текста, и набор из нуля или более элементов выпадающего меню. Нужно использовать два шаблона, один для полей ввода и другой для выпадающего меню.
Выпадающее меню - самое простое. Из файла notetaker.label. Ключевые слова
собираются вместе в , т.е. теге <Seq>. Это устройство соответствует стандартной организации
фактов, так что можно использовать простой синтаксис запроса и,
следовательно, создание шаблона не должно вызывать затруднений.
Сначала протестируем шаблон на простом документе, не будем
добавлять его на панель инструментов сразу. Таким образом мы избежим
сложностей с контентом выпадающего меню. Поскольку шаблоны и
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<!DOCTYPE window>
<window xmlns="http://www.mozilla.org/keymaster/
gatekeeper/there.is.only.xul">
<vbox>
<description value="Static content"/>
<hbox>
<description value="Repeated content"/>
</hbox>
</vbox>
</window>
Для шаблона нам необходимы следующие моменты:
Файл
Стартовая точка запроса: ref="
Простая переменная требует повторяющегося контента:
В качестве переменной запроса с простым синтаксисом используем:
rdf:http://www.mozilla.org/notetaker-rdf#label
Объединяя эту информацию с кодом листинга 14.18, получим листинг 14.20.
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/"
type="text/css"?>
<!DOCTYPE window>
<window xmlns="http://www.mozilla.org/keymaster/
gatekeeper/there.is.only.xul">
<vbox datasources="notetaker.rdf" ref="urn:notetaker:keywords">
<description value="Static content"/>
<template>
<hbox uri="rdf:*">
<description value="Repeated content"/>
<description value="rdf:http://www.mozilla.org/
notetaker-rdf#label"/>
</hbox>
</template>
</vbox>
</window>
Контент " находится вне тега <template>, так что мы увидим его в любом случае. Контент " появится один раз для каждого решения,
найденного запросом. Третий тег description даст значение единственной
переменной, обоснованной запросом. Результаты работы шаблона показаны
на рисунке 14.6.
(рис 14.6) Контент, генерируемый шаблоном в тестовой форме.Теперь у нас есть работающий шаблон. Чтобы этого добиться, мы игнорировали некоторые мелочи; с системой шаблонов, однако, все в порядке, за исключением, может быть, нехватки отладочных инструментов.
Теперь мы можем модифицировать шаблон, встроив его в панель инструментов. В листинге 14.21 показано выпадающее меню до и после присоединения шаблона.
<?xml version="1.0"?>
<menulist editable="true">
<menupopup>
<!-- static menu items removed -->
</menupopup>
</menulist>
<menulist id="notetaker-toolbar.keywords" editable="true">
<menupopup datasources="notetaker.rdf" ref="urn:notetaker:keywords">
<template>
<menuitem uri="rdf:*" label="rdf:
http://www.mozilla.org/notetaker-rdf#label"/>
</template>
</menupopup>
</menulist>
Результаты этих изменений видны на рисунке 14.7.
Если запрос не обнаружит ключевых слов, в меню не будет ни одного
элемента, и на панели инструментов это будет выглядеть плохо. Чтобы
исправить положение, мы добавили временный тег <menuitem> перед
тегом <template>. Другой способ - сделать наверняка, чтобы в
файле notetaker.
Второй шаблон на панели инструментов должен найти единственное
решение для тега <textbox>. Чтобы представить себе, каким может
быть этот запрос, снова посмотрим на файл notetaker. ), и имеет свойство summary. Таким образом
стандартная организация фактов, требуемая для простого синтаксиса
запроса, соблюдена. Наверное, мы можем использовать простой
синтаксис.
Но на деле мы простой синтаксис использовать не можем, потому что мы привередливы - мы хотим выбирать, какие члены последовательности будут получены. Нам нужен единственный член, являющийся записью именно о текущем URL. Так что придется использовать расширенный синтаксис.
(рис 14.7) Выпадающее меню панели инструментов NoteTaker, порожденное шаблоном.В расширенном синтаксисе мы не обязаны начинать запрос с вершины последовательности, так что мы можем быть более изобретательны. Мы можем начать его прямо с URL текущей записи. Если мы так сделаем, примером запроса может быть:
<- http://saturn/test1.html, http://www.mozilla.org/ notetakerrdf#summary, ?summary ->
Используя совет, данный в настоящей лекции, в разделе "Часто встречающиеся образцы запросов", создадим шаблон следующим образом:
<box datasources="notetaker.rdf" ref="http://saturn/test1.html">
<template>
<rule>
<conditions>
<content uri="?uri"/>
<triple subject="?uri"
predicate="http://www.mozilla.org/notetaker-rdf#summary"
object="?summary"/>
</conditions>
<action>
<textbox id="notetaker-toolbar.summary" uri="?summary"
value="?summary"/>
</action>
</rule>
</template>
</box>
Этот код заменит единственный тег <textbox/>, присутствующий
на панели инструментов. Мы заключили textbox в невидимый тег <box>, чтобы привязать к нему шаблон.
Этот шаблон в качестве исходной точки запроса имеет фиксированный
URL. В недалеком будущем мы сделаем данное значение динамическим,
используя скрипт и метод setAttribute(). На этом изменения в XUL
панели инструментов NoteTaker заканчиваются. Обратимся к шаблонам
диалогового окна Edit. Оба тега этого окна, и <listbox>, и <tree>, требуют использования шаблонов.
Шаблон для тега <listbox> - более простая задача, так что
начнем с нее. Снова заглянем в файл notetaker., то есть имеет место стандартная организация фактов.
Проблема состоит в том, что URL записи - известная, фиксированная
величина, а не переменная для каждой записи в последовательности. Эта
ситуация подобна ситуации с шаблоном для <textbox> на панели
инструментов, так что используем расширенную запись запроса.
Вторая причина использовать расширенный синтаксис - необходимость
добыть текстовую строку ключевых слов. Эти строки - свойства каждого
ключевого слова, а не свойства всей записи. Мы можем легко их
получить, расширяя запрос глубже по множеству фактов - один добавочный
тег <triple> свяжет найденные ключевые слова записи с их
текстовыми значениями. Требуемый шаблон выглядит как листинг
14.23.
<listbox id="dialog.keywords" rows="3" datasources="notetaker.rdf"
ref="http://saturn/test1.html">
<template>
<rule>
<conditions>
<content uri="?uri"/>
<triple subject="?uri"
predicate="http://www.mozilla.org/
notetaker-rdf#keyword"
object="?keyword"/>
<triple subject="?keyword"
predicate="http://www.mozilla.org/
notetaker-rdf#label"
object="?text"/>
</conditions>
<action>
<listitem uri="?keyword" label="?text"/>
</action>
</rule>
</template>
</listbox>
За исключением добавочного тега <triple>, этот тот же код,
что и для <textbox>.
Мы могли бы использовать шаблон и для панели Edit в диалоговом окне Edit. Но у нас есть достаточно оснований так не поступать, так что
оставим эту панель в прежнем состоянии. Одно из этих оснований - то,
что мы не знаем, какая запись больше всего подойдет, когда загружается
данный URL.
Последний шаблон, который мы сконструируем, это шаблон дерева для связанных ключевых слов.
Снова рассмотрим файл notetaker.label для
ключевого слова. Нам также требуются связанные свойства, чтобы найти
ключевые слова, связанные с найденным. Наконец, нам нужно, чтобы
началом ( level 0 ) дерева были ключевые слова для записи текущего URL.
Мы используем этот URL как вершину запроса, но высветим лишь дочерние
решения данного URL, но не сам URL.
Для полного
<- current-page-url, keyword, ?keyword -> // level 0 <- ?keyword, label, ?text -> <- ?keyword, related, ?keyword2 -> <- ?keyword2, label, ?text2 -> // level 1 <- ?keyword2, related, ?keyword3 -> // level 2 <- ?keyword3, label, ?text3 -> ... и так далее ...
Такое множество фактов не отвечает стандартной организации, так что
требуется расширенный синтаксис. Это множество фактов является
рекурсивным запросом, так что нам действительно нужен именно тег <tree>.
Каким будет запрос? Зададим вопрос более точно: что необходимо
получить запросу, чтобы продвинуться на один уровень глубже по дереву
решений? На каждом уровне есть два факта, поэтому кажется, что
(рис 14.8) Диаграмма RDF для рекурсивного запроса шаблона.Ясно, что рекурсивность требует одного шага вглубь дерева вдоль вертикальной стрелочки. Так что запрос является запросом единственного факта. А другая стрелочка раскрывает информацию, требуемую на каждом уровне, но не участвующую в рекурсии.
Сначала рассмотрим факты, порождающие рекурсию, и расположенные
вдоль вертикальных стрелок. Проблема в том, что иногда они содержат
ключевые слова, а иногда - связанные ключевые слова. Другими словами,
для
<- current-page-url, keyword, ?keyword -> <- current-keyword-urn, related, ?keyword ->
Каким-то образом запрос шаблона должен учесть оба случая. Один
способ - использовать отдельные правила <rule> для каждой
возможности. В нашем случае, однако, хорошее решение - атрибут шаблона containment. К счастью, при любом , либо со свойством related, но не с обоими сразу. А это
значит, что мы можем использовать несколько предикатов container
вместе. Мы перечислим и предикат related, и предикат в
значении этого атрибута.
Чтобы понять, почему мы можем использовать containment, рассмотрим
работу запроса. Когда запрос открывает верхний уровень дерева,
предикат найдет решения, а предикат related - нет, потому что
так в related найдет решения, а предикат
- нет. Это в точности то, что нам нужно. Полученный в результате
шаблон приведен в листинге 14.24.
<tree id="dialog.related" flex="1"
datasources="notetaker.rdf"
ref="http://saturn/test2.html"
containment="http://www.mozilla.org/notetaker-rdf#related http://
www.mozilla.org/notetaker-rdf#keyword" hidecolumnpicker="true"
>
<treecols>
<treecol id="tree.all" hideheader="true"
primary="true"
flex="1"/>
</treecols>
<template>
<rule>
<conditions>
<content uri="?uri"/>
<member container="?uri"
hild="?keyword"/>
</conditions>
<action>
<treechildren>
<treeitem uri="?keyword">
<treerow>
<treecell label="?keyword"/>
</treerow>
</treeitem>
</treechildren>
</action>
</rule>
</template>
</tree>
Запрос содержит тег <, чтобы проверять соответствие
атрибуту containment. Поскольку это <description>. Мы обязаны
использовать один из тегов, явным образом поддерживающий рекурсивные
запросы, в данном случае для <tree>.
Теперь шаблон готов, нужно лишь добавить поиск дополнительной
информации, как показано на рисунке 14.8. Это можно сделать, используя
тег <. Добавим следующий код сразу после тега
</conditions>: <bindings> <binding subject="?keyword" predicate="http://www.mozilla.org/notetaker-rdf#label" object="?text"/> </bindings>
Поскольку теги < не сказываются на рекурсивном
процессе, запрос мы этим не повредим, а лишь уточним им обнаруживаемую
информацию. Наконец, нужно изменить тег <treecell>, чтобы
вывести label, обнаруживаемый тегом <, а не :
<treecell label="?text"/>
На этом создание всех шаблонов завершено. Хотя теги <listbox>
и <tree> имеют контент, порожденный шаблоном, обработчики
событий, созданные нами в лекции 13, "Списки и деревья",
продолжают нормально работать. Они обслуживают DOM структуру
порожденного шаблоном контента так же легко, как и статические теги
XUL.
С шаблоном <tree> у нас возникает одна проблема. Наш шаблон
не обнаруживает связанные ключевые слова так, как это делал
экспериментальный снимок шаблона в лекции 13, "Списки и
деревья". Он обнаруживает лишь то, что есть в в файл
notetaker.
Наконец, нам нужно реализовать обновление данных, построенных
шаблоном. Это означает необходимость связать данные на панели
инструментов, в диалоговом окне Edit и HTML-записи с
<textbox> на панели инструментов каждый раз, когда изменяется текущая запись.Keywords диалогового окна при его открытии.Чтобы этого добиться, внесем следующие небольшие изменения на панели инструментов:
<textbox> на панели инструментов.delete на панели инструментов нужна команда notetaker-delete.save на панели инструментов нужна команда notetaker-sav e.notetaker-open-dialog должна обновлять выпадающее меню на панели инструментов, когда закрывается диалоговое окно.Во-первых, мы должны реализовать объект note на JavaScript и его
методы clear() и и свойство url. Метод clear() уничтожает
все данные текущей записи, преобразует данный URL в URL
существующей записи и сохраняет результат. В данной лекции эти
изменения будут тривиальны, но мы уточним их позже. Код нового объекта note приведен в листинге 14.25.
function Note() {} // constructor
Note.prototype = {
url : null,
summary : "",
details : "",
chop_query : true,
home_page : false,
width : 100,
height : 90,
top : 80,
left : 70,
clear : function () {
this.url = null;
},
resolve : function (url){
this.url = url;
},
}
var note = new Note();
Во-вторых, реализуем функцию refresh_toolbar(), обновляющую
шаблоны панели инструментов. Некоторые из этих функций нам придется
усовершенствовать в следующих лекциях. Функция приведена в листинге
14.26.
function refresh_toolbar() {
var menu = window.document.getElementById
('notetaker-toolbar.keywords');
menu.firstChild.builder.rebuild();
var box = window.document.getElementById
('notetaker-toolbar.summary');
box.parentNode.setAttribute('ref', note.url);
box.parentNode.builder.rebuild();
}
Метод автоматически удалит и пересоздаст контент шаблона.
В случае выпадающего меню контент изменится, только если изменится
исходный <textbox> модифицируется сам шаблон,
поэтому запрос каждый раз разный.
Наконец, посмотрим на регулярные проверки. Они вызываются из
функции content_poll(), так что поправим ее так, чтобы обновлялась не
только высвеченная запись, но и панель инструментов.
function content_poll() {
var doc;
try {
if ( !window.content ) throw('fail');
doc = window.content.document;
if ( !doc ) throw('fail');
if ( doc.getElementsByTagName("body").length == 0 )
throw('fail');
if ( doc.location.href == "about:blank" )
throw('fail'); }
catch (e) {
note.clear(); refresh_toolbar(); return;
}
if ( doc.visited )
return;
note.resolve(doc.location.href);
display_note();
refresh_toolbar();
doc.visited = true;
}
Если подходящего URL не существует, текущая запись и панель инструментов очищаются. В противном случае ищется новая текущая запись и обновляются панель инструментов, запись и текущая страница.
Мы еще не выполнили пункты 4 и 6, потому что пока не знаем, как
модифицировать action() так, чтобы она вызывала refresh_toolbar() каждый раз, когда это необходимо. Листинг 14.28
показывает этот простой код.
function action(task) {
if ( task == "notetaker-open-dialog" ) {
window.openDialog("editDialog.xul","_blank","modal=yes");
refresh_toolbar();
}
if ( task == "notetaker-display" ) {
display_note();
}
if ( task == "notetaker-save" ) {
refresh_toolbar();
}
if ( task == "notetaker-delete" ) {
refresh_toolbar();
}
}
На этом управление шаблонами завершено. Для диалогового окна нам
нужно сделать то же самое для шаблонов панели . Мы выполним
эту задачу в команде notetaker-load. В функции action(), обслуживающей
команду, добавим вызов refresh_dialog() и реализуем refresh_dialog()
как показано в листинге 14.29.
function refresh_dialog() {
var listbox = window.document.getElementById('dialog.keywords');
listbox.setAttribute('ref', window.opener.note.url);
listbox.builder.rebuild();
var tree = window.document.getElementById('dialog.keywords');
tree.setAttribute('ref', window.opener.note.url);
tree.builder.rebuild();
}
Этот код идентичен коду обновления шаблона на панели инструментов выпадающего меню.
Если шаблоны созданы и используются корректно, все работает. В работе шаблонов практически нет отклонений, способных вызвать сбой. Большинство ошибок - следствие синтаксических ошибок кода.
Работая на платформе Microsoft Windows, удостоверьтесь, что Mozilla
полностью завершила работу и выгружена из памяти после закрытия
последнего окна. Если используется неверно сформированный шаблон,
процесс может застрять в памяти и повлиять на последующие пробы. Если
такое случается - самый общий симптом состоит в том, что кажется,
будто изменения, вносимые в код XUL или JavaScript, не дают ожидаемого
эффекта. Безопаснее всего перестартовывать платформу каждый раз
заново. Если вы не отключили
Вторая <menu> и <tree>, остальные ведут себя
непредсказуемо и могут вызвать падение платформы.
Комбинация <tree>, описанное в лекции 13,
"Списки и деревья". Если хоть мельчайшая деталь некорректна,
шаблон не даст вовсе никакого результата, и не будет и намека, почему
так произошло. Очень важно все делать правильно с самого начала.
Создавая шаблон, всегда начинайте с тестовых данных во внешнем
Создав корректные данные, удостоверьтесь, что результат можно видеть в окне XUL.
Если шаблон не рекурсивен, создайте шаблон с базовым тегом <. Выведите что-нибудь в тег <description> или <label> без лишних "красивостей" в правилах. Как
только что-то осмысленное появится на экране, вы получаете по крайней
мере корень запроса и часть его правильной структуры. Даже если ваша
цель - сложный тег "дерево" со многими уровнями вложения,
начинайте сначала с <.
Если ваш источник данных - внутренний, прочитайте советы в лекции 16, "Объекты XPCOM", и извлеките максимум информации из данных на тестовую страницу. Некоторыми источниками данных можно управлять прямо из шаблона, остальные требуют скриптов. Нужно хорошо изучить порождаемый контент, иначе запрос шаблона не сработает.
Наконец, стройте запрос. Система запросов гибка, и может обработать
некоторые вариации контента внутри тега <template>, но вносить
их все же не рекомендуется. Чтобы избежать лишних хлопот, следуйте как
можно ближе к порядку тегов, приведенному в данной лекции. Хотя от него
и можно отступать, это может привести к некорректному преобразованию
шаблона и его переменных во внутреннюю форму. Тут перемена мест на
результат влияет, и еще как.
Если шаблон рекурсивен, вы не можете тестировать рекурсию без тегов <menu> или <tree>, но лишь первый уровень рекурсии. Чтобы
тестировать дальнейшие уровни, используйте <tree>, а не <menu>. Невозможно построить рекурсивно порожденное множество
меню единственным правилом <rule> - требуется, по крайней мере,
два.
Одно правило необходимо для элементов <menu>, другое - для
элементов <menuitem>. Так что для тестирования рекурсивных
запросов дерево - самый подходящий и простой механизм.
Только после того, как тестовый запрос даст ожидаемый результат,
начинайте работу с реальным виджетом. В случае дерева начинайте с
кода, приведенного в данной лекции, и обязательно следите за тем, чтобы
дерево имело первичную колонку. Необходимые детали можно добавить
позже. Внимательно просмотрите флаги и опции, которые можно добавить к
базовому тегу, некоторые из них жизненно важны. Автоматически добавьте flags="dont-build-content" и , если только
вы не знаете точно, что они не нужны.
Когда ваш шаблон заработает правильно, можно добавить скрипты его динамического поведения. Раздел 14.6.1, "Советы по созданию динамических шаблонов" содержит действительно важные советы. За пределами, описанными в этом разделе, поддерживается не слишком многое.
Наконец, обратите внимание на раздел "Источники данных"
лекции 16, "Объекты XPCOM". Если ваш источник данных
Система шаблонов Mozilla обрабатывает
Система сложна для изучения. Она использует новаторские концепции и массу подводных камней, и выдает слишком мало отладочной информации в процессе создания шаблона. Разнородные источники данных требуют каждый индивидуального подхода и усилий по их изучению, что также не упрощает работу.
Несмотря на проблемы первой версии платформы, шаблоны являются
очень мощным инструментом.
Для порождения и управления новым контентом XUL документа могут
быть использованы JavaScript и DOM.
В этой лекции рассказывается о том, как определить контент XUL
документа, используя поток
Система шаблонов Mozilla - это подмножество XUL тегов. Эти теги используются, чтобы создать документ, содержание которого не определено. Исходный документ служит основой для представления меняющихся со временем данных, либо в результате воздействия пользователя, либо в результате изменения самих исходных данных. Это также основа для создания приложений, чей графический интерфейс зависит от внешней информации. Внешняя информация может быть проста, как файл, или сложна, как база данных, и находиться где угодно в сети. В любом случае, вид такого документа меняется в зависимости от ситуации.
Система шаблонов позволяет создавать многие виды приложений. Когда информация в шаблоне меняется согласно показаниям датчиков, документ ведет себя как телеметрическое приложение, например центр управления сетью или система контроля состояния окружающей среды. Когда информация изменяется конечным пользователем, документ превращается в приложение для работы с данными. В частности, система шаблонов соответствует приложениям для исследования данных, таких как категориальный анализ и анализ бизнес-процессов, системам контент- и документ-менеджмента, визуализации сетевых схем. Ее можно использовать и для обычных систем ввода данных.
При традиционной web-разработке динамически изменяемый документ
HTML может быть сконструирован двумя способами. HTML может
генерироваться на стороне web-сервера (чем-то вроде CGI-программы),
или HTML на стороне клиента может иметь многочисленные скрипты
(динамический HTML). В любом случае, мы должны работать с кодом
третьего поколения (
Система шаблонов Mozilla не требует
Контент File | . Это дерево
описывает текущие открытые окна.
Понимание системы шаблонов означает понимание системы правил
шаблонов. Последовательность правил может быть простой или сложной. В
самом простом случае правила лишь подразумеваются и не выражены явно.
В сложных случаях правила подобны или запросу к базе данных или
оператору switch в языке JavaScript. В обоих случаях приходится
использовать специальные переменные шаблонов.
Как и во многих других случаях XUL, система шаблонов начинается с простого и ясного синтаксиса:
<template> <rule> ... </rule> <rule> ... </rule> </template>
Шаблоны так же сложны, как и деревья, и простой базовый синтаксис скоро усложнится, поскольку есть множество подробностей.
Шаблоны не имеют собственного содержания: нет никаких блокоподобных
тегов шаблонов. Теги шаблонов больше похожи на макро-инструкции и
оператор # препроцессора языка C. Эти теги всегда используются
внутри других XUL тегов; они не могут быть тегами верхнего уровня,
наподобие тега <window>.
На схеме в начале этой лекции показана область, затрагиваемая
системой шаблонов в платформе. Из нее видно, что шаблоны - маленькая,
компактная система, отделенная от остальной платформы Mozilla. Их
работа - последний этап в процессе формирования документа при его
загрузке. Шаблоны никак не затрагивают систему отображения XUL
контента. Поскольку шаблоны работают в паре с
Листинг 14.1 XUL-документ, содержащий простейший шаблон, выводящий "hello, world" один или несколько раз.
<?xml version="1.0"?> <window xmlns="http://www.mozilla.org/keymaster/ gatekeeper/there.is.only.xul"> <vbox datasources="test.rdf" ref="urn:test:seqroot"> <template> <label uri="rdf:*" value="Content: rdf:http://www.example.org/Test#Data"/> </template> </vbox> </window>
Как видно из листинга, система шаблонов состоит из собственных
тегов, подобных тегу <template>, и специальных атрибутов для
других тегов, таких, как атрибут ref.
Mozilla предоставляет несколько типов синтаксиса правил, образующих
систему запросов в шаблонах. В данном примере использовался простейший
синтаксис: только одно правило, причем подразумеваемое. Оно гласит:
обработать все сообщения конкретного контейнера , а контент, представляющий сообщения, определяется
тегом <label>. Обратите внимание, что и внутри, и снаружи тега
шаблона <template> могут быть теги обычного типа, не относящиеся
к системе шаблонов.
В листинге 14.2 приведен
<?xml version="1.0"?>
<RDF xmlns:Test="http://www.example.org/Test#"
xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
<Description about="http://www.example.org/">
<Test:Container>
<Seq about="urn:test:seqroot">
<li resource="urn:test:welcome"/>
<li resource="urn:test:message"/>
</Seq>
</Test:Container>
<Description about="urn:test:welcome" Test:Data="hello, world"/>
<Description about="urn:test:message" Test:Data="This is a test"/>
</RDF>
Данный файл <Seq>,
имя ресурса которого использовалось в коде XUL-шаблона в листинге
14.1. Это унифицированное имя ресурса (Test - пространство имен xmlns. Data и Container -
специальные свойства (предикаты) имен в этом пространстве имен. Имена
Data также присутствует в теге <label> листинга 14.1, где оно указано со своим полным URL.
Если сохранить эти два листинга в файлы и загрузить первый, то мы увидим картинку, приведенную на рисунке 14.1. Диагностические стили включены, чтобы выявить структуру окна, полученного в результате.
На рисунке видно, что в финальном XUL были сгенерированы два тега <label>. Значения каждого тега определяются и фиксированным
значением ("Content: "), и строкой, определяемой одним из
двух фактов <Description> в документе , напротив,
появляется лишь один раз. Структуру финального документа можно
исследовать с помощью приложения DOM Inspector. На рисунке 14.2
приведен вид DOM Inspector, соответствующий рисунку 14.1.

(рис 14.2) XUL-документ, созданный по шаблону и двум фактам.(рис 14.1) Тот же документ в DOM Inspector.На снимке видно, что система шаблонов добавила два тега в финальный
документ, по одному на каждый факт в файле <label> - метка из исходного файла шаблона, другие два тега <label> - контент, сгенерированный шаблоном. Таким образом,
финальный документ содержит два поддерева - одно для спецификации
шаблона, а другое для сгенерированного контента. Поддерево,
начинающееся тегом <template>, никак не отражается на внешнем
виде документа. Когда система шаблонов генерирует теги для другого
поддерева, она присваивает им
XUL этого шаблона можно сделать гораздо сложнее, используя свойства системы правил шаблонов.
Перед тем, как углубиться в синтаксис XUL системы шаблонов, нам
следует отступить далеко назад, чтобы увидеть, что все это означает с
точки зрения фактов. В конце концов, шаблону для работы нужен
Система шаблонов Mozilla затрагивает все стандартные отличительные
черты приложений Mozilla: XUL, JavaScript и
Система шаблонов XUL - это система запросов. Она осуществляет поиск
в массиве данных и возвращает элементы массива, соответствующие
Запросы, выполняемые XUL-шаблоном, часто описываются как система
сравнивания с образцом. В самом общем смысле слова
"образец", принятого в
Шаблоны XUL не являются фильтрами и не выполняют сравнение с
образцом в этом каждодневном смысле слова. Если документ
В отличие от простой фильтрации, запросы в шаблонах выполняют унификацию. Унификация имеет место тогда, когда множество элементов данных комбинируется в конечный результат. Пример из реальной жизни - собирание паззла. Когда все кусочки паззла собраны вместе, решение найдено (получена картинка). Если дано больше элементов, чем нам понадобилось (предположим, было перемешано несколько наборов паззлов), часть элементов будут отброшены, как незначащие. Унификация может дать больше, чем один результат. Если элементов головоломки достаточно, можно собрать несколько картинок. Если элементы имеют подходящую форму, то несколько результатов может быть получено даже из одного набора.
В Mozilla элементы головоломки это подлежащие, сказуемые и
дополнения набора
Это кажется знакомым. Инструкция SELECT в SQL ведет себя точно так
же, когда выполняет запрос join - то есть выбирает данные из двух или
более таблиц. Данные в полученных колонках не соответствуют данным ни
в одной из исходных строк, они соответствуют информации в строках
разных таблиц. Этим способом может быть обнаружено более одной
строки.
Фактически, запросы XUL-шаблонов являются примерами реляционных
вычислений, так же как
Синтаксис шаблонов XUL необычен и лучше начинать не с него. Чтобы
разобраться в структуре запросов шаблонов, давайте вернемся к примеру
с мальчиком, собакой и мячиком из лекции 11, "
Вспомним, что этот пример использовался для описания
"чистой" системы сообщений, без
<- 1, is-named, Tom -> <- 1, owner, 2 -> <- 1, plays-with, 5 -> <- 2, is-named, Spot -> <- 2, owned-by, 1 -> <- 2, plays-with, 5 -> <- 5, type-of, tennis -> <- 5, color-of, green ->
Эта информация моделирует сообщение "Том и его собака
В лекции 11, "
<- 1, owner, ??? ->
Поскольку дополнение (объект) в этом триплете неизвестно, это не основной факт. Его нельзя использовать как данные, но можно - как стартовую точку для запроса о других фактах. Используем переменную для неизвестной части. Переменная начинается с символа вопросительного знака, точно как переменные в DOS начинаются и заканчиваются знаком '%', а переменные в оболочке UNIX начинаются со знака '$'. Переменная не может быть в основном состоянии, иначе она не переменная, а литерал. Будем называть процесс перевода переменной с неизвестным значением в переменную с известным - обоснованием переменной.
<- 1, owner, ?dogId ->
При выполнении запроса унификация означает, что все переменные из множества доступных фактов будут преобразованы в литералы. Причудливым образом можно сказать так: "Обоснуй-ка мне все переменные, пожалуйста". Для нашего простого примера данному перегруженному переменными запросу отвечает второй факт из листинга 14.3.
<- 1, owner, 2 ->
Переменная ?dogId не имеет значения, и если значение 2 заменит ее,
будет получен факт, соответствующий существующему факту. Таким
образом, переменная ?dogId может быть обоснована значением 2. Это
тривиальный пример запроса, возвращающего один результирующий факт.
Предположим, у Тома есть вторая собака, по кличке Фидо. Значит, есть
дополнительный факт:
<- 1, owner, 3 -> <- 3, is-named, Fido ->
Если факт, содержащий переменную ?dogId, снова использовать как
запрос, ему будут соответствовать уже два факта:
<- 1, owner, 2 -> <- 1, owner, 3 ->
?dogId может быть обоснована либо значением 2, либо 3, так что
теперь есть два решения. Мы можем говорить, что результирующее
множество содержит два факта, две строки, или два элемента.
Предшествующий факт, используемый как запрос, также может быть расширен. Его можно указать так:
<- ?personId, owner, ?dogId ->
В этом случае соответствие требует комбинации значений,
удовлетворяющих обеим переменным одновременно (обосновывается и ?personId, и ?dogId ). Если мы используем существующие факты,
результирующее множество также будет иметь две строки: ( ?personId
обосновывается 1 и ?dogId обосновывается 2) даст один факт, а
( ?personId обосновывается 1 и ?dogId обосновывается 3) даст
второй. Увеличение количества переменных не всегда означает увеличение
количества результирующих фактов. Это лишь означает, что нужно найти
соответствие большему количеству предметов.
Предположим, что Джейн (чей person id = 4) также владеет Фидо, но не Спотом. Фидо, таким образом, принадлежит двум хозяевам, но Спотом владеет только Том. В списке фактов добавятся два новых:
<- 4, is-named, Jane -> <- 4, owner, 3 ->
Если последний запрос выполнить вновь, мы получим три результата:
?personId обосновывается 1 (Tom) and ?dogId обосновывается 2 (Spot) ?personId обосновывается 1 (Tom) and ?dogId обосновывается 3 (Fido) ?personId обосновывается 4 (Jane) and ?dogId обосновывается 3 (Fido)
Хотя ?personI может иметь значение 4 (Джейн), а ?dogId - 2 (
Наконец, заметим, что информация, которую нужно обосновать в
последнем простом запросе, имеет иную нотацию. Она может быть записана
как набор неизвестных, которые нужно найти. Этот набор можно записать
как
<- ?personId, ?dogId ->
Этот INTO в SQL запросе SELECT. Если кто-то другой писал запрос,
такая информация - все, что вам нужно, чтобы понять полученный
результат.
В последнем примере три строки соответствуют этому
<- 1, 2 -> <- 1, 3 -> <- 4, 3 ->
Если процессору запросов не дать достаточно информации, он не будет знать, что ему делать. Недостаточно сказать, "компьютер, умница, найди-ка мне эти переменные". Запрос должен указать процессору, на что смотреть. В случае простого запроса предписание может быть очень простое: "комп, тупица, просмотри-ка все триплеты данных и найди все, соответствующие этому триплету-запросу".
Система шаблонов Mozilla поддерживает простые (single-
Слегка заглядывая вперед, скажем, что в запросе о единичном факте
тег < должен быть записан одним из двух способов.
Если искомый факт содержится в , и так далее, то в теге < должны содержаться <content> и <. Если же искомый факт содержит хорошо
известные предикаты, < должен содержать теги <content> и <triple>. Простые запросы шаблонов обсуждаются
далее в разделе "Распространенные образцы запросов".
Система XUL шаблонов поддерживает комплексные (multifact) запросы.
Комплексные запросы напоминают SQL запрос join и также напоминают
навигацию по древообразной структуре данных.
Комплексные запросы - это вопросы, требующие для ответа, чтобы два
или более реальных факта были скомбинированы. Другими словами,
требуется некая
Используя пример о мальчике и собаке, предположим, что нужно задать запрос: "Как зовут собаку, которой владеет Том"?
<- ?personId, is-named, Tom -> <- ?personId, owner, ?dogId -> <- ?dogId, is-named, ?dogName ->
Формулирование комплексных запросов требует некоторой практики. Это
тот же вид практики, который требуется, чтобы освоить SQL запросы join
для нескольких таблиц или регулярные выражения с несколькими
переменными. Ключевая проблема состоит в том, что запрос приходится
писать сразу, усилием воли, с чистого листа.
Данный запрос был построен следующим образом. Сначала было
установлено уже нам известное ("Том"). Затем мы определили
то, что нам не известно, но мы хотим узнать: dogName. Мы просмотрели
доступные нам кортежи, чтобы узнать, каким из них могут
соответствовать известные и неизвестные нам элементы. Это дало нам два
is-named
используется в обоих personId и dogId. Мы добавили их в список неизвестных. Мы заметили,
что эти два personId и dogId. Итак, мы получаем список
кортежей, где все неизвестные присутствуют, и все они соединены, так
что этот список образует единый запрос.
Если эти три факта, как единый запрос, направить в процессор
запросов, то, чтобы решение нашлось, все неизвестные должны быть
обоснованы одновременно. Поскольку каждая из переменных ?personId и ?dogId присутствует в двух
<- 1, is-named, Tom -> <- 1, owner, 2 -> <- 2, is-named, Spot ->
Сравните эти три факта с запросом. Решение ставит в соответствие неизвестным переменным
<- ?personId, ?dogId, ?dogName ->
единственную возможность:
<- 1, 2, Spot ->
Как процессор запросов в Mozilla ищет решение? Существует много возможных техник. Простейшая - перебирать все комбинации из трех реальных фактов и сравнивать каждую комбинацию с запросом. Это решение проблемы "грубой силой", оно очень неэффективно. Так в Mozilla не делается. Mozilla использует более тонкий метод, заключающийся в исследовании части графа структуры фактов. Скоро мы сможем в этом убедиться.
Если снова поместить в список исходных фактов Фидо и Джейн, тот же самый запрос даст два решения:
<- 1, is-named, Tom -> <- 1, owner, 2 -> <- 2, is-named, Spot -> <- 1, is-named, Tom -> <- 1, owner, 3 -> <- 3, is-named, Fido ->
Здесь значения, обосновывающие неизвестные переменные, следующие:
<- 1, 2, Spot -> <- 1, 3, Fido ->
Обратите внимание, как конструируется запрос для сравнения с
фактами списка. Подлежащие и дополнения соответствуют переменным,
таким как ?personId. Результат, напротив, просто набор обоснованных
переменных в
Этот пример эквивалентен SQL запросу join из трех таблиц. Листинг
14.4 показывает воображаемый SELECT запрос, выполняющий ту же работу,
что и наш последний запрос. Каждая из трех воображаемых таблиц
соответствуют одному факту из нашего списка.
SELECT p.personId, d.dogId, d.dogName FROM persons p, owners o, dogs d WHERE p.personName = "Tom" AND p.personId = o.personId AND o.dogId = d.dogId
Точно как join в personId в двух типах запросов, и вы увидите
подобие, несмотря на абсолютно разный синтаксис.
В общем случае этот пример демонстрирует, как большой массив фактов
может быть исследован с помощью правильно сконструированных запросов,
содержащих переменные. Если массив фактов - это
Система шаблонов поддерживает комплексные шаблоны двумя способами.
Простой синтаксис шаблона автоматически выполняет запрос по двум
фактам, при условии, что <content>, любое количество
тегов < и <triple>, и любое количество тегов <. Каждый из этих тегов (за исключением тега <content> ) представляет в запросе один факт.
В лекции 11, "<Seq>. Mozilla использует комбинацию
С точки зрения прикладного программиста, Mozilla использует
"бурящий" (
Когда начальная точка выбрана, процессор запроса Mozilla двигается
из нее по графу
Систему запросов можно проиллюстрировать
На рисунке 14.3 все факты принадлежат списку фактов. Иллюстрируемый
запрос состоит из двух фактов (two-
(рис 14.3) Уточненный граф "мальчик и собака" и путь запроса.Мы можем поэкспериментировать немного с этим примером.
(рис 14.4) На Рисунке 14.4 показан другой запрос на том же графе.
Снова мы имеем запрос из двух фактов, но на этот раз он начинается с идентификатора Спота (2). Снова три решения. Заметим, что путь 2-1- Том не является решением. Потому что стрелка указывает в противоположную сторону. Вовсе не 2 - подлежащее факта, и 1 - дополнение, а наоборот. Запрос не может двигаться в обратном порядке. Но даже для возможных решений наш второй запрос все же вряд ли имеет смысл. Слишком разные обнаруживаются предикаты на этих путях. Если все же нужно найти в этом запросе смысл, лучше предположить, что либо реальные данные плохо описываются фактами, либо запрос был недостаточно хорошо продуман.
Минус этой системы в том, что не все факты из исходного списка
просматриваются. Теоретически, система может пропустить некоторые
решения. Но ее достоинство - скорость. На практике, если
Этот "сверлящий" алгоритм - приближение. В реальности система шаблонов работает сложнее. Однако это достаточно хорошее приближение и рекомендуемая интерпретация способа работы системы шаблонов XUL.
Способ организации <Seq>, < или <Alt>.
Известная стартовая точка - либо
Листинги 14.5 и 14.6
показывают фрагмент
<Description about="http://www.example.org/"> <NS:Owns> <Bag about="urn:test:seq"> <li resource="urn:test:seq:fido"/> <li resource="urn:test:seq:spot"/> <li resource="urn:test:seq:cerebus"/> </Bag> </NS:Owns> </Description> <Description about="urn:test:seq:fido" NS:Tails="0"/> <Description about="urn:test:seq:spot" NS:Heads="1"/> <Description about="urn:test:seq:cerberus" NS:Heads="3"/>
NS в листинге 14.5 означает некоторое пространство имен,
предположительно, объявленное в коде где-то ранее. Пространство имен
должно иметь NS для идентификации экземпляров фактов,
эквивалентных применяемым в листинге 14.5. Использование NS в
листинге 14.6 не имеет никакого конкретного смысла, поскольку факты в этом
листинге не являются ни XML, ни кодом вообще.
<- http://www.example.org/, NS:Owns, ?bag -> <- ?bag, ?index, ?item -> <- ?item, NS:Heads, ?heads ->
В запросе первый обосновываемый факт спускается ( ( - неупорядоченное < ).
Второй обосновываемый факт спускается далее до элементов множества
(множество из трех элементов <li resource= ...). Третий факт спускается до фактов о количестве голов у
каждого элемента (в результате ноль или один ответ на каждую строку
запроса, в зависимости от наличия головы у элемента множества (Фидо -
ноль хвостов,
<- ?bag, ?index, ?item, ?heads ->
а два найденных решения так:
<- urn:test:seq, rdf:_2, urn:test:seq:spot, 1 -> <- urn:test:seq, rdf:_3, urn:test:seq:cerberus, 3 ->
Вспомним, что ,каждому потомку в контейнере. Первый NS: вместо NS:Heads.
Поддержка такого типа запросов - первоочередной приоритет системы запросов Mozilla. Это самый надежный и плодотворный способ работы с системой шаблонов.
В предыдущем примере переменная ?index использовалась для описания
предиката факта. Система запросов Mozilla не может использовать
переменную в запросе для предиката, но она имеет тег <,
который достигает почти той же цели (с некоторыми ограничениями).
Итак, набор фактов запроса обнаруживает подходящие записи в
аккуратно упорядоченной коллекции и строит
Запросы XUL шаблона живут столько же, сколько и содержащий их документ. Они не запускаются однажды, а затем отбрасываются. Они используются, пока не закроется их отображающее окно.
Список
Когда данные изменяются, каждый запрос шаблона также меняет свое мнение о том, какие существуют решения этого запроса. Если новые решения возможны, они будут добавлены ко множеству решений. Если некоторые решения стали невозможны, они будут удалены. Возможны и изменения в ранее найденных решениях.
Ближайшее следствие этого - то, что множество решений может со
временем изменяться. Шаблонный запрос - не всегда "событие
согласованного чтения" (если использовать жаргон
Живой отклик запроса требует от прикладного программиста некоторой активности. Ведь запрос должен непрестанно сверяться со списком фактов, чтобы решения были актуальны. Чтобы это делалось эффективно, и только тогда, когда нужно, должны быть написаны определенные скрипты.
XUL документы используют шаблонные запросы повсеместно.
Бурящую стратегию шаблонных запросов Mozilla можно применять
рекурсивно. Каждую конечную точку бурения можно использовать как
следующую начальную точку для того же самого запроса. Это позволяет
запросу продвигаться глубже по
Рекурсивное использование запросов очень плодотворно на
древообразных структурах данных. Такие структуры могут иметь
произвольную глубину, что соответствует произвольному числу связей в
В XUL документе шаблонные запросы внутри тега <tree> выполняют и добавочную работу.
Система запросов Mozilla позволяет объединить несколько запросов в список.
Когда начинается обработка запросов, все запросы списка обрабатываются одновременно. Любое решение, удовлетворяющее сразу нескольким запросам, будет поставлено в соответствие лишь одному. А именно - ближайшему к началу списка.
Метод, которым это достигается, прост: на каждом шагу вниз по
Такая система позволяет оценить ряд фактов одним набором критериев
(одним запросом), а если решение найти не удалось, вновь оценить
другим набором критериев (другим запросом). Это очень похоже на
булевские условные выражения if ... else if.
Списки запросов в Mozilla позволяют порождать несколько различных подмножеств одного множества фактов. Каждый запрос порождает одно такое множество решений.
На этом мы закончим рассмотрение запросов шаблона. После выполнения запроса нужно обработать найденные решения.
В обычном случае все, что XUL шаблон делает с полученными данными - это выводит их на экран.
Шаблон делает это, совмещая полученные данные с обычным XUL- контентом. Он действует так же, как программа для печати информации в наглядной форме, или заготовка для написания отчета, "рыба". Выводимые данные интегрируются в XUL-документ и выводятся на экран, как любой иной XUL-контент.
Если шаблон содержится в теге XUL, таком как <menupopup>, <listbox>, <, <tree> или даже <box>,
то контент тега XUL (элементы меню, кнопки панели инструментов, строки
списка или дерева) могут порождаться шаблоном. Это означает, что сами
интерактивные интерфейсы могут описываться
Проиллюстрируем процесс такого порождения простым примером. В
листинге 14.7 -
<?xml version="1.0"?>
<RDF xmlns:Test="http://www.test.com/Test#"
xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<Description about="urn:test:top">
<Test:TopSeq>
<Seq about="urn:test:seqroot">
<li resource="urn:test:message1"/>
<li resource="urn:test:message2"/>
</Seq>
</Test:TopSeq>
</Description>
<Description about="urn:test:message1" Test:Foo="foo"/>
<Description about="urn:test:message2" Test:Bar="bar"/>
</RDF>
Два свойства могут быть извлечены из этого файла и выведены на
экран с помощью шаблона. Рисунок 14.5 показывает два набора
сгенерированного XUL-контента из данного
(рис 14.5) Вывод двух шаблонов, использующих одни RDF данные.На снимке оба шаблона располагаются бок о бок. Мы видим конечный
результат процесса порождения XUL контента. Шаблон слева генерирует
теги <description> с рамками, заданными стилем. Теги находятся в
теге <. Шаблон справа генерирует теги <treeitem>,
каждый из них содержит <treerow> и <treecell>. Все они
находятся в тегах <tree> и <treechildren>. Очевидно, что
содержание, извлеченное из
В итоге можно сказать, что шаблоны объединяют данные, полученные в результате обработки запроса, с иным контентом, определяющим, как эти данные должны быть представлены.
Теги XUL, относящиеся к системе шаблонов, не отражены в конечном, видимом документе. Отображены теги, генерируемые системой. Оба типа тегов присутствуют в XUL документе одновременно, но теги шаблонов имеют такие стили, что не отображаются.
Теги шаблона формируют одно DOM поддерево XUL документа. После того, как шаблон генерирует свой контент, эти теги могут использоваться только для ссылок. Система шаблонов может перечитать такой тег, если прикладной программист добавит соответствующий скрипт.
Сгенерированные теги формируют поддерево DOM для каждого решения, найденного шаблонным запросом. Три решения дадут три поддерева. Эти поддеревья скажутся при любом обращении к ним пользователя или события, вызванного скриптом.
Каждое из сгенерированных поддеревьев имеет тег верхнего уровня.
Этот тег получит уникальный id атрибут, равный id используется как
Пример "hello, world", приводившийся в начале лекции, показывает эти поддеревья на снимке.
Шаблоны могут изменяться во время работы. Генерируемый ими контент тоже может меняться. Оба эффекта требуют применения JavaScript, и оба могут требовать очередного выполнения шаблонного запроса. Шаблоны могут и задерживать результат ("ленивое" порождение контента).
Для пересчета шаблона необходима одна строка на JavaScript. Не нужно перегружать никаких документов. Часть XUL документа, содержащая шаблон, и результат его работы изменяются "на лету". Окружающий контент не будет затронут, за исключением, возможно, оформления. Вот типичная строчка, выполняющая эту работу:
document.getElementByTagName('tree').builder.rebuild();
Теги шаблона также можно изменять, используя операции DOM 1, такие
как removeChild() и appendChild(). Однако если так сделать, выведенное
на экран содержание будет изменено при пересчете шаблона.
Если шаблон не изменит результатов запроса, выведенное на экран
содержание все равно изменится, когда изменятся
XUL документы не только задействуют шаблоны повсеместно, но и могут использовать их вновь и вновь в любое время.
Порождение контента может быть отложено. Это возможно только для
"Ленивое" вычисление работает, только если теги шаблона,
имеющие атрибут - следующие:
<menu> <menulist> <menubutton> <toolbarbutton> <button> <treeitem>
Дочерние теги этих тегов, такие как тег <menu> в <menulist> строятся "лениво".
Шаблоны, использующие <tree> или <menu>, могут
откладывать часть работы на более позднее время.
Два или большее количество шаблонов могут использовать одни и те же
Это очень мощное и полезное свойство шаблонов. Оно позволяет по-
разному взглянуть на одно и то же множество данных одновременно, и при
этом своевременно отображать изменения. Это используется, в частности,
в тех приложениях, где применяется метафора рабочего стола. Например,
в дизайнерских инструментах или Integrated
Чтобы увидеть эффект одновременного изменения контента в нескольких шаблонах, выполним следующий тест:
Менеджер Закладок содержит шаблон, основанный на теге <tree>.
Персональная Панель инструментов - на теге <. Элемент
меню "Уничтожить" запустит скрипт, который уничтожит факт,
содержащий информацию о новой закладке. Этот же скрипт предписывает
обоим шаблонам пересчитать содержание. Части контента, ассоциируемые с
этим уничтоженным фактом, ( <treeitem> в одном случае, и <toolbarbutton> в другом) исчезнут из списка найденных
результатов.
Система шаблонов добавляет объекты к AOM XUL-документа. Она
использует также несколько XPCOM компонентов и интерфейсов, в
частности,
database AOM-объекта, управляя фактами и исходными builder AOM-объекта, управляя процессом построения шаблона.<tree> - и <listbox> -образных шаблонов.Эти задачи будут описаны в разделе "Скриптинг". Они часто
требуют работы с компонентами XPCOM, поддерживающими
Последний технический аспект шаблонов - источники данных.
Данные
Шаблоны Mozilla могут извлекать факты из более чем одного источника
одновременно. Это значит, что, например, факты из более чем одного
Источники данных подробно рассматриваются в лекции 16, "Объекты XPCOM". Здесь же мы только отметим, что выбор источника данных для шаблона критичен. Если неправильно выбрать источник, вряд ли будет много толку. Необходимо знать свои источники данных.
Вот краткий обзор основных моментов. Каждый шаблон имеет
комплексный источник данных. Чтобы воздействовать на источник данных
шаблона из скрипта, зачастую необходимо найти и использовать один из
конкретных источников данных, вносящих свой вклад в результирующий
комплексный источник. Этот конкретный источник - список . Так часто
поступают, когда конструируют пользовательский снимок дерева
данных.
Раздел этой лекции, посвященный скриптам, описывает некоторые распространенные манипуляции с источниками данных. Рекомендуется изучить также лекцию 16, "Объекты XPCOM".
В данном разделе обсуждается, как шаблон собирается из составляющих
его частей, и рассматриваются конкретные теги. Общая конструкция
шаблона приведена в листинге 14.8. Это
<top>
<stuff/>
<template>
<rule> ... simple or extended rule info goes here ... </rule>
... zero or more further <rule> tags go here ...
</template>
<stuff/>
</top>
Здесь тегом, названным <top>, может быть любой обычный XUL
тег - <top> не реальный тег. Хотя собственно шаблон начинается
тегом <template>, некоторые атрибуты шаблонов могут быть
добавлены и к тегу <top>. Другой XUL-контент может
предшествовать или окружать тег <top>. Типичные кандидаты для
тега <top> - это <tree>, <, <menulist>, и <listbox>, но <top> может быть и <box> или даже <button>.
Тег, названный здесь <stuff>, тоже может быть обычным XUL
тегом, это не реальный тег. Эти теги опциональны и их может быть любое
число. Теги между <top> и <template> копируются и
генерируются лишь однажды для каждого шаблона и отображаются
графически также единожды перед содержанием шаблона.
Тег <template> - реальный XUL тег. Любой XUL-контент внутри
этого тега генерируется один раз для каждого решения, найденного
запросом. Тег <template> окружает весь контент, который должен
повторяться.
Тег <rule> - также реальный XUL-тег. Это единственный
контент, разрешенный внутри тега <template>. Может быть один или
более тегов <rule>, и предусмотрена также сокращенная запись,
позволяющая не писать ни одного. Каждый тег <rule> отвечает за
один запрос шаблона, как описывалось раньше, в разделе "Списки
запросов". Каждый тег <rule> также содержит контент. Этот
контент воспроизводится каждый раз, когда запрос находит решение.
Система шаблонов имеет несколько разных синтаксисов тега <rule>.
Наиболее гибкий и мощный - расширенный синтаксис шаблона. Этот
синтаксис требует, чтобы переменные запроса были определены в одном
месте, а применялись впоследствии в другом. Такие переменные
называются расширенными. Расширенный синтаксис требует, чтобы каждый
тег <rule> содержал ряд специальных тегов шаблона как часть его
контента.
Удобный и краткий синтаксис - простой синтаксис шаблона. Этот
синтаксис реализован для специального, но широко распространенного
случая, когда запрос обращается к контейнеру <rule>
содержал только простой XUL контент. Этот контент может содержать
простые переменные. Когда запрос шаблона находит решение, переменная
замещается найденными данными факта.
Если шаблон имеет только один тег <rule>, то простой
синтаксис имеет еще и краткую запись. Теги <rule> и </rule> можно отбросить. Краткая запись - иной способ записи
простого синтаксиса.
См. детальное описание тега <rule>.
Система XUL шаблонов имеет несколько специальных имен. Переменные
шаблонов не используются нигде, кроме как внутри тега <template>.
Расширенные переменные шаблонов Mozilla - это переменные,
используемые для простых (single
Расширенные переменные шаблона начинаются со знака вопроса ("?") и могут содержать любые символы. Регистр букв имеет значение. Они заканчиваются либо пробелом, либо знаком шляпки, или циркумфлекса ("^"), либо концом той строки, в которой они нам встретились. Пробел или шляпка не являются частью переменной. Если встречается пробел, он считается первым знаком контента, не относящимся к переменной. Если шляпка, она просто игнорируется.
Следующие имена переменных идентичны. Третий пример содержит XML сущность, означающую пробел.
"?name " "?name^" "?name #x20;"
Следующие примеры - тоже правильные имена. Мы рекомендуем, однако, всегда использовать значащие имена.
"?name_two" "?nameThree" "?name-four" "?name66" " ?66name" "?$%@$z+"
Простая запись для правил (см. тег " <rule> ") имеет
свои "переменные". Эти переменные - попросту
Простые переменные имеют формат:
rdf:URI
Такие переменные также оканчиваются пробелом (" ") либо шляпкой ("^"), либо заканчиваются вместе с содержащей их строкой. Пробел и шляпка не являются частью переменной. Пробел считается первым символом контента, не являющимся переменой, шляпка просто игнорируется.
Часть простой переменной, являющаяся
Примеры содержательных
"rdf:urn:test:example:more" "rdf:http://www.test.com/Test#Data"
И расширенные, и простые переменные используются только в значениях XUL атрибутов. Когда контент генерируется шаблоном, переменные замещаются найденными значениями.
Когда запрос находит решение, генерируется контент. Когда это
случается, имена переменных в содержащих их строках просто замещаются
их значениями. Если при этом переменная не имеет обосновывающего ее
значения (это возможно, если используется тег < ), то она
замещается строкой длины ноль.
Система шаблонов использует несколько специального вида " используется для
представления данных, генерируемых самой платформой Mozilla. Вот
список
rdf:addressdirectory rdf:bookmarks rdf:charset-menu rdf:files rdf:history rdf:httpindex rdf:internetsearch rdf:ispdefaults rdf:local-store rdf:localsearch rdf:mailnewsfolders rdf:msgaccountmanager rdf:msgfilters rdf:smtp rdf:subscribe rdf:window-mediator
Есть два специальных вида такого типа
rdf:null
означает использование источника данных, не содержащего фактов.
Такой источник данных, как правило, получит данные позднее из
JavaScript.
rdf:*
специфичная только для Mozilla запись, означающая
"соответствует любому предикату". Использование звездочки
("*") навеяно ее применением в
...
Эта запись идентична , но теперь ее не следует
использовать.
В таблице 11.3 приведены пространства имен, применяемые Mozilla для
работы с фактами
В XML часто используют атрибут xmlns, чтобы заменить длинный URL
пространства имен коротким алиасом. В системе шаблонов практически
всегда следует использовать полный URL, а не <rule>. В
этом случае
Тег верхнего уровня шаблона - родительский тег <template>. Он
называется базовым тегом шаблона. Это обычный XUL-тег, наподобие <tree> или <box>. Этот тег должен содержать часть
конфигурационной информации шаблона.
Специальные атрибуты, которые могут быть добавлены к такому тегу верхнего уровня:
datasources flags coalesceduplicatearcs allownegativeassertions xulcontentgenerated ref containment
Атрибут означает, что в шаблоне будут использоваться
.
Поскольку атрибут может иметь один или более
аргументов, он всегда является комплексным источником данных (имеющим
интерфейс nsIRDFCompositeDataSource ).
Если XUL-документ инсталлирован в . Этот
источник добавляет информацию о конфигурации
Атрибут flags используется для оптимизации выполнения шаблонного
запроса. Он применим только для
dont-build-content. Это ключевое слово относится к шаблонам
деревьев. Оно предписывает стандартному конструктору шаблона передать
ответственность по выводу на дисплей найденного контента встроенному
конструктору дерева. Конструктор шаблона по-прежнему генерирует
контент, основанный на
dont-test-empty. Это ключевое слово предписывает запросу не
обследовать контейнер, чтобы узнать, не пуст ли он. Это оптимизация,
которая позволяет не выполнять тест, который может оказаться весьма
дорогим. Она также позволяет системе шаблонов справиться с
динамическими иерархическими данными, где такой тест вообще
невозможен. Например, исследование сети может привести к такой
ситуации. В этом случае ответить на вопрос "не пусто ли множество
элементов сети?" невозможно, потому что код может ожидать, пока
придет ответ "нет" бесконечно. dont-test-empty - удачный
выбор для шаблонов, основанных на источнике данных .
coalesceduplicatearcs, allownegativeassertions, и xulcontentgenerated также несколько улучшают быстродействие и
модифицируют запрос.
Атрибут coalesceduplicatearcs, когда он указан, затрагивает факты,
которые могут быть извлечены из нескольких источников данных шаблона.
Большинство флагообразных атрибутов в Mozilla считаются
установленными, когда их значение равно true. Не так устроен этот
атрибут, его значение должно быть false. Он воздействует на то, каким
образом JavaScript обращается с фактами, а не с результатами запроса.
Если этот атрибут не установлен, идентичные данные из различных
источников данных шаблона будут обнаружены лишь единожды, а не по
одному результату на копию. Если он имеет значение false, все факты
будут обнаружены, независимо от того, дублируются они или нет. Запросы
выполняются быстрее, если этот атрибут установлен.
Атрибут allownegativeassertions, когда он установлен, также
затрагивает факты, которые могут быть извлечены из нескольких
источников данных шаблона. Большинство флагообразных атрибутов в
Mozilla считаются установленными, когда их значение равно true. Но
этот атрибут также может быть установлен в значение false. Он
воздействует на то, как JavaScript обращается с фактами, а не с
результатами запроса. Если этот атрибут не установлен, факт, который
утверждается и позитивно, и негативно, никогда не будет обнаружен,
поскольку два факта "погасят" друг друга.
Атрибут xulcontentgenerated применим к любому тегу в шаблоне, и к
любому тегу, сгенерированному шаблоном. Он приведен в данном списке
атрибутов, поскольку он также влияет на оптимизацию. Начинайте
экспериментировать с этим атрибутом только после того, как полностью
разберетесь с шаблонами. Атрибут xulcontentgenerated может иметь
значение true. Он сказывается в тот момент, когда запрос еще
выполняется, а контент генерируется. Если шаблон строится лениво, то в
каждый момент часть контента уже порождена, а часть нет. Если мы
обращаемся к тегу с какой-либо DOM операцией (наподобие добавления
дочернего тега), а тег имеет неполный, ленивый контент, может
возникнуть неясность. Куда добавить дочерний тег, если множество
дочерних тегов еще только предстоит вычислить? Mozilla решает эту
проблему, просто заставляя шаблон породить необходимый контент перед
выполнением DOM операций. Атрибут xulcontentgenerated отменяет эту
работу, чтобы ничего не пересчитывалось в данный момент в XUL дереве.
Это ускоряет DOM операции и отменяет ненужные вычисления.
Атрибут ref определяет начальную точку запроса. Он содержит полный
<Seq>, <Alt>, или < контейнера.
Атрибуты ref и containment обсуждаются в следующем разделе.
Атрибуты ref и containment можно использовать, чтобы определить
стартовую точку запроса, который не задействует официальный <Seq>, <, или <Alt>. Эти псевдоконтейнеры нуждаются в дополнительном
комментарии.
Рассмотрим обычный
<Description about="urn:eg:ownerA">
<prop1>
<Seq about="urn:eg:ContainerA">
<li>
<Description about="urn:eg:item1" prop2="blue"/>
</li>
</Seq>
</prop1>
</Description>
Предикаты в этом примере умышленно выбраны простыми. Листинг 14.9 эквивалентен трем фактам:
<- urn:eg:ownerA, prop1, urn:eg:containerA -> <- urn:eg:containerA, rdf:_1, urn:eg:item1 -> <- urn:eg:item1, prop2, blue ->
Первый факт в качестве подлежащего имеет item1 - член этого контейнера. В третьем факте записана некоторая
полезная информация о цвете данного item1. Это все обычный <Seq> листинга 14.9.
Предположим, программа имеет информацию об этих трех фактах, а не
исходный , чтобы понять,
что container A и есть ), но в этом примере достаточно
заметить .
Теперь предположим, что в эти три факта внесено единственное
изменение. Пусть предикат был заменен на (или что-
нибудь еще). Тогда три факта будут выглядеть так:
<- urn:eg:ownerA, prop1, urn:eg:containerA -> <- urn:eg:containerA, rdf:member, urn:eg:item1 -> <- urn:eg:item1, prop2, blue ->
В Листинге 14.10. показан фрагмент
<Description about="urn:eg:ownerA"> <prop1> <Description about="urn:eg:ContainerA"> <rdf:member> <Description about="urn:eg:item1" prop2="blue"/> </rdf:member> </Description> </prop1> </Description>
Есть ли по-прежнему контейнер в этих трех фактах? В конце концов,
оба случая так похожи. Можно утверждать, что контейнер действительно
существует. Во-первых, способ организации трех фактов не изменился.
Во-вторых, выбор в качестве предиката предполагает, что item1 принадлежит чему-то. В-третьих, любой запрос, построенный с
тегом <Seq>, может работать с новым предикатом точно так же, как
он работал со старым.
Суть в том, что рассматривая container, но продолжать рассматривать
Здесь нам придется снова рассмотреть атрибут ref. Он может быть
установлен в значение ", и этот ресурс
может служить начальной точкой запроса, независимо от того, выглядит
ли листинг исходного <Seq>, <, или <Alt> необязательны.
При данном гибком использовании ref есть одна хитрость. Mozilla
нужно определить, можно ли использовать данный ref ref
<Seq>, <Bag >, или <Alt> теги.Для Mozilla проверка на эти условия эквивалентна проверке на .
Если вы не хотите использовать предикаты или Folder в своих
фактах, вы не обязаны это делать. Вы можете использовать ваши
собственные предикаты. Чтобы это сделать, создайте containment к
основному тегу шаблона.
Атрибут containment может содержать список предикатов, разделенных
пробелами. Эти предикаты будут добавлены к списку тестов контейнера.
Эти предикаты будут тестироваться точно так же, как тестировались
элементы в предыдущем списке. Например, запись
containment="http://www.test.com/Test#member"
означает, что <Description> будет рассматриваться
Mozilla как контейнер, при условии, что xmlns:Test="http://www.test.com/ Test#"
было декларировано где-либо ранее:
<Description about="urn:foo:bar"> <Test:member resource="urn:foo:bar:item1"/> <Description>
Итак, запрос шаблона будет работать, даже если не существует
стандартных container. В этом случае необходимо указать
системе шаблонов, какие предикаты должны быть использованы для
реализации данного нестандартного контейнера.
Если для шаблона используется тег <tree>, применимы
добавочные атрибуты:
flex="1" statedatasource flags="dont-build-content"
Деревья не имеют значения атрибута height по умолчанию. Если шаблон <tree> не имеет атрибута , содержание шаблона
зачастую может не появиться на экране вообще. Всегда используйте
в шаблоне <tree>.
Атрибут statedatasource - устанавливается для именованного
источника данных, используемого для сохранения текущего состояния
дерева. Если пользователь откроет или закроет ряд поддеревьев на
экране, информация о том, какие поддеревья открыты, а какие закрыты,
будет сохранена в этом именованном источнике данных. В настоящее время
это используется только в
Если атрибут statedatasource не установлен, используется источник
данных, названный в атрибуте .
Значение "dont-build-content" атрибута flags также
используется только для деревьев. Оно описывается в разделе
"Основные теги".
Система шаблонов позволяет сортировать колонки данных. Это свойство реализовано для XUL меню, списков и деревьев.
Процесс сортировки использует несколько атрибутов. Они могут быть
установлены для базового тега шаблона, либо для конкретных тегов <listcol> или <treecol>. Это следующие атрибуты:
resource resource2 sortActive sortDirection sortResource sortResource2
Атрибут resource содержит переменную шаблона. Автор XUL-документа
указывает его для колонки, которая должна быть отсортирована. Этот
атрибут указывает ключ, содержащий данные, которые должны
сортироваться. Переменная шаблона, который он именует, представляет
предикат/свойство факта, дающего решение запроса для каждой строки.
Данные, используемые как ключ для сортировки, являются
дополнением/значением этого предиката. Другими словами, данный атрибут
указывает свойство, чье значение для каждой строчки должно
сортироваться.
sort - resource. Его также
применяют, чтобы указать сортируемую колонку в списке или дереве.
Используйте resource и sortActive, но не этот атрибут.
resource2 - вторичный предикат для сортирующего механизма.
Сортировка по значениям, указанным в resource, нестабильна. Это
означает, что после выполнения сортировки вторая колонка информации
может быть неупорядочена. Вторичный предикат используется, чтобы
отсортировать значения во второй колонке, если значения в первой
одинаковы. Тем не менее, третья и последующие колонки могут быть не
отсортированы.
sortActive может принимать значение true и указывать тем самым,
была ли произведена сортировка. Mozilla автоматически устанавливает
этот атрибут на нужную колонку списка или дерева. Его может указать и
программист приложения. Его можно использовать для доступа к колонке,
которая должна сортироваться, то есть его следует указывать всегда,
если не использован атрибут sort.
sortDirection может принимать значения , , или . Он может быть установлен автором XUL документа или Mozilla
автоматически после сортировки. Mozilla установит его одновременно и
на рассматриваемую колонку, и на базовый тег.
sortResource и sortResource2 - то же самое, что и resource и resource2. Эти атрибуты устанавливает Mozilla. Вторичный критерий
сортировки может быть установлен программистом с помощью JavaScript,
но не прямо в XUL.
sortSeparators может принимать значение true. Если он установлен,
закладки сортируются особенным образом. Сортировка не перемещает
элементы за границы разделителей закладок, если этот атрибут
установлен и используется источник данных .
Тег <template> содержит все детали информации о шаблоне,
которые не были указаны в базовом теге. Он содержит набор правил,
каждое из которых - пара запрос-контент. Тег <template> не имеет
собственных атрибутов. Единственный тег, который он может содержать -
тег <rule>. Зато он может содержать произвольное их число.
Если тегов <rule> нет, но есть иной контент, этот контент
считается единственным правилом с синтаксисом для простых правил.
Тег <template> может содержать простые и расширенные
правила.
Тег <rule> определяет единичный запрос шаблона и контент,
генерируемый для оформления вывода результатов запроса. Несколько
тегов <rule> формируют
Правила могут быть записаны с помощью простого и расширенного
синтаксисов. Если первый дочерний тег тега <rule> - это тег <, правило должно быть записано в расширенном
синтаксисе. В любом другом случае применим простой синтаксис. Тег <rule> может быть единственным тегом без какого-либо
контента.
Все запросы с простым синтаксисом и многие с расширенным
основываются на фактах в
Это стандартное устройство также эквивалентно
JavaScript: var container = {item1:{p1:v1,p2:v2}, item2:{p1:v1,p3:v3}}
В этой строке контейнер содержит два элемента. item1 и item2 - это
объекты, каждый из которых имеет множество свойств pN. Каждое свойство
имеет значение vN. Может быть любое число элементов, каждый с любым
числом свойств. Суть такой структуры - дать легкий доступ ко множеству
объектов и интересующим нас свойствам. Листинги 14.2,
14.5, 14.7, и
14.9 являются корректными примерами этой структуры в
<Seq about="container"> <li resource="item1"/> <li resource="item2"/> </Seq> <Description about="item1" p1="v1" p2="v2"/> <Description about="item2" p1="v1" p3="v3"/>
Чтобы сделать <Seq> обычно
заворачивают в тег <Description>, не показанный в
листинге 14.11. <Seq> может быть, кроме того, заменен на <
или <Alt>. Вместо них можно использовать тег <Description>
в роли контейнера.
Все факты, которые обрабатываются запросом с простым синтаксисом, должны иметь это стандартное устройство.
Простой синтаксис тега <rule> не имеет специальных
тегов.
Весь контент тега <rule> генерируется каждый раз, когда
запрос находит решение. Контент тега <rule> может содержать
простые переменные шаблона, помещенные в любое значение атрибута XML.
Контент генерируется так же, как для тега <action>, за
исключением двух незначительных отличий: простой синтаксис требует,
чтобы атрибут имел значение , и простой синтаксис не может
использовать тег <textnode>.
Когда применяется простой синтаксис, тег <rule> имеет
несколько специальных атрибутов:
type iscontainer isempty predicate="object" parsetype
Все эти атрибуты определяют, будет ли запрос правила успешен. Часть
запроса определяется предположением, что
Атрибут type взят из официального пространства имен
Его обычно записывают как , включая это пространство имен
ранее где-либо в документе XUL с помощью xmlns. Можно указать и с полным именем предиката, как
http:// home.netscape.com/NC-rdf#version.
Этот атрибут используется для проверки существования предиката. То
есть проверяет, существует ли в
Атрибут iscontainer может иметь значение true или false.
Значения по умолчанию нет. Он проверяет, является ли подлежащее данного факта
контейнером, используя "тесты контейнера", описанные ранее в
разделе "Атрибуты ref и containment: Тесты контейнера". Если
тесты не проходят, правило отвергает данного кандидата на решение.
Атрибут может иметь значение true или false. Значения по
умолчанию нет. Он проверяет, содержит ли данный true он проверяет, имеет ли
подобный контейнеру
Атрибут означает любую пару имен
предиката и дополнения. Поскольку имена предикатов зачастую длинны, их
сокращают, добавляя xmlns-декларацию в начале XUL документа. Если это
сделано, пара наподобие
NC:version="0.1"
проверяет, существует ли предикат version в пространстве имен NC
(вероятно, http://home.netscape.com NC-rdf#) и имеет ли он дополнение
со значением "0.1" - иными словами, имеет ли объект в контейнере
свойство version со значением "0.1". Следующие
зарезервированные имена не могут применяться для предиката, поскольку
они используются иным образом:
property instanceOf id parsetype
Эти три атрибута, плюс любое число тестов ,
могут содержаться в одном теге <rule>. Они
соединены между собой булевым AND и относятся ко всем запросам
правила. Если никакой из них не указан, то любой факт в контейнере
является решением для запроса. Если любой из них присутствует, запрос
не найдет решения, если хоть какой-то из этих атрибутов не
удовлетворяется.
Последний атрибут, parsetype, может иметь значение Integer. Если
это указано, во всех парах часть
"объект" будет интерпретироваться как целое. Любое нецелое
значение приведет к тому, что весь запрос будет проигнорирован. Если
атрибут не используется, объектные части пар интерпретируются как
строки. Система запросов не имеет встроенной математики для, например,
складывания целых. Она лишь выясняет, целое перед ней или строка.
Запрос в простом правиле обычно может быть выражен и как расширенное правило. Листинг 14.12 - пример простого синтаксиса, использующего некоторые из специальных атрибутов.
<rule iscontainer="true" isempty="false" rdf:type="http://home.netscape.com/NC-rdf#version" NC:title="History" >
Эквивалентный расширенный синтаксис приведен в листинге 14.13.
<rule>
<conditions>
<content uri="?uri"/>
<member container="?uri" child="?item"/>
<triple subject="?item
predicate="http://home.netscape.com/NC-rdf#version"
object="?version"/>
<triple subject="?item"
predicate="http://home.netscape.com/NC-rdf#title"
object="History"/>
</conditions>
Расширенный синтаксис может делать все то же, что и простой, за
исключением опций iscontainer="false" и
(значения, противоположные приведенным в примере в
листинге 14.12). Эти две опции в расширенном синтаксисе невозможны.
Расширенный синтаксис может проверить существование факта, но не его
отсутствие. Эти простые проверки все же можно осуществить в
расширенном синтаксисе, указывая два правила, а не одно. Первое
правило проверяет наличие конкретного факта, но не генерирует
контента, второе отбирает оставшиеся случаи, в которых контент
отсутствует, и генерирует требуемый.
Когда используется расширенный синтаксис, тег <rule> не имеет
специальных атрибутов. Этот синтаксис - наиболее гибкий и мощный из
всех синтаксисов шаблонов. В разделе "Часто встречающиеся образцы
запросов" приведены рецепты для наиболее распространенных
случаев. В данном же разделе описываются опции синтаксиса.
Расширенный синтаксис правил состоит из тега <rule> с двумя
или тремя дочерними тегами. Тег < должен быть первым
из дочерних тегов и должен содержать запрос правила. Тег < - необязательный средний тег, позволяющий создавать
дополнительные переменные. Тег <action> содержит тот контент,
который следует генерировать при каждом обнаружении решения. Эти теги
рассматриваются каждый в своем подразделе.
Расширенный синтаксис правил использует расширенный синтаксис
переменных, и эти переменные могут использоваться в дочерних тегах
тега <template>. Обычно их помещают в теги определения колонок в
списках и деревьях.
<.
Тег < содержит запрос шаблона, описанный
расширенным синтаксисом. Этот тег не имеет собственных атрибутов.
Если он присутствует, он должен быть первым тегом <rule>.
Рекурсивность <.
Этот тег может содержать теги <content>, <triple> и <. Первым дочерним тегом должен быть <content>, и
этот тег должен быть ровно один. Тег <content> должен также
содержать по крайней мере один тег < или <triple>.
Тег < может содержать тег <treeitem>. Если
шаблон основан на теге <tree>, то вместо тега <content>
можно использовать <treeitem>. В этом случае он записывается и
ведет себя точно так же. Нет никаких особенных причин поступать именно
так, это всего лишь память "давно минувших дней". <treeitem> считается устаревшим, лучше использовать <content>, однако на старых версиях платформы следует
использовать <treeitem>.
Когда эти теги используются, их порядок должен соответствовать порядку перебора ("бурение" данных), используемому процессором запроса. То есть это тот же порядок, что и иерархический порядок самих исследуемых данных.
Тег <content> должен быть первым дочерним тегом тега <. Он имеет единственный специальный атрибут:
uri
Это атрибут расширенной переменной шаблона. Данная переменная затем
обосновывается значением атрибута ref базового тега шаблона. Это
значение является стартовой точкой запроса. Если запрос рекурсивен,
вместо атрибута ref используется атрибут родительского запроса.
Тег <content> всегда имеет одну и ту же форму, так что обычно он
выглядит вот так:
<content uri="?uri"/>
Атрибут также используется в дочерних тегах тега <action>. Переменная, употребленная как атрибут тега <content>, никогда не должна употребляться как значение
атрибутов , появляющихся в контенте тега <action>. Если ее
использовать таким образом, запрос в шаблоне не обнаружит решений, и
никакого контента не будет порождено. Переменная, используемая в
атрибуте тега <content>, может появляться в любом другом
месте контента тега <action>.
Если шаблон основан на дереве, в версиях платформы младше 1.5
используется тег <treeitem>, вот так:
<treeitem uri="?uri"/>
Тег <treeitem> также может быть частью порождаемого контента.
В этом случае он может присутствовать в теге <action>, но любой
атрибут в качестве значения должен иметь переменную, отличную от ?.
Тег <triple> представляет один шаг (одну арку в графе <triple> увеличивает
число шагов на единицу, и также на единицу увеличивает число фактов,
требуемых для решения. Тег <triple> используется для связи
фактов с переменными и для обнаружения фактов. Тег <triple>
имеет следующие специальные атрибуты, которые должны всегда
присутствовать.
subject predicate object
может принимать значение расширенной переменной шаблона или
может принимать значение
object может принимать значение расширенной переменной шаблона,
В атрибутах предиката нельзя использовать переменные.
Можно сконструировать последовательность тегов <triple> так,
что они образуют <triple> с нулевыми
переменными бесполезен.
Тег < используется для поиска элементов, содержащихся
в теге-контейнере. Он имеет специальные атрибуты
container child
Атрибут container - это
сравнивается с дополнениями фактов, имеющими подлежащим
<member container="?uri" child="?item"/>
Поскольку искомые связи внутри или что то подобное в качестве
предиката), обычный тег <triple> может быть использован для
поиска этих элементов. Тег < - попросту
специализированная версия тега <triple>.
Преимущество, которое имеет тег < перед тегом <triple> состоит в том, что можно вообще не указывать предикат.
Тег < может применять тесты контейнера, описанные ранее в
разделе "Атрибуты ref и containment: тесты контейнера".
Чтобы выполнить ту же работу с тегом <triple>, придется
задействовать добавочный запрос, указывающий
Хотя атрибут контейнера тега < часто содержит
Тег < - необязательная часть расширенного синтаксиса
запроса. Он не имеет специальных атрибутов, и может содержать только
теги <. Теги < и <
постоянно используются в Mozilla, особенно в XBL. Между их применением
в шаблонах и где угодно еще нет прямой связи. В терминах SQL, они
являются реализацией инструкции " и нулевых
значений.
Тег < следовало бы называть <, поскольку это вовсе не "привязка" в смысле
XBL (или XPConnect или -переменная это просто
добавочная переменная, которая может быть обоснована добавочным
запросом. Это же значение имеет и тег <.
Раздел правила < - это место, где можно поместить
добавочные переменные, не ограничивая результатов <
запроса. Сделать это очень просто. В секции < все
переменные должны быть обоснованы, чтобы было найдено решение. Это
решение передается в секцию . Далее процессор запроса пытается
обосновать все переменные, перечисленные в секции <.
Если лишь некоторые из них удается обосновать, процессор просто
присваивает остальным нулевые значения. Это значит, что решения < никак не ограничиваются переменными <. Фактически, секция < подобна - если что-то подходит, об этом сообщается, в
противном случае вы получаете только то, что найдено по запросу.
Переменные в секции < должны быть расширенными
переменными шаблона. Переменные из раздела < можно
использовать здесь, но не наоборот. Чтобы секция <
имела смысл, должна быть использована по крайней мере одна из
переменных секции <.
Тег < идентичен тегу <triple> по атрибутам и
способу использования. Он отличается от <triple> только в
правилах, применяемых для обоснования его переменных, как описано в
разделе <.
Тег <action> используется в <rule> с расширенным
синтаксисом запроса. Он дает контент, который будет генерироваться
для каждого результата данного запроса. Контент правила <rule> с
простым синтаксисом генерируется точно так же, как контент тега <action>. Здесь описывается система генерации.
Контент тега <action> состоит из обычных XUL тегов и
расширенных переменных запроса. Система шаблонов замещает значение
каждой переменной при генерации контента. Таким образом, переменные
используются в теге <action>, хотя определяются и обосновываются
в теге < (они определяются и обосновываются
автоматически при простом синтаксисе). Система шаблонов добавляет
атрибут id каждому тегу каждый раз, когда генерируется контент. Тег <action> не может включать тег <script>.
Контент тега <action> должен быть организован так, как
показано в листинге 14.14
<action> // simple syntax:
<rule>
<box id="A">
<box id="B">
<box id="C" uri="?var"> // simple syntax: uri="rdf:*"
<box id="D"/>
<box id="E">
<box id="F"/>
</box>
</box>
</box>
</box>
</action>
Мы используем этот пример, чтобы объяснить, что и как
здесьработает. В общем случае теги могут вкладываться на произвольную
глубину внутри <action>, и может быть использован любой XUL-код.
Специальный случай шаблонов, основанных на деревьях, обсуждается
отдельно.
Контент тега <action> делится на тег, содержащий атрибут ,
порождающие его теги и наследующие ему теги. В листинге 14.14 С
содержит ; A и B - теги-предки; D, E и F - дочерние теги.
Теги-предки A и B порождаются лишь однажды, независимо от того, как
много решений обнаружит запрос. Если переменные запроса (расширенные
для контента <action>, простые для контента <rule> )
используются в A и B, они будут иметь значения, найденные в первом
решении запроса. Если A и B имеют дочерние теги, эти теги могут быть
неадекватны. Рекомендуется их избегать.
Тег C - начало повторяющегося контента, поскольку он имеет атрибут . И С, и его контент могут генерироваться как целое ноль и более
раз. Чтобы контент был сгенерирован хоть один раз, должны быть
выполнены два условия. Во-первых, запрос должен обнаружить хоть одно
решение. Во-вторых, значение атрибута тега C в этом обнаруженном
решении должно быть другим. Самый простой способ удостовериться, что
это именно так - установить его в значение переменной, упоминаемой как
дополнение в некотором тега <. В этом случае необходимо использовать ?item:
<member container="?seq" child="?item"/>
В наиболее общем случае, атрибуту должно быть присвоено
значение подлежащего или дополнения, разные для каждого решения,
обнаруженного запросом. Атрибут id принимает данное уникальное
значение для каждого тега C во время генерации контента. Тег C не
должен иметь дочерних тегов, это может привести к ошибке.
Рекомендуется в данном случае дочерних тегов избегать.
Если требуется построение контента с задержкой
("ленивое"), тег C должен быть одним из следующих
XUL-тегов:
<menu> <menulist> <menubutton> <toolbarbutton> <button> <treeitem>
Теги D, E, и F - обычные теги, генерируемые один раз на каждое
найденное решение запроса. Они могут иметь дочерние теги и обширный
собственный контент. Если эти теги имеют переменные шаблона, такие
переменные будут замещены найденными решениями.
Контент шаблонов, основанных на теге <tree>, может нарушать
правило, согласно которому теги-родители
Если шаблон основан на теге <tree>, каждый <treeitem> в
финальном дереве может иметь тег <treechildren> как свой второй
дочерний тег. Этот тег может содержать любое число поддеревьев. К
счастью, контент тега <action> должен представлять единственную
строку дерева. Конструктор шаблона, обрабатывающий тег <tree>,
достаточно разумен, чтобы скопировать этот контент в каждое поддерево.
Другими словами, он достаточно разумен, чтобы определить необходимость
<action> нужно прописать
достаточно аккуратно, чтобы такая конструкция работала. Она показана в
Листинге 14.15.
<action>
<treechildren> //simple syntax: use <rule>
<treeitem uri="?var"> //simple syntax: use uri="rdf:*"
<treerow>
... any normal treerow content ...
</treerow>
</treeitem>
</treechildren>
</action>
Все теги в этой конструкции могут иметь добавочные атрибуты. Не
следует использовать атрибут id для тега <treeitem>.
Переменная ?var обычно соответствует переменной в дополнении тегов < или <triple>.
Данный синтаксис можно слегка изменить, и даже использовать такой
шаблон внутри другого шаблона. Например, так, что тег <treeitem> порождается из одного источника <treechildren> - из другого. Подобные вложения следует
тщательно тестировать, потому что они не используются широко и,
следовательно, не являются достаточно надежными.
Шаблоны, основанные на деревьях, используют <action>
перед <treechildren>, см. листинг 14.15. Эта новая копия становится
затем отправной точкой для всех решений, найденных новым запросом.
И простые, и расширенные переменные могут появляться только в
значениях атрибутов XML. Некоторые теги XUL порождают текстовое
содержание между их открывающей и закрывающей частями. Например, тег <Description>.
Тег <textnode> предоставляет способ поместить переменную в
контент, не являющийся атрибутом. Предположим, переменная ?var в
некоторый момент содержит строку "red". Тогда строка
<tag> <textnode value="big ?var truck"/> </tag>
будет эквивалентна строке
<tag>big red truck</tag>
Тег <textnode> можно поместить в любое место внутри тега <action>. Тег <textnode> не может быть использован, если
запрос задействует простой синтаксис. На данном теге мы завершим
рассмотрение тегов шаблона.
В шаблонах широко используются следующие запросы.
Наиболее очевидные запросы шаблонов используют стандартную
организацию фактов, а это означает применение
Запросы одного факта (см. предыдущее обсуждение) можно
сконструировать лишь с использованием расширенного синтаксиса
запросов. Простой синтаксис использовать нельзя. Запросы одного факта
могут возвратить ноль или более решений. Единственное неизвестное
может быть лишь дополнением запрашиваемого факта. Подлежащее и
предикат должны быть известны и вдобавок буквально указаны в запросе.
Подобный запрос можно реализовать лишь с тегами < или <triple>. Если использовать тег <, это выглядит
так:
<rule>
<conditions>
<content uri="?uri"/>
<member container="?uri" child="?data"/>
</conditions>
<action>
<description uri="?data" value="?uri ?data"/>
</action>
</rule>
В данном случае, если предикат единичного факта не является фактом,
содержащимся в контейнере (то есть , или некоторым специфичным
для Mozilla значением, например ), то этот предикат должен быть
указан в атрибуте containment. В данном атрибуте можно перечислить
несколько альтернативных предикатов. В случае <triple> код
выглядит так:
<rule>
<conditions>
<content uri="?uri"/>
<triple subject="?uri" predicate="predURI" object="?data"/>
</conditions>
<action>
<description uri="?data" value="?uri ?data"/>
</action>
</rule>
Предикат - "predURI", выраженный литералом. Если
требуется указать несколько предикатов, используйте несколько правил rule.
Набор свойств - это запрос, чьей целью является получение ряда
элементов информации, связанных с подлежащим факта. Типичный пример,
когда мы рассматриваем подлежащее как объект JavaScript и хотим
получить значения свойств этого объекта. Другой пример - считать
подлежащее факта идентификатором записи в базе данных и получить все
элементы данной записи. Эти аналогии не противоречат обычному
использованию терминов "свойство" и "значение" в
Если подлежащее и его свойства являются членами
<rule> <box uri="rdf:*"> <label value="rdf:http://www.test.com/Test#Prop1"/> <label value="rdf:http://www.test.com/Test#Prop2"/> <label value="rdf:http://www.test.com/Test#Prop3"/> <label value="rdf:http://www.test.com/Test#Prop4"/> </box> </rule>
Если подлежащее и его свойства не являются элементами контейнера,
следует использовать расширенную запись запроса. В этом случае
стартовая точка та же, что и в запросе единичного факта, с
использованием тега <triple>. Должно быть известно, что по
крайней мере одно свойство существует.
<rule>
<conditions>
<content uri="?uri"/>
<triple subject="?uri" predicate="p1" object="?v1"/>
<triple subject="?uri" predicate="p2" object="?v2"/>
<triple subject="?uri" predicate="p3" object="?v3"/>
<triple subject="?uri" predicate="p4" object="?v4"/>
</conditions>
<action>
<description uri="?data" value="?v1 ?v2 ?v3 ?v4"/>
</action>
</rule>
Здесь p снова означает полный <triple>. Если некоторые свойства могут
не существовать (или имеют значение null ), соответствующий
тег <triple> можно заменить тегом < и переместить в
секцию <.
Если запрос находит ровно одно решение, оно называется единственным решением. Обычно это бывает, если прикладной программист знает, что решение всегда существует, и единственно. Этот случай не требует специального синтаксиса, это просто следствие устройства фактов.
Здесь есть, однако, некоторая хитрость. Она возникает, когда мы
используем атрибут в теге <action>. Поскольку речь идет о
теге <action>, значит, это расширенный синтаксис. Здесь
возникает случай, когда запрос найдет множество решений, но построит
контент лишь для одного. Это возможно только для комплексных запросов.
Приведенный ниже пример иллюстрирует этот случай. Предположим, что у
нас есть следующий контент
<Description about="urn:example:root">
<link1>
<Description about="urn:example:child">
<link2 resource="urn:example:X"/>
<link2 resource="urn:example:Y"/>
</Description>
</link1>
</Description>
Все ресурсы этих фактов можно обнаружить таким запросом:
<rule>
<conditions>
<content uri="?uri"/>
<triple subject="?uri" predicate="p1" object="?child"/>
<triple subject="?child" predicate="p2" object="?res"/>
</conditions>
<action>
<description uri="?res" value="?uri ?child ?res"/>
</action>
</rule>
В этом запросе p1 и p2 нужно заменить подходящими link1 и link2. Поскольку переменная ? принимает свое значение для каждого
решения (одно X и одно Y), будут порождены две копии контента тега <action>. Если, однако, тег <description> заменить
следующей строкой, будет порождена лишь одна копия:
<description uri="?child" value="?uri ?child ?res"/>
Здесь порождается лишь одна копия, потому что переменная ?
может быть обоснована лишь одним значением. Обычно найденное решение
соответствует первому найденному в документе
Все запросы шаблонов эквивалентны навигации по дереву данных, поскольку система запросов использует стратегию "сначала вниз". Запросы шаблонов кажутся сложными, потому что (а) зачастую они рекурсивны, (б) требуется расширенный синтаксис. Сложный синтаксис маскирует тот факт, что на самом деле они очень просты. Листинг 14.16 иллюстрирует это положение.
<tree flex="1" datasources="test.rdf"
ref="http://www.example.com/test.rdf">
<treecols>
<treecol id="colA" primary="true"/>
</treecols>
<template>
<rule>
<conditions>
<content uri="?uri"/>
<member container="?uri" child="?item"/>
</conditions>
<action>
<treechildren>
<treeitem uri="?item">
<treerow>
<treecell label="?item"/>
</treerow>
</treeitem>
</treechildren>
</action>
</rule>
</template>
</tree>
В листинге 14.16 приведена прямолинейная минимальная комбинация
шаблона и дерева. Темным выделена разметка шаблона, светлым - разметка
дерева. Несмотря на то, что конструируется общий случай, разметка
собственно шаблона очень проста. Секция <rule> есть не что иное,
как запрос единичного факта. Результат запроса используется ровно в
одном месте. Код кажется сложным, потому что перегруженная разметка
дерева смешивается с перегруженной разметкой шаблона. Если тег <tree> заменить на <box> а порождаемый контент
минимизировать до тега <description>, шаблон сведется к
листингу 14.17.
<box datasources="test.rdf" ref="http://www.example.com/test.rdf">
<template>
<rule>
<conditions>
<content uri="?uri"/>
<member container="?uri" child="?item"/>
</conditions>
<action>
<description uri="?item" value="?item"/>
</action>
</rule>
</template>
</box>
Здесь видно, что он несложен.
Эту запись можно упростить и дальше, если
Оба факта должны повторяться вниз по дереву, поскольку каждый шаг запроса требует обоих фактов. Это значит, что дерево, исследуемое запросом с простым синтаксисом, должно быть вдвое больше, нежели дерево, запрашиваемое более экономичным расширенным. В листинге 14.17 требуется только один факт на каждый шаг вниз по дереву.
Есть несколько способов получить решения объединений двух или более запросов.
Атрибут может указывать на несколько
Атрибут containment может добавить к запросу несколько
разных предикатов container.
Можно использовать несколько тегов <rule>, чтобы найти более
одного решения на данном множестве фактов.
Можно использовать несколько тегов <, чтобы получить
несколько поддеревьев данного запроса.
Следующий запрос не будет обработан:
<rule> <conditions> <content uri="?uri"/> <triple subject="?uri" predicate="a" object="?v1"/> <triple subject="?v1" predicate="b" object="?v2"/> <triple subject="?v2" predicate="c" object="?v3"/> <triple subject="?v4" predicate="d" object="?v3"/> </conditions> </rule>
В данном запросе последний тег <triple> не использует
переменную ?v3 как подлежащее, а пытается двигаться по дереву в
обратную сторону. Это уменьшает глубину проникновения в дерево на шаг,
вместо того чтобы двигаться вглубь. Такое поведение запроса не
реализовано, все условия < должны продвигать запрос в
одну сторону.
Рассмотрим те шаги, которые последовательно проходит запрос шаблона. Первая часть процесса - начальное порождение контента XUL.
observers ), эти наблюдатели отслеживаются в процессе поиска.Вторая часть процесса касается взаимодействия пользователя и шаблона после завершения первоначального порождения контента.
<listbox> или <tree>, должны откликнуться на эти действия,
возможно даже обновляя содержание источника фактов. Перетаскивание
мышкой контента шаблона требует от прикладного программиста написания
дополнительных скриптов.nsIRDFRemoteDataSource.Рассмотрим, как улучшать шаблоны из скриптов и управлять ими, и как
использовать продвинутые свойства деревьев, обсуждавшиеся в лекции 13,
"Списки и деревья". Лекция 16, "Объекты XPCOM",
содержит подробное описание
Шаблоны на чистом XUL относительно просты, поскольку неизменны и порождают контент лишь однажды. Шаблоны с использованием XUL, JavaScript, AOM и XPCOM - это достойная задачка, потому что полная функциональность в этом случае скорее исключение, чем правило. Вот некоторая трансцендентная мудрость о динамических шаблонах:
dont-build-content, и другие флаги, сказывающиеся на
производительности, не работают, когда шаблон должен быть перестроен
как целое. Они воздействуют лишь на производительность обработки любой
рекурсивной части запроса шаблона, и на способ слияния множественных
источников данных.ref шаблона может быть изменено в любое
время, и порождаемый контент будет автоматически перестроен.ref, требуют
вызова метода rebuild () вручную.nsIRDFCompositeDataSource, содержащий все источники
данных шаблона, не следует использовать для добавления новых фактов
(ни методом Assert () ни любым другим). Всегда работайте с конкретным
источником данных.in-memory-datasource (изначально пустые источники данных, в дальнейшем
заполняющие значение rdf :null атрибута datasources ) и xml-datasource
(xml-datasource можно лишь с помощью схемы file:. С использованием
схем chrome : или resource:, или любой иной, этого делать не
следует.beginBatchUpdate() для
деревьев в Таблице 13.3.Flush () поддерживается лишь для источников данных,
основанных на URL типа "file:".Refresh() поддерживается для URL типа "file:" и "http:". Используя этот метод для получения файла с
web-сервера, проследите, чтобы получаемые данные нигде не кешировались,
это может привести к некорректному поведению системы.Система шаблонов добавляет свойства JavaScript к объектам, представляющим теги шаблона. Свойства добавляются и к тегам, определяющим шаблон, и к порождаемым тегам. Такие свойства добавляются к стандартным свойствам тегов шаблона. Эти свойства указаны в Таблице 14.1.
| Свойство | Полезность | Тег <template> |
Теги правил | Порожденные теги |
|---|---|---|---|---|
database |
+ | - | - | - |
builder |
Иногда + | - | - | - |
resource |
+ | + (содержит id тега) |
- | + (содержит значение null ) |
|
+ | Пустая строка | Пустая строка | Пустая строка |
ref |
+ | Пустая строка | Пустая строка | Пустая строка |
В этой таблице, "+" означает, что свойство приобретает некоторое полезное значение; "-" значит, что свойство приобретает значение null; "Пустая строка" означает, что свойство содержит строку длины нуль.
Свойство database - это объект, содержащий ссылки на источники
данных, используемые шаблоном. Он реализует интерфейс nsICompositeDataSource XPCOM. Он существует даже если единственный
источник данных . Для шаблонов, получающих данные из .
Свойство builder - это объект, управляющий запросом и процессом
порождения контента шаблона. Его можно рассматривать как
высокоспециализированный (и очень ограниченный) инструмент верстки и
рендеринга шаблона. Он реализует интерфейс nsIXULTemplateBuilder. Он
используется лишь для шаблонов на основе тегов <listbox> и <tree>.
Свойство resource - это объект, содержащий <template>, он содержит id шаблона, как
не-, он
содержит значение указанной расширенной переменной шаблона. Объект
реализует интерфейс nsIRDFResource.
Свойство содержит значение XUL атрибута .
Свойство ref содержит значение XUL атрибута ref.
Объект database имеет методы AddDataSource(), RemoveDataSource(), и GetDataSources(), используемые для управления источниками данных
шаблона.
Объект builder имеет метод , используемый для полного
пересчета и обновления содержания шаблона.
Объект resource и атрибуты и ref существуют лишь для
удобства. Ни один из этих объектов не может быть замещен прикладным
программистом.
В дополнение к данным объектам AOM, существуют объекты-наблюдатели, объекты-снимки и объекты-делегаты конструкторов шаблонов. Они рассматриваются ниже.
Конструкторы шаблонов - это конструкторы, то есть код внутри платформы Mozilla, порождающий контент дерева. Конструкторы не могут быть реализованы прикладным программистом, но могут модифицироваться.
Простейшее использование конструктора - пересчет и обновление дерева в шаблоне. Требуется лишь одна строка кода:
treeElement.builder.rebuild()
Здесь нет опций. Эта техника работает только для шаблонов,
построенных на тегах <tree> или <listbox>. не
работает на шаблонах, построенных на иных тегах.
Во время перестройки дерева состояния open и closed всех
поддеревьев сохраняются, если указано ленивое построение дерева. Чтобы
этого не случилось, используйте атрибут statedatasource тега <tree>, и затем удалите источник данных перед перестройкой.
Чтобы его удалить, удалите источник данных из свойства databases,
затем удалите атрибут tree, используя операцию DOM, после чего
вызовите метод .
Вспомним, что в Mozilla используется два конструктора; конструктор контента XUL и конструктор шаблонов. Мы здесь обсуждаем последний. Конструктор шаблона основан на XPCOM-компоненте и интерфейсе:
@mozilla.org/xul/xul-template-builder;1 nsIXULTemplateBuilder
Данный интерфейс содержит метод . Данный конструктор не
может быть модифицирован или замещен прикладным программистом.
XUL конструктор имеет частный случай для деревьев:
@mozilla.org/xul/xul-tree-builder;1 nsIXULTreeBuilder
Этот конструктор также не может быть замещен прикладным
программистом. Но он может быть улучшен. С помощью интерфейса nsITreeBuilderObserver можно зарегистрировать новый объект. Хотя этот
интерфейс и напоминает объект-наблюдатель, он также очень похож и на
объект-делегат. Чем его считать - дело вкуса.
Интерфейс nsITreeBuilderObserver - подмножество интерфейса nsITreeView, применяемого для создания пользовательских снимков
дерева. Его можно использовать для улучшения способов взаимодействия
пользователя и дерева, такого как кликанье мышкой по колонкам и
перетаскивание мышкой контента. В приложениях Mozilla можно найти два
примера применения этого интерфейса: одно в менеджере закладок и одно
в
Эти интерфейсы применяются для реализации
Если используется объект с интерфейсом nsITreeBuilderObserver, его
нужно реализовать как наблюдатель DOM-объекта дерева с помощью метода addObserver() интерфейса nsITreeView.
Все конструкторы Mozilla также поддерживают интерфейс nsIRDFObserver, а это означает, что все дерево целиком может
действовать как наблюдатель. Этот интерфейс может быть добавлен
объекту источника данных (интерфейс nsIRDFDataSource ), и он будет
опрашиваться каждый раз, когда появляются новые факты, значимые для
запроса шаблона.
Если шаблон основан на дереве, то также доступны свойства снимков. В лекции 13, "Списки и Деревья", объяснялось, что снимки - это автоматически создаваемые объекты, используемые конструктором дерева или списка для генерации актуального в каждый момент контента.
Созданный программистом объект-снимок полностью заменяет контент,
который будет показан шаблоном как часть данных из файла <tree> - , то созданный
программистом снимок делает всю работу по наполнению дерева данными.
Простейший способ это реализовать - использовать тег <tree> с
нормальной секцией <treecols>, плюс одна из трех следующих
опций для остающегося контента:
<children/> <template> <treechildren/> </template> <template> ... normal set of template rules ... </template>
Подобное дерево сначала построит свой обычный контент, затем, когда
снимок изменится и дерево будет перестроено, начинает действовать
снимок, который определяет дальнейший контент. Если использован
атрибут-флаг "dont-build-content", обычный контент вообще не
будет построен и показан.
Объекты-делегаты - это очень обобщенный термин в объектно-ориентированном программировании, и множество структур имеют делегато-подобные свойства.
В платформе Mozilla объекты-делегаты - это объекты, связывающие
URIs фактов
В этой лекции нет места и времени для подробного обсуждения
объектов-делегатов. Как стартовую точку изучения можно рекомендовать
интерфейсы nsIRDFResource и nsIRDFDelegateFactory, а также следующие
компоненты XPCOM:
@mozilla.org/rdf/delegate-factory;1?key=
Ниже приведен краткий список стратегий решения часто встречающихся
задач. Программируемые и другими внутренними
источниками данных.
Чтобы сменить источник данных, используйте databases.getDataSources(), шаг за шагом по доступному списку
источников, чтобы найти нужный, задействуйте databases.removeDataSource() с этим источником в качестве аргумента, и
затем перестройте шаблон. Либо удалите этот источник и перестройте
шаблон.
Чтобы сменить корневой setAttribute("ref",newURI) для базового тега. Шаблон будет
перестроен автоматически. Установка свойства ref даст тот же
эффект.
Чтобы сменить правила запроса, используйте операции DOM или
innerHTML чтобы изменить теги прямо в XUL, и затем перестройте шаблон
с помощью . Лучшее решение - создать все возможные правила и
затем запретить ненужные. Это можно сделать, поместив перед правилами,
которые нужно запретить, правило "catch-all". Правило "catch-all" - это такое правило, которое находит решения
всех доступных ему данных, так что до оставшихся правил дело не
доходит.
Чтобы изменить факты в источнике данных, выберите нужный источник с
помощью databases.GetDataSources(). Используйте методы или Change() интерфейса nsIRDFDataSource. В некоторых случаях шаблон будет
перестроен автоматически. Чтобы перестроить его наверняка, используйте .
Чтобы изменить результаты запроса, следует немного отступить назад.
Вы не можете изменить результаты, найденные запросом, потому что они
порождаются им. Необходимо изменить запрос или исходные @mozilla.org/
и другие чтобы
установить значение факта true. Затем перестройте шаблон.
Чтобы изменить порожденный контент, применяются обычные DOM
операции. (Эти изменения будут потеряны, если шаблон перестроить).
Чтобы сделать изменения постоянными, измените часть правила <content>, а не порожденный контент, и перестройте шаблон.
Система шаблонов не имеет специальных стилевых усовершенствований, но и с существующими стилями можно использовать несколько удачных приемов.
Контент шаблона можно оформлять стилями, и в атрибутах style и class использовать переменные шаблона. Таким образом стилевая
информация может предоставляться самими
Стили можно применять, используя теги <rule> как селекторы,
Наконец, стили можно применить к порожденному контенту, используя операции JavaScript DOM. Если шаблон будет перестроен, это стилевое оформление может потеряться.
Данный раздел "Практика" описывает использование шаблонов нашего приложения, работающих с реальными данными.
В этом разделе мы заменим часть нашего кода шаблоном и затем протестируем приложение на реальных данных.
Для начала, у нас есть модель
chrome://notetaker/contents/notetaker.rdf
Шаблоны нам понадобятся три раза:
Edit также должен загружаться с существующими ключевыми словами текущей заметки.Edit должно загружаться со всеми ключевыми словами, связанными с текущими ключевыми словами.Последний пункт требует специальной техники; содержание дерева, грубо говоря, должно уточнять содержание списка, а это требует координирования их работы.
Данные также появляются в HTML-записи на текущей web-странице. HTML
не поддерживает шаблонов, так что мы должны извлечь необходимые нам
данные из
Для того чтобы построить шаблон, нам нужны некоторые данные.
Создадим
В листинге 14.18 приведены данные для этих двух записей и связи ключевых слов.
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmnls:NT="http://www.mozilla.org/notetaker-rdf#">
<Description about="urn:notetaker:root">
<NT:notes>
<Seq about="urn:notetaker:notes">
<li resource="http://saturn/test1.html"/>
<li resource="http://saturn/test2.html"/>
</Seq>
</NT:notes>
<NT:keywords>
<Seq about="urn:notetaker:keywords">
<li resource="urn:notetaker:keyword:checkpointed"/>
<li resource="urn:notetaker:keyword:reviewed"/>
<li resource="urn:notetaker:keyword:fun"/>
<li resource="urn:notetaker:keyword:visual"/>
<li resource="urn:notetaker:keyword:cool"/>
<li resource="urn:notetaker:keyword:test"/>
<li resource="urn:notetaker:keyword:breakdown"/>
<li resource="urn:notetaker:keyword:first draft"/>
<li resource="urn:notetaker:keyword:final"/>
<li resource="urn:notetaker:keyword:guru"/>
<li resource="urn:notetaker:keyword:rubbish"/>
</Seq>
</NT:keywords>
</Description>
<!-- details for each note -->
<Description about="http://saturn/test1.html">
<NT:summary>My Summary</NT:summary>
<NT:details>My Details</NT:details>
<NT:top>100</NT:top>
<NT:left>90</NT:left>
<NT:width>80</NT:width>
<NT:height>70</NT:height>
<NT:keyword resource="urn:notetaker:keyword:test"/>
<NT:keyword resource="urn:notetaker:keyword:cool"/>
</Description>
<Description about="http://saturn/test2.html">
<NT:summary>Good place to list</NT:summary>
<NT:details>Last time I had a website here, my page also appeared on Yahoo </NT:details>
<NT:top>100</NT:top>
<NT:left>300</NT:left>
<NT:width>100</NT:width>
<NT:height>200<NT:height>
<NT:keyword resource="urn:notetaker:keyword:checkpointed"/>
<NT:keyword resource="urn:notetaker:keyword:reviewed"/>
<NT:keyword resource="urn:notetaker:keyword:fun"/>
<NT:keyword resource="urn:notetaker:keyword:visual"/>
</Description>
<!-- values for each keyword -->
<Description about="urn:notetaker:keyword:checkpointed" NT:label="checkpointed"/>
<Description about="urn:notetaker:keyword:reviewed" NT:label="reviewed"/ >
<Description about="urn:notetaker:keyword:fun" NT:label="fun"/>
<Description about="urn:notetaker:keyword:visual" NT:label="visual"/>
<Description about="urn:notetaker:keyword:breakdown" NT:label="breakdown"/>
<Description about="urn:notetaker:keyword:first draft" NT:label="first draft"/>
<Description about="urn:notetaker:keyword:final" NT:label="final"/>
<Description about="urn:notetaker:keyword:guru" NT:label="guru"/>
<Description about="urn:notetaker:keyword:rubbish" NT:label="rubbish"/>
<Description about="urn:notetaker:keyword:test" NT:label="test"/>
<Description about="urn:notetaker:keyword:cool" NT:label="cool"/>
<!--sufficient related keyword pairings -->
<Description about="urn:notetaker:keyword:checkpointed">
<NT:related resource="urn:notetaker:keyword:breakdown"/>
<NT:related resource="urn:notetaker:keyword:first draft"/>
<NT:related resource="urn:notetaker:keyword:final"/>
</Description>
<Description about="urn:notetaker:keyword:reviewed">
<NT:related resource="urn:notetaker:keyword:guru"/>
<NT:related resource="urn:notetaker:keyword:rubbish"/>
</Description>
<Description about="urn:notetaker:keyword:fun">
<NT:related resource="urn:notetaker:keyword:cool"/>
</Description>
<!-- single example of a cycle -->
<Description about="urn:notetaker:keyword:cool">
<NT:related resource="urn:notetaker:keyword:test"/>
</Description>
</Description>
</RDF>
К сочетанию
Сначала мы напишем шаблоны для панели инструментов NoteTaker. Для панели инструментов потребуется два значения, по одному для каждого поля ввода текста, и набор из нуля или более элементов выпадающего меню. Нужно использовать два шаблона, один для полей ввода и другой для выпадающего меню.
Выпадающее меню - самое простое. Из файла notetaker.label. Ключевые слова
собираются вместе в , т.е. теге <Seq>. Это устройство соответствует стандартной организации
фактов, так что можно использовать простой синтаксис запроса и,
следовательно, создание шаблона не должно вызывать затруднений.
Сначала протестируем шаблон на простом документе, не будем
добавлять его на панель инструментов сразу. Таким образом мы избежим
сложностей с контентом выпадающего меню. Поскольку шаблоны и
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<!DOCTYPE window>
<window xmlns="http://www.mozilla.org/keymaster/
gatekeeper/there.is.only.xul">
<vbox>
<description value="Static content"/>
<hbox>
<description value="Repeated content"/>
</hbox>
</vbox>
</window>
Для шаблона нам необходимы следующие моменты:
Файл
Стартовая точка запроса: ref="
Простая переменная требует повторяющегося контента:
В качестве переменной запроса с простым синтаксисом используем:
rdf:http://www.mozilla.org/notetaker-rdf#label
Объединяя эту информацию с кодом листинга 14.18, получим листинг 14.20.
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/"
type="text/css"?>
<!DOCTYPE window>
<window xmlns="http://www.mozilla.org/keymaster/
gatekeeper/there.is.only.xul">
<vbox datasources="notetaker.rdf" ref="urn:notetaker:keywords">
<description value="Static content"/>
<template>
<hbox uri="rdf:*">
<description value="Repeated content"/>
<description value="rdf:http://www.mozilla.org/
notetaker-rdf#label"/>
</hbox>
</template>
</vbox>
</window>
Контент " находится вне тега <template>, так что мы увидим его в любом случае. Контент " появится один раз для каждого решения,
найденного запросом. Третий тег description даст значение единственной
переменной, обоснованной запросом. Результаты работы шаблона показаны
на рисунке 14.6.
(рис 14.6) Контент, генерируемый шаблоном в тестовой форме.Теперь у нас есть работающий шаблон. Чтобы этого добиться, мы игнорировали некоторые мелочи; с системой шаблонов, однако, все в порядке, за исключением, может быть, нехватки отладочных инструментов.
Теперь мы можем модифицировать шаблон, встроив его в панель инструментов. В листинге 14.21 показано выпадающее меню до и после присоединения шаблона.
<?xml version="1.0"?>
<menulist editable="true">
<menupopup>
<!-- static menu items removed -->
</menupopup>
</menulist>
<menulist id="notetaker-toolbar.keywords" editable="true">
<menupopup datasources="notetaker.rdf" ref="urn:notetaker:keywords">
<template>
<menuitem uri="rdf:*" label="rdf:
http://www.mozilla.org/notetaker-rdf#label"/>
</template>
</menupopup>
</menulist>
Результаты этих изменений видны на рисунке 14.7.
Если запрос не обнаружит ключевых слов, в меню не будет ни одного
элемента, и на панели инструментов это будет выглядеть плохо. Чтобы
исправить положение, мы добавили временный тег <menuitem> перед
тегом <template>. Другой способ - сделать наверняка, чтобы в
файле notetaker.
Второй шаблон на панели инструментов должен найти единственное
решение для тега <textbox>. Чтобы представить себе, каким может
быть этот запрос, снова посмотрим на файл notetaker. ), и имеет свойство summary. Таким образом
стандартная организация фактов, требуемая для простого синтаксиса
запроса, соблюдена. Наверное, мы можем использовать простой
синтаксис.
Но на деле мы простой синтаксис использовать не можем, потому что мы привередливы - мы хотим выбирать, какие члены последовательности будут получены. Нам нужен единственный член, являющийся записью именно о текущем URL. Так что придется использовать расширенный синтаксис.
(рис 14.7) Выпадающее меню панели инструментов NoteTaker, порожденное шаблоном.В расширенном синтаксисе мы не обязаны начинать запрос с вершины последовательности, так что мы можем быть более изобретательны. Мы можем начать его прямо с URL текущей записи. Если мы так сделаем, примером запроса может быть:
<- http://saturn/test1.html, http://www.mozilla.org/ notetakerrdf#summary, ?summary ->
Используя совет, данный в настоящей лекции, в разделе "Часто встречающиеся образцы запросов", создадим шаблон следующим образом:
<box datasources="notetaker.rdf" ref="http://saturn/test1.html">
<template>
<rule>
<conditions>
<content uri="?uri"/>
<triple subject="?uri"
predicate="http://www.mozilla.org/notetaker-rdf#summary"
object="?summary"/>
</conditions>
<action>
<textbox id="notetaker-toolbar.summary" uri="?summary"
value="?summary"/>
</action>
</rule>
</template>
</box>
Этот код заменит единственный тег <textbox/>, присутствующий
на панели инструментов. Мы заключили textbox в невидимый тег <box>, чтобы привязать к нему шаблон.
Этот шаблон в качестве исходной точки запроса имеет фиксированный
URL. В недалеком будущем мы сделаем данное значение динамическим,
используя скрипт и метод setAttribute(). На этом изменения в XUL
панели инструментов NoteTaker заканчиваются. Обратимся к шаблонам
диалогового окна Edit. Оба тега этого окна, и <listbox>, и <tree>, требуют использования шаблонов.
Шаблон для тега <listbox> - более простая задача, так что
начнем с нее. Снова заглянем в файл notetaker., то есть имеет место стандартная организация фактов.
Проблема состоит в том, что URL записи - известная, фиксированная
величина, а не переменная для каждой записи в последовательности. Эта
ситуация подобна ситуации с шаблоном для <textbox> на панели
инструментов, так что используем расширенную запись запроса.
Вторая причина использовать расширенный синтаксис - необходимость
добыть текстовую строку ключевых слов. Эти строки - свойства каждого
ключевого слова, а не свойства всей записи. Мы можем легко их
получить, расширяя запрос глубже по множеству фактов - один добавочный
тег <triple> свяжет найденные ключевые слова записи с их
текстовыми значениями. Требуемый шаблон выглядит как листинг
14.23.
<listbox id="dialog.keywords" rows="3" datasources="notetaker.rdf"
ref="http://saturn/test1.html">
<template>
<rule>
<conditions>
<content uri="?uri"/>
<triple subject="?uri"
predicate="http://www.mozilla.org/
notetaker-rdf#keyword"
object="?keyword"/>
<triple subject="?keyword"
predicate="http://www.mozilla.org/
notetaker-rdf#label"
object="?text"/>
</conditions>
<action>
<listitem uri="?keyword" label="?text"/>
</action>
</rule>
</template>
</listbox>
За исключением добавочного тега <triple>, этот тот же код,
что и для <textbox>.
Мы могли бы использовать шаблон и для панели Edit в диалоговом окне Edit. Но у нас есть достаточно оснований так не поступать, так что
оставим эту панель в прежнем состоянии. Одно из этих оснований - то,
что мы не знаем, какая запись больше всего подойдет, когда загружается
данный URL.
Последний шаблон, который мы сконструируем, это шаблон дерева для связанных ключевых слов.
Снова рассмотрим файл notetaker.label для
ключевого слова. Нам также требуются связанные свойства, чтобы найти
ключевые слова, связанные с найденным. Наконец, нам нужно, чтобы
началом ( level 0 ) дерева были ключевые слова для записи текущего URL.
Мы используем этот URL как вершину запроса, но высветим лишь дочерние
решения данного URL, но не сам URL.
Для полного
<- current-page-url, keyword, ?keyword -> // level 0 <- ?keyword, label, ?text -> <- ?keyword, related, ?keyword2 -> <- ?keyword2, label, ?text2 -> // level 1 <- ?keyword2, related, ?keyword3 -> // level 2 <- ?keyword3, label, ?text3 -> ... и так далее ...
Такое множество фактов не отвечает стандартной организации, так что
требуется расширенный синтаксис. Это множество фактов является
рекурсивным запросом, так что нам действительно нужен именно тег <tree>.
Каким будет запрос? Зададим вопрос более точно: что необходимо
получить запросу, чтобы продвинуться на один уровень глубже по дереву
решений? На каждом уровне есть два факта, поэтому кажется, что
(рис 14.8) Диаграмма RDF для рекурсивного запроса шаблона.Ясно, что рекурсивность требует одного шага вглубь дерева вдоль вертикальной стрелочки. Так что запрос является запросом единственного факта. А другая стрелочка раскрывает информацию, требуемую на каждом уровне, но не участвующую в рекурсии.
Сначала рассмотрим факты, порождающие рекурсию, и расположенные
вдоль вертикальных стрелок. Проблема в том, что иногда они содержат
ключевые слова, а иногда - связанные ключевые слова. Другими словами,
для
<- current-page-url, keyword, ?keyword -> <- current-keyword-urn, related, ?keyword ->
Каким-то образом запрос шаблона должен учесть оба случая. Один
способ - использовать отдельные правила <rule> для каждой
возможности. В нашем случае, однако, хорошее решение - атрибут шаблона containment. К счастью, при любом , либо со свойством related, но не с обоими сразу. А это
значит, что мы можем использовать несколько предикатов container
вместе. Мы перечислим и предикат related, и предикат в
значении этого атрибута.
Чтобы понять, почему мы можем использовать containment, рассмотрим
работу запроса. Когда запрос открывает верхний уровень дерева,
предикат найдет решения, а предикат related - нет, потому что
так в related найдет решения, а предикат
- нет. Это в точности то, что нам нужно. Полученный в результате
шаблон приведен в листинге 14.24.
<tree id="dialog.related" flex="1"
datasources="notetaker.rdf"
ref="http://saturn/test2.html"
containment="http://www.mozilla.org/notetaker-rdf#related http://
www.mozilla.org/notetaker-rdf#keyword" hidecolumnpicker="true"
>
<treecols>
<treecol id="tree.all" hideheader="true"
primary="true"
flex="1"/>
</treecols>
<template>
<rule>
<conditions>
<content uri="?uri"/>
<member container="?uri"
hild="?keyword"/>
</conditions>
<action>
<treechildren>
<treeitem uri="?keyword">
<treerow>
<treecell label="?keyword"/>
</treerow>
</treeitem>
</treechildren>
</action>
</rule>
</template>
</tree>
Запрос содержит тег <, чтобы проверять соответствие
атрибуту containment. Поскольку это <description>. Мы обязаны
использовать один из тегов, явным образом поддерживающий рекурсивные
запросы, в данном случае для <tree>.
Теперь шаблон готов, нужно лишь добавить поиск дополнительной
информации, как показано на рисунке 14.8. Это можно сделать, используя
тег <. Добавим следующий код сразу после тега
</conditions>: <bindings> <binding subject="?keyword" predicate="http://www.mozilla.org/notetaker-rdf#label" object="?text"/> </bindings>
Поскольку теги < не сказываются на рекурсивном
процессе, запрос мы этим не повредим, а лишь уточним им обнаруживаемую
информацию. Наконец, нужно изменить тег <treecell>, чтобы
вывести label, обнаруживаемый тегом <, а не :
<treecell label="?text"/>
На этом создание всех шаблонов завершено. Хотя теги <listbox>
и <tree> имеют контент, порожденный шаблоном, обработчики
событий, созданные нами в лекции 13, "Списки и деревья",
продолжают нормально работать. Они обслуживают DOM структуру
порожденного шаблоном контента так же легко, как и статические теги
XUL.
С шаблоном <tree> у нас возникает одна проблема. Наш шаблон
не обнаруживает связанные ключевые слова так, как это делал
экспериментальный снимок шаблона в лекции 13, "Списки и
деревья". Он обнаруживает лишь то, что есть в в файл
notetaker.
Наконец, нам нужно реализовать обновление данных, построенных
шаблоном. Это означает необходимость связать данные на панели
инструментов, в диалоговом окне Edit и HTML-записи с
<textbox> на панели инструментов каждый раз, когда изменяется текущая запись.Keywords диалогового окна при его открытии.Чтобы этого добиться, внесем следующие небольшие изменения на панели инструментов:
<textbox> на панели инструментов.delete на панели инструментов нужна команда notetaker-delete.save на панели инструментов нужна команда notetaker-sav e.notetaker-open-dialog должна обновлять выпадающее меню на панели инструментов, когда закрывается диалоговое окно.Во-первых, мы должны реализовать объект note на JavaScript и его
методы clear() и и свойство url. Метод clear() уничтожает
все данные текущей записи, преобразует данный URL в URL
существующей записи и сохраняет результат. В данной лекции эти
изменения будут тривиальны, но мы уточним их позже. Код нового объекта note приведен в листинге 14.25.
function Note() {} // constructor
Note.prototype = {
url : null,
summary : "",
details : "",
chop_query : true,
home_page : false,
width : 100,
height : 90,
top : 80,
left : 70,
clear : function () {
this.url = null;
},
resolve : function (url){
this.url = url;
},
}
var note = new Note();
Во-вторых, реализуем функцию refresh_toolbar(), обновляющую
шаблоны панели инструментов. Некоторые из этих функций нам придется
усовершенствовать в следующих лекциях. Функция приведена в листинге
14.26.
function refresh_toolbar() {
var menu = window.document.getElementById
('notetaker-toolbar.keywords');
menu.firstChild.builder.rebuild();
var box = window.document.getElementById
('notetaker-toolbar.summary');
box.parentNode.setAttribute('ref', note.url);
box.parentNode.builder.rebuild();
}
Метод автоматически удалит и пересоздаст контент шаблона.
В случае выпадающего меню контент изменится, только если изменится
исходный <textbox> модифицируется сам шаблон,
поэтому запрос каждый раз разный.
Наконец, посмотрим на регулярные проверки. Они вызываются из
функции content_poll(), так что поправим ее так, чтобы обновлялась не
только высвеченная запись, но и панель инструментов.
function content_poll() {
var doc;
try {
if ( !window.content ) throw('fail');
doc = window.content.document;
if ( !doc ) throw('fail');
if ( doc.getElementsByTagName("body").length == 0 )
throw('fail');
if ( doc.location.href == "about:blank" )
throw('fail'); }
catch (e) {
note.clear(); refresh_toolbar(); return;
}
if ( doc.visited )
return;
note.resolve(doc.location.href);
display_note();
refresh_toolbar();
doc.visited = true;
}
Если подходящего URL не существует, текущая запись и панель инструментов очищаются. В противном случае ищется новая текущая запись и обновляются панель инструментов, запись и текущая страница.
Мы еще не выполнили пункты 4 и 6, потому что пока не знаем, как
модифицировать action() так, чтобы она вызывала refresh_toolbar() каждый раз, когда это необходимо. Листинг 14.28
показывает этот простой код.
function action(task) {
if ( task == "notetaker-open-dialog" ) {
window.openDialog("editDialog.xul","_blank","modal=yes");
refresh_toolbar();
}
if ( task == "notetaker-display" ) {
display_note();
}
if ( task == "notetaker-save" ) {
refresh_toolbar();
}
if ( task == "notetaker-delete" ) {
refresh_toolbar();
}
}
На этом управление шаблонами завершено. Для диалогового окна нам
нужно сделать то же самое для шаблонов панели . Мы выполним
эту задачу в команде notetaker-load. В функции action(), обслуживающей
команду, добавим вызов refresh_dialog() и реализуем refresh_dialog()
как показано в листинге 14.29.
function refresh_dialog() {
var listbox = window.document.getElementById('dialog.keywords');
listbox.setAttribute('ref', window.opener.note.url);
listbox.builder.rebuild();
var tree = window.document.getElementById('dialog.keywords');
tree.setAttribute('ref', window.opener.note.url);
tree.builder.rebuild();
}
Этот код идентичен коду обновления шаблона на панели инструментов выпадающего меню.
Если шаблоны созданы и используются корректно, все работает. В работе шаблонов практически нет отклонений, способных вызвать сбой. Большинство ошибок - следствие синтаксических ошибок кода.
Работая на платформе Microsoft Windows, удостоверьтесь, что Mozilla
полностью завершила работу и выгружена из памяти после закрытия
последнего окна. Если используется неверно сформированный шаблон,
процесс может застрять в памяти и повлиять на последующие пробы. Если
такое случается - самый общий симптом состоит в том, что кажется,
будто изменения, вносимые в код XUL или JavaScript, не дают ожидаемого
эффекта. Безопаснее всего перестартовывать платформу каждый раз
заново. Если вы не отключили
Вторая <menu> и <tree>, остальные ведут себя
непредсказуемо и могут вызвать падение платформы.
Комбинация <tree>, описанное в лекции 13,
"Списки и деревья". Если хоть мельчайшая деталь некорректна,
шаблон не даст вовсе никакого результата, и не будет и намека, почему
так произошло. Очень важно все делать правильно с самого начала.
Создавая шаблон, всегда начинайте с тестовых данных во внешнем
Создав корректные данные, удостоверьтесь, что результат можно видеть в окне XUL.
Если шаблон не рекурсивен, создайте шаблон с базовым тегом <. Выведите что-нибудь в тег <description> или <label> без лишних "красивостей" в правилах. Как
только что-то осмысленное появится на экране, вы получаете по крайней
мере корень запроса и часть его правильной структуры. Даже если ваша
цель - сложный тег "дерево" со многими уровнями вложения,
начинайте сначала с <.
Если ваш источник данных - внутренний, прочитайте советы в лекции 16, "Объекты XPCOM", и извлеките максимум информации из данных на тестовую страницу. Некоторыми источниками данных можно управлять прямо из шаблона, остальные требуют скриптов. Нужно хорошо изучить порождаемый контент, иначе запрос шаблона не сработает.
Наконец, стройте запрос. Система запросов гибка, и может обработать
некоторые вариации контента внутри тега <template>, но вносить
их все же не рекомендуется. Чтобы избежать лишних хлопот, следуйте как
можно ближе к порядку тегов, приведенному в данной лекции. Хотя от него
и можно отступать, это может привести к некорректному преобразованию
шаблона и его переменных во внутреннюю форму. Тут перемена мест на
результат влияет, и еще как.
Если шаблон рекурсивен, вы не можете тестировать рекурсию без тегов <menu> или <tree>, но лишь первый уровень рекурсии. Чтобы
тестировать дальнейшие уровни, используйте <tree>, а не <menu>. Невозможно построить рекурсивно порожденное множество
меню единственным правилом <rule> - требуется, по крайней мере,
два.
Одно правило необходимо для элементов <menu>, другое - для
элементов <menuitem>. Так что для тестирования рекурсивных
запросов дерево - самый подходящий и простой механизм.
Только после того, как тестовый запрос даст ожидаемый результат,
начинайте работу с реальным виджетом. В случае дерева начинайте с
кода, приведенного в данной лекции, и обязательно следите за тем, чтобы
дерево имело первичную колонку. Необходимые детали можно добавить
позже. Внимательно просмотрите флаги и опции, которые можно добавить к
базовому тегу, некоторые из них жизненно важны. Автоматически добавьте flags="dont-build-content" и , если только
вы не знаете точно, что они не нужны.
Когда ваш шаблон заработает правильно, можно добавить скрипты его динамического поведения. Раздел 14.6.1, "Советы по созданию динамических шаблонов" содержит действительно важные советы. За пределами, описанными в этом разделе, поддерживается не слишком многое.
Наконец, обратите внимание на раздел "Источники данных"
лекции 16, "Объекты XPCOM". Если ваш источник данных
Система шаблонов Mozilla обрабатывает
Система сложна для изучения. Она использует новаторские концепции и массу подводных камней, и выдает слишком мало отладочной информации в процессе создания шаблона. Разнородные источники данных требуют каждый индивидуального подхода и усилий по их изучению, что также не упрощает работу.
Несмотря на проблемы первой версии платформы, шаблоны являются
очень мощным инструментом.
Для порождения и управления новым контентом XUL документа могут
быть использованы JavaScript и DOM.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.