W3C XForms (по-английски это слово употребляется как в единственном так и множественном числах) - это усовершенствованная версия HTML-форм, которая предоставляет расширяемые средства, позволяющие включать в HTML-документы более богатые и более динамичные формы. С помощью XForms можно ускорить и упростить создание Web-форм. XForms допускают поддержку многочисленных устройств и структурированных данных форм, как например XML-документы. Они избавляют разработчиков от необходимости писать скрипты, которые используются при генерировании динамических Web-форм, необходимых как для объединения многочисленных форм на одной и той же странице, так и управления данными. Наконец, хотя каждая часть XForms, а именно: модель данных (data model), вид (view) и контроллер (controller) - полностью отделима от других и может использоваться с другими технологиями, важно осознать, что мощь этих частей - в их объединении в приложении.
В этой статье рассматриваются некоторые наиболее полезные - с практической точки зрения - свойства XForms; также приводится пример одного простого приложения. Материал статьи опирается на Рабочий проект XForms 1.0, который был опубликован в июле 2002 года (см. Ресурсы).
Корни некоторых положений, реализованных в XForms, могут обнаружены в стандартном обобщенном языке разметки SGML (Standardized General Markup Language). SGML был разработан, чтобы отделить текстовое содержимое от его представления - для этого содержание заключалось в машиночитаемые теги. А это, помимо всего прочего, означало, что разработкой содержания и представления могли заниматься разные люди. Наконец, этот язык обеспечивал простоту в распространении и совместимости.
Язык гипертекстовой разметки HTML (Hypertext Markup Language), являющийся типом SGML-документа, также обрамляет содержимое в значимые теги. Однако, HTML отошел от принципа отделения содержимого от представления. Одновременно с превращением Internet в общедоступную технологию этот язык, благодаря тому, что он обеспечивал относительную простоту создания Web-страниц, получил практически повсеместное признание. В результате стандартизации HTML-тегов появился язык, который был понятен любому Web-браузеру. Однако, по мере того, как развитие бизнеса заставляло Web-разработчиков создавать более сложные динамические сайты, ограничения языка становились все более очевидными.
Листинг 1. Пример HTML-формы ...<!--Ellipsis represent parts that are
missing-->
<FORM action="http://www.example/ " method="post">
<P>
<INPUT type="radio"
name="HairColor" value="Brown">Brown<BR>
</P>
</FORM>
Обратите внимание на то, что name="HairColor" и value="Brown" в Листинге 1 установлены в пределах того же кода, что создает и пользовательский интерфейс. Кроме того, этот HTML-фрагмент жестко установленным образом программирует тип управляющего элемента - в данном случае радио-кнопки - который появится в пользовательском интерфейсе. Поэтому данная форма не могла бы корректно изобразиться на платформах, не поддерживающих радио-кнопки. Поскольку HTML-формы могут включать вложенные данные и жестко закодированные решения, изменения представления отдельной формы является непростой задачей. Кроме того, стандартизация HTML означала, что разработчик не мог расширить набор HTML-тегов, то есть возможность настраивать язык и улучшить его выразительность оказывалась ограниченной.
С целью решения указанных проблем были разработаны расширяемый язык разметки XML (Extensible Markup Language) и расширяемый язык стилей XSL (Extensible Stylesheet Language). В отличие от HTML, объединение XML-документов с XSL-преобразованиями позволяет отделить данные от их представления. Поля, такие как name и value, могут храниться как XML-данные, а представление может создаваться посредством преобразования XML-документа в HTML с помощью XSL-преобразования. Благодаря этому разработчики оказываются избавленными от множества жестко запрограммированных решений, которые неизбежны при использовании HTML-форм. Одни и те же XML-данные могут быть представлены самыми различными способами, как правило, для этого используются различные таблицы стилей XSL; и, наоборот, одиночное XSL-преобразование может изобразить неоднородный XML в единообразном стиле. Помимо этого, XML/ XSL предоставляет разработчикам расширяемость, которой HTML не обладает.
Однако, хотя HTML, генерированное путем применения XSL-преобразования к XML-содержимому, обладает целым рядом преимуществ по сравнению со статическим HTML, эта дополнительная функциональность имеет свою цену. Во-первых, сервер, выполняющий преобразование XML в HTML, не будет работать так же хорошо, как сервер, который обслуживает только статический HTML. Для самих преобразований необходимо несколько циклов работы сервера; кроме того, формы, возможно, потребуют несколько итераций обмена данными между клиентом и сервером. Во-вторых, разработка XML с XSL-преобразованием выдвигает особые требования к профессиональному уровню программиста, в данном случае нужно гораздо больше опыта, чем для работы с HTML.
Как было указано выше, появление спецификации XForms было вызвано потребностью в расширяемых средствах, позволяющих включать в HTML-документы более богатые и более динамичные формы, а также необходимостью ускорить и упростить создание Web-форм. XForms можно рассматривать как модуль расширения XHTML (форма HTML, согласующаяся с XML). Спецификация XForms определяет предопределенный набор тегов, элементов и атрибутов, которые упрощают построение Web-форм. Браузеры с XForms-процессорами могут изображать XForms на клиентских машинах. Благодаря этому, разработчики могут избежать расходов на исполнение, которые вызваны повторными обращениями к серверу с целью модификации Web-формы. (При желании, для преобразования XForms-документов в HTML вы можете также использовать серверный XForms-интерпретатор.) Важно то, что XForms выделяют модель данных формы, вид и контроллер. Далее, эти части раскладываются на уровни, которые допускают более совершенное многократное использование. Например, XForms дифференцируют вид формы на ее презентацию (presentation) и предназначение (purpose).
Модель данных XForms позволяет объявлять единицы данных и отделять структуру от любого набора элементов управления, используемых для отображения значений этих данных. XForms описывают средства связывания этих единиц данных с управляющими элементами отдельно от самого объявления режима данных. Помимо этого, для каждой отдельной единицы данных определяются декларативные средства поведения при изменении значений.
Элементы управления XForms по своей природе абстрактны, поэтому для их различных реализаций можно выбирать разные платформы. Например, если в HTML-тег <radioButton> может иметь только одну презентацию на платформах, в XForms элемент управления <select1> (см. Приложение C4) может быть "выпадающим" меню в PC-браузере или списком радио-кнопок в "карманном" компьютере (PDA). Однако, предназначение контрола <select1> останется тем же самым - пользователь получает возможность выбирать единственный элемент из набора элементов.
В этой статье мы покажем, как решать важнейшие задачи, используя всего лишь небольшое количество основных XForms-тегов. Мы рассмотрим использование и синтаксис этих тегов, а также смысл некоторых обычных атрибутов. Объяснение отдельных тегов будет сопровождаться ссылками на Приложения к статье, где приведена вся спецификация.
Для первого знакомства со структурой формы и синтаксисом XForms рассмотрим всем хорошо известный пример "Hello World". Этот пример позволяет сравнить XForms с другими языками разметки. В следующих разделах будут показаны части формы, предназначенной для выполнения заказа в среде электронной коммерции; эта форма будет рассматриваться на протяжении всей статьи.
В Листинге 2 приведен весь код "Hello World", на Рис. 1 показано, как может выглядеть этот пример при его отображении в окне браузера, совместимого с XForms. Обратите внимание на основную структуру этого документа, поскольку каждый XForms-документ имеет схожую разметку. Вы увидите, что модель определяется в пределах заголовка (см. XForms-модель), а представление в теле документа (см. Пользовательский интерфейс XForms). Заметьте, что пространства имен указываются в пределах каждого HTML-тега. Для того, чтобы избежать конфликта имен, необходимо, где только можно, использовать префиксы пространств имен.
Рис. 1. Изображение
Hello World
Обратите внимание на то, что поскольку в настоящий момент язык XForms не располагает процессором в виде готового продукта, изображения всех примеров - это всего лишь иллюстрации, которые не являются результатом реализации XForms. (Ссылки на бета-версии XForms- процессоров см. в Ресурсах.)
В остальной части статьи рассказывается о форме, используемой для выполнения заказа в среде электронной коммерции. Эта форма заказа состоит из разделов, предназначенных для ввода информации о клиенте, подсчета цены и перечисления приобретенных товаров. Сначала мы рассмотрим определение модели, а затем описание представления. В Приложении А приводится полный текст кода, на Рис. 2 показано изображение этой формы заказа.
Рис. 2. Изображение формы заказа
XForms предусматривают определение многочисленных моделей в пределах одной и той же формы. Это удобно, если вы хотите, чтобы одно приложение поддерживало множество функций. Например, личный портал может состоять из модели биржевого аппарата, модели календаря и так далее. Если вы описали множество моделей, можете воспользоваться атрибутом id, чтобы идентифицировать каждую из них. В Листинге 3 приведен скелет кода для формы заказа:
<HTML xmlns="http://www.w3.org/1999/xhtml"
xmlns:xforms=http://www.w3.org/2002/01/xforms
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xlink="http://www.w3.org/1999/xlink">
<head>
<title>XForms: Order
Form</title>
<xforms:model>
...
<!--Instance and Logical Components-->
</xforms:model>
</head>
<body>
... <!--User Interface goes here-->
</body>
</HTML>
Более подробная информация о XForms-модели приведена в Спецификации (см. Приложение B6).
Данные экземпляра определяются в пределах модели. Они представляют все ту информацию, которая передается в обработчик, и любое временное хранилище, которое необходимо в пределах модели. Каждый экземпляр, однако, может содержать только одиночное дерево XML-данных - другими словами, может быть только один корневой узел.
Экземпляр определятся локально в пределах модели или указывает с помощью URI на существующие XML-данные, хранящиеся на удаленной машине. В Листинге 4 показан экземпляр, OrderInfo, определенный локально в форме заказа.
<xforms:model>
<xforms:instance>
<OrderInfo>
<PersonalInfo>
<Name>
<First></First>
<Middle></Middle> <Last></Last>
</Name>
<Address>
<Street></Street>
<City></City> <State></State>
<Zip></Zip>
</Address>
</PersonalInfo>
<PriceInfo>
<SubTotal></SubTotal>
<TaxTotal></TaxTotal>
<TaxRate></TaxRate>
<Total></Total>
</PriceInfo>
<TaxInfo>
<CT>.060</CT>
<NY>.085</NY>
<NJ>.083</NJ>
</TaxInfo>
<ShoppingCart>
<ProductInfo
name="itm1">
<Quantity>5</Quantity>
<Description>Wht.
Chocolate Bars</Description>
<UnitPrice>1.45</UnitPrice>
<ItemTotal></ItemTotal>
</ProductInfo>
<ProductInfo
name="itm2">
<Quantity>8</Quantity>
<Description>Blk.
Chocolate Bars</Description>
<UnitPrice>1.45</UnitPrice>
<ItemTotal></ItemTotal>
</ProductInfo>
<ProductInfo
name="itm3">
<Quantity>2</Quantity>
<Description>Car.
Filled Choc</Description>
<UnitPrice>1.80</UnitPrice>
<ItemTotal></ItemTotal>
</ProductInfo>
</ShoppingCart>
</OrderInfo>
</xforms:instance>
...
</xforms:model>
OrderInfo, приведенный в Листинге 4, состоит из четырех основных компонентов:
Как правило, под данными формы принято понимать информацию, которую пользователь вводит в форму. Тем не менее, разделы PriceInfo и TaxInfo демонстрируют, что данные экземпляра можно использовать и как временные переменные, и как постоянную информацию, соответственно.
В Листинге 5 показано, как можно реализовать экземпляр при обращении к удаленному XML-ресурсу.
<xforms:model>
<xforms:instance
href="http://www.example.com/OrderFormData.xml"/>
...
</xforms:model>
Более подробная информация о данных экземпляра приведена в Спецификации (см. Приложение B5).
Существует два способа присвоения значений данным экземпляра в XForms: данные могут зависеть от других данных, либо данные могут быть связаны с входными данными, предоставляемыми пользователем. В этом разделе рассмотрен первый способ; второй - связывание входных данных пользователя - в Пользовательском интерфейсе XForms.
В пределах модели определяется тег <bind>; он позволяет сделать данные экземпляра зависящими от других данных. Например, инструкция в Листинге 6 связывает TaxTotal с вычисляемым налогом (TaxRate умножается на SubTotal):
<!--Within the Model-->
<xforms:bind ref="/OrderInfo/PriceInfo/TaxTotal"
calculate="/OrderInfo/PriceInfo/TaxRate *
/OrderInfo/PriceInfo/SubTotal"/>
Атрибут ref ссылается на узел, который вы желаете связать - TaxTotal. Атрибут calculate определяет значение, которое вы желаете связать с этим узлом; в данном случае вы связываете TaxTotal с произведением TaxRate и SubTotal. Кроме умножения calculate поддерживает и другие простые функции (полный список см. в Приложении D).
Вы можете воспользоваться атрибутом relevant для определения условий, при которых тег bind является допустимым и должен применяться. Например, вы можете связать TaxRate, как показано в Листинге 7:
<!--Within the Model-->
<xforms:bind ref="/OrderInfo/PriceInfo/TaxRate"
calculate="/OrderInfo/TaxInfo/CT"
relevant="/OrderInfo/PersonalInfo/Address/State =
'CT'"/>
Вы можете также использовать тег <bind> для различных ограничений данных экземпляра, например, указав тип данных с помощью атрибута type. В Листинге 8 показано, как сделать так, чтобы поле SubTotal было десятичным числом:
Листинг 8.
Инструкция bind и ограничение типа
<!--Within the Model-->
<xforms:bind ref="/OrderInfo/PriceInfo/SubTotal"
type="xsd:decimal"/>
Существуют и другие способы ограничения данных экземпляра; полный список см. в Приложении E. XForms-процессор сверяет данные экземпляра с ограничениями, проверяя поле за полем. Если пользователь вводит данные, которые нарушают любое из ограничений, браузер, поддерживающий XForms, немедленно сообщит об этом пользователю. Благодаря этому, существенно повышаются удобство и простота использования, а обработчик получает только правильно оформленные данные.
Более подробная информация о связываниях, зависимостях и ограничениях приведена в Спецификации (см. Приложение B5).
Модель формы заказа была бы неполной без описания способа связи с сервером обработчика. Вы можете использовать тег <submission> и атрибут action, чтобы указать, какой вызов необходимо запустить при готовности пользователя к инициализации (см. Листинг 9):
<!--Within the model-->
<xforms:submission id="submit1" action="http://www.example/"
method="post"/>
В пределах одной и той же модели может быть множество блоков <submission>. Поэтому необходимо задать каждому тегу уникальный идентификатор с атрибутом id (например, id="sub"), поскольку в пользовательском интерфейсе эти теги будут связаны с кнопками submit (см. submit).
Более подробная информация о <submission> приведена в Спецификации (см. Приложение B9).
group - это простейший составной контрол: это основной контейнер, который группирует контролы. В Листинге 10 показано, как группировать различные контролы формы, чтобы затем использовать эту группу в качестве объекта на большой форме электронной коммерции.
Листинг 10. Скелет фрагмента формы, содержащей адрес<body>
<xforms:group>
<!--AddressForm form
controls goes here-->
</xforms:group>
</body>
Более подробная информация о group приведена в Спецификации (см. Приложение B3).
С помощью тега <repeat> можно уменьшить величину избыточного кода в форме - для этого разработчики могут применить шаблон пользовательского интерфейса к набору данных экземпляра с тем же типом и структурой. В примере формы заказа мы использовали тег <repeat> для отображения приобретенных товаров (см. Рис. 3).
Листинг
11. Пример использования инструкции repeat
<xforms:repeat id="shoppingcart"
nodeset="OrderInfo/ShoppingCart/ProductInfo">
<xforms:output
ref="Quantity"/>
<xforms:output
ref="Description"/>
<xforms:output
ref="UnitPrice"/>
<xforms:output
ref="ItemTotal"/>
</xforms:repeat>
В Листинге 11 атрибут nodeset элемента repeat определяет XPath, который оценивается по экземпляру модели. Элемент repeat затем "итерирует" к каждому контролу, сгруппированному в nodeset.
В Листинге 11, атрибут ref ссылается на значения полей в поддереве ProductInfo. Вы можете также сослаться на значения атрибута, предварительно пометив XPath символом @. Например, вы могли бы обратиться к атрибуту name в каждом ProductInfo посредством следующего вызова:
ref = "@name"
Разработчики могут воспользоваться тегом <repeat>, чтобы сделать свои XForms-документы более короткими и более "заточенными" под реальный экземпляр данных. Таким образом, этот тег также повышает выразительную мощь языка XForms: вам не нужно точно знать, сколько товаров приобретено; тег автоматически обойдет дерево экземпляра и выдаст данные для каждого возможного соответствия.
Более подробная информация о <repeat> приведена в Спецификации (см. Приложение B8).
Инструкция <switch> предназначена для динамической генерации пользовательского интерфейса. В пределах инструкции <switch> находятся инструкции <case>, которые определяют условия, при которых может использоваться другой пользовательский интерфейс. Например, при работе с формой электронной коммерции по получении личной информации поставщики могут захотеть установить метод платежа. Тег <switch> может быть использован для перехода к типу платежа, который выбрал пользователь. Если пользователь избрал платеж с помощью кредитной карты, отображается динамически сгенерированный набор контролов пользовательского интерфейса. Если же пользователь решил платить наличными или выбрал еще какой-нибудь иной способ, форма генерирует другой набор визуальных компонентов. Таким образом, тег <switch> позволяет пользователю управлять интерфейсом.
Более подробная информация о <switch> приведена в Спецификации (см. Приложение B11).
Элементарные контролы - это базовые компоненты, которые используются для разработки пользовательского интерфейса. Вы можете комбинировать эти контролы с тремя высокоуровневыми контролами, описанными выше. Давайте рассмотрим некоторые элементарные контролы.
Наиболее общим контролом формы является тег <input>. Как было указано в разделе Связывания, зависимости и ограничения это один из способов связать с экземпляром данные, предоставляемые пользователем. Пример тега <input> в форме адреса приведен в Листинге 12:
<!--In the User Interface-->
<xforms:input class="ZipCode" id="zipcode"
ref="OrderInfo/PersonalInfo/Address/ZipCode">
</xforms:input>
Атрибут ref задает XPath, с которым должны быть связаны входные данные. Поскольку атрибут ref использует XPath, чтобы установить расположение экземпляра, в случае совпадения множества узлов (например, многочисленных узлов /AddressInfo/Address/Zip), этот атрибут выбирает первое совпадение, если только разработчик не установил явно, какой индекс выбирать. В нашем примере значение, которое пользователь вводит в первое поле ввода, связано с /OrderInfo/PersonalInfo/Address/ZipCode. Чтобы добавить заголовок поля ввода необходимо создать потомок <label> тега <input>. (Обратите внимание на то, что тег <label> является одним из немногих факультативных тегов, которые могут быть созданы в пределах каждого контроля формы. Полный список этих тегов приведен Приложении F.)
Более подробная информация о <input> приведена в Спецификации (см. Приложение B4).
<output> просто изображает значения данных экземпляра. В примере, приведенном в Листинге 13, вы можете использовать контрол <output>, чтобы распечатать вычисленный налог:
<!--In the User Interface-->
<xforms:label class="label">Tax Amount $</xforms:label>
<xforms:output class="Amount" id="taxtotal"
ref="OrderInfo/PriceInfo/TaxTotal" />
Более подробная информация о <output> приведена в Спецификации (см. Приложение B7).
Атрибут event устанавливает, к какому событию должен "прислушиваться" тег <action>. В Листинге 14 показано, как в форме заказа определяется действие refreshForm.
Листинг 14. Инструкция action<!--In the User Interface or embedded in a UI form control-->
<xforms:action event="click" >
<xforms:refresh ev:event="xforms:activate"/>
</xforms:action>
При событии event обработчик событий перехватывает это событие и генерирует действие <refresh>.
В пределах одного и того же тега <action> можно иметь множество действий. Когда обработчик событий активирован, он вызывает все действия, определенные в пределах своего тела. (Полный список декларативных действий XForms приведен в Приложении G.) При размещении внутри тега <action> эти общие действия позволяют клиентским браузерам генерировать контекст в ответ на событие, вызванное пользователем. Теги <action> могут быть также определены в пределах модели. В следующем разделе объясняется, как встроить тег <action> в контрол формы.
Более подробная информация о <action> приведена в Спецификации (см. Приложение B1).
trigger - это контрол пользовательского интерфейса, который выполняет действие при активации. Например, это могут быть кнопки, которые реагируют на щелчок мышки. При активации trigger вызывает XML-событие, которое перехватывается обработчиком событий и которое описано с помощью тега <action>. Вы можете определить trigger, задав инструкцию, как показано в Листинге 15:
<!--In the User Interface-->
<xforms:trigger>
<label>My Refresh Trigger</label>
</xforms:trigger>
Этот trigger, однако, ничего не делает. Для того, чтобы он что-нибудь выполнил, необходимо встроить его вместе действием, подобным тому, что было определено в action (см. Листинг 16).
<!--In the User Interface-->
<xforms:trigger>
<xforms:label>Reset</xforms:label>
<xforms:action event="click" >
<xforms:refresh
ev:event="xforms:activate"/>
</xforms:action>
</xforms:trigger>
Более подробная информация о <trigger> приведена в Спецификации (см. Приложение B12).
Более подробная информация <submit> приведена в Спецификации (см. Приложение B10).
С помощью XForms вы можете определять Web-формы, отделив предназначение от представления. Вы сможете уделять больше внимания содержанию и собираемым данным, а не стилю представления. Этот язык описывает мощную модель событий и устраняет необходимость в специальных скриптах, используемых для выполнения простых, связанных с формой задач.
Благодаря XForms разработчики могут сосредоточить свои усилия в первую очередь на данных, которые необходимо собирать. Использование стандартных XML-схем позволяет явно определить структуру и тип данных. XForms расширяют эту модель, включив в спецификацию дополнительные ограничения и зависимости. XForms-процессор оценивает и реализует эти ограничения, не испытывая необходимость в дополнительном коде. Процессор проверяет типы данных и ограничения до того, как эти данные представлены для обработки.
Спецификация XForms также предусматривает создание динамических форм посредством задания условий, зависящих от данных. Вам больше не нужно писать специальный код, который будет генерировать пользовательские формы, основываясь на отклике пользователей. XForms могут настраивать формы "на лету" при сборе данных и изменении условий.
Навигация по XForms обрабатывается моделью событий XForms, которая не зависит от того, как она изображается на клиентской машине. Так, вы можете представить на одной клиентской машине XForms как отдельную страницу, и на другой - как множество станиц, не заботясь при этом о сохранении состояния и представлении соответствующих контролов для навигации.
Благодаря краткой спецификации и мощным функциональным возможностям, формы, созданные с XForms, легче поддерживать по сравнению с обычными Web-формами. Также отсутствует необходимость в дополнительном коде, предназначенном для проверки типа данных. Структура данных оказывается выведенной из разметки представления формы.
Независимо от того, являются ли XForms в действительности окончательным решением для разделения предназначения и представления, XForms на самом деле являются следующим поколением Web-форм.