Оригиналы статей
Редактирование XML-данных через Web при помощи W3C XML Schema и XSLT
W3C XML Schema (WXS) - основанный на XML язык для описания и конструирования содержимого XML-документов. Стандартной практикой становится использование WXS для валидации данных в XML-документах. Также при помощи схем мы можем выполнять смежную задачу: создавать или редактировать корректное содержание XML-документа, используя информацию из схемы.
В этой статье описано, как содержимое XML-документа может быть отредактировано через автоматически созданный основанный на формах GUI, причем процесс основывается на схеме данных документа. Здесь представлен полный цикл создания GUI (с использованием XSLT), редактирования и обновления (с использованием XUpdate) XML-данных.
Следующая схема иллюстрирует общую идею: содержимое XML-документа, которое можно редактировать через GUI, созданный по соответствующей схеме.
Схема 1. Предполагаемая схема системы. |
Первое, о чем следует подумать, это прямая трансформация схемы через процессор (например, XSL-процессор) в GUI.
Схема 2. Прямая трансформация XMLSchema в основанный на формах GUI |
Схема (помечена как XSD) преобразована через процессор в GUI. Процессор создает поле ввода для каждого (простого) элемента, встречающегося в XSD-документе. Возможный подход к такому варианту действий был изложен в статье Transforming XML Schemas, в которой рассматривалось преобразование XSD в основанный на формах GUI с использованием XSLT.
В этой статье приводится полная концепция решения вопроса с веб-интерфесом GUI, следовательно, сервлет можно использовать для полчения и обработки данных, вводимых пользователем. После того, как схема обработана, пользователь может ввести данные в поля ввода, и данные посылаются сервлету. Затем сервлет использует эти входящие данные для создания XML-документа, который будет проверен на корректность по исходной схеме.
Ограниченность этого варианта проявляется в том, что он работает только при создании нового XML-документа с данными, и процессор только трансформирует схему в GUI. Уже существующие XML-данные нельзя редактировать, поскольку процессор не знает о трансформации XML-данных в GUI.
Нам требуется процессор, способный взять XML-документ с данными и создать основанный на формах GUI, чтобы можно было редактировать документ. См. следующую схему.
>Схема 3. Редактирование XML-данных. |
На схеме 3 отражена следующая концепция: вместо трансформации схемы прямо в GUI, процессор сделает XSLT-файл, который мы назовем XSLGUI. Эта стилевая таблица содержит информацию о том, как именно трансформировать XML-данные корректно при помощи схемы в основанный на формах GUI.
Чтобы понять на примере, как работает эта концепция, представим, что у нас есть схема Person.xsd, определяющая элементы, описывающие личность человека (нпр., name, last_name, ...):
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema version="1.0"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="person">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="phone" type="xsd:string"
minOccurs="1" maxOccurs="3"/>
<xsd:element name="date_of_birth"
type="xsd:date"/>
<xsd:element name="course" minOccurs="0"
maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="course_name"
type="xsd:string"/>
<xsd:element name="start_date"
type="xsd:date"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Представим также, что у нас также есть документ с данными, описывающими человека по имени Марк (Marc.xml), и этот документ использует Person.xsd:
<?xml version="1.0" encoding="UTF-8"?>
<person
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="Person.xsd">
<name>Marc</name>
<phone>0153816546</phone>
<phone>0630458920</phone>
<date_of_birth>1978-01-21</date_of_birth>
<course>
<course_name>TCP/IP</course_name>
<start_date>2001-12-10</start_date>
</course>
<course>
<course_name>Java Programming</course_name>
<start_date>1997-08-01</start_date>
</course>
</person>
Цикл, показанный на схеме 3, использует Person.xsd для создания XSLT-файла (XSLGUI), который способен создать GUI из элементов, найденных в Marc.xml.
Существует много способов, как XSLGUI может сделать основанный на формах GUI из файла с исходными данными. Первый способ - использовать XForms, имеющий сейчас статус кандидата в рекомендации W3C. XSLGUI должен в этом случае создать правильный XML-документ XForms, основанный на XML-документе с данными (e.g Marc.xml). Однако использование XForms означает, что броузер должен поддерживать XForms, и т.к. XForms еще не является рекомендацией, наиболее распространенные броузеры его не используют.
Второй способ - Apache Cocoon XMLForm. Основное отличие между Cocoon XMLForm и W3C XForms в том, что XMLForm можно использовать в любом броузере на любом клиентском устройстве, в то время как Cocoon не требует, чтобы на стороне клиента распознавалась XForms-разметка (см. XML Forms, Web Services and Apache Cocoon).
Возможный третий способ, представленный в этой статье, есть комбинация XPath, XUpdate и W3C XML Schema validation. Причина, по которой мы выбрали этот способ, в том, что он не зависит от броузера (броузеры пока еще не поддерживают XForms) или от использования Cocoon (если вы выбираете XMLForms, вы должны использовать Cocoon).
Автор - Ali Mesbah
Для каждого (простого) элемента в Marc.xml (нпр., name, last_name, ...) XSLGUI создаст поле ввода. В основанном на броузере GUI поля ввода имеют атрибуты name и value, и только эти два параметра мы можем послать нашему сервлету. Следовательно, XSLGUI устанавлиает параметр name для каждого элемента формы, который соответствует XPath-позиции этого элемента в XML-документе, в порядке обработки структуры данных в этом документе. Например, HTML-тег input для второго телефонного номера в нашем документе Marc.xml будет выглядеть так:
<input name="/person/phone[2]" value="0630458920"/>
Согласно документу W3C "Basic HTML data
types", атрибут name
тега input
должен начинаться с буквы, поэтому строку "/person/phone[2]" недопустимо использовать как значение атрибута name тега input
. Мы протестировали эту систему записи в сервлете под Tomcat, и она работает. Однако можно заменить симол "/" на какой-нибудь другой допустимый символ, а на серверной стороне провести обратное преобразование в корректный XPath.
В процессе создания этого XPath необходимо, чтобы XSLGUI отслежиал путь к местонахождению и числу элементов в нашем XML-документе. Далее показаны части нашего сгенеренного XSLGUI. Для всех некомплексных элементов создается
match (???), подобный аналогичному для "phone". Строка пути, показывающая позицию текущего элемента в каждом match, приводится, если надо, в стандартный вид и обрабатывается рекурсивно. Число вхождений каждого элемента также подсчитывается и используется как индекс в XPath-нотации. Для course
, являющегося complexType
-элементом, напрямую полей ввода не создается, но параметр path передается его потомкам при вызове apply-template
.
Ниже - краткое представление документа XSLGUI:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="person">
<xsl:param name="root">/person</xsl:param>
<html>
<head>
<title>person</title>
</head>
<body>
<form name="xmsForm" action="xms.InputPage" method="post">
<xsl:apply-templates>
<xsl:with-param name="path" select="$root"/>
</xsl:apply-templates>
<input type="submit" name="action" value="save"/>
</form>
</body>
</html>
</xsl:template>
...
<xsl:template match="phone">
<xsl:param name="path"/>
<xsl:variable name="index">
<xsl:number count="phone"/>
</xsl:variable>
<B>phone: </B>
<!-- Нижеследующее выводится так:
<input name="/person/phone[2]" value="0630458920"/> -->
<input>
<xsl:attribute name="name">
<xsl:value-of
select="concat($path,'/phone[', $index,']')"/>
</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="text()"/>
</xsl:attribute>
</input>
</xsl:template>
...
<xsl:template match="course">
<xsl:param name="path"/>
<xsl:variable name="index">
<xsl:number count="course"/>
</xsl:variable>
<B>course </B>
<xsl:apply-templates select="*">
<xsl:with-param name="path"
select="concat($path,'/course[', $index,']')"/>
</xsl:apply-templates>
</xsl:template>
...
</xsl:stylesheet>
Как мы видим, каждое создаваемое поле ввода в качестве "имени" использует свою XPath-адресацию, которая описывает точную позиию этого элемента в XML-документе с данными. Представим, что пользовватель изменяет значение второго телефонного номера с 0630458920 на 0150458920. Когда пользователь запрашивает сохранение данных, сервлет получает введенную информацию.Теперь он должен пройти в цикле по всем веденным полям, чьи имена - корректно записанные XPath-выражения, и создать XUpdate-документ. Для второго телефонного номера серер получает параметр с
name="/person/phone[2]"
и value="0150458920"
XUpdate-документ с командой update
может быть таким:
<?xml version="1.0" encoding="UTF-8"?>
<xu:modifications
xmlns:xu="http://www.xmldb.org/xupdate">
<xu:update select="/person/phone[2]">
0150458920
</xu:update>
</xu:modifications>
После того, как для всех введенных данных будет создан XUpdate-документ, копия исходного документа Marc.xml будет использована для обновления исходного документа при помощи JAXUP, который определяет интерфес обновления XML-документов и обеспечивает реализациюXUpdate-спецификации, предложеной инициативной группой XML:DB.
После этого проводится проверка копии на корректность (валидация). Если документ валиден, он сохраняется на место оригинального, в противном случае пользователю возвращаются ошибки.
Мы уже обсуждали процессор, который берет WXS-схему и производит требуемую трансформацию в "XSLGUI". Процессор может быть каким угодно, лишь бы он был в состоянии выдавать необходимую информацию. Например, комбинация DOM и Java может быть процессором. В нашем случае процессор - фактически комбинация XSLT-документов и преобразований, как видно из следующей схемы.
Схема 5. XML Schema для процессора XSLGUI. |
Все, что нам нужно - это XSLT-стиль, который берет наш XSD и трансформирует его в соответствующий XSLGUI. Назовем этот стиль "MetaXSLGUI".
Основная задача MetaXSLGUI состоит в следующем:
Для каждого элемента создать xsl:template
с атрибутом
match
, эквивалентным имени элемента.
Если это complexType-элемент, то добавить в шаблон функцию xsl:apply-templates
select="*"
с соответствующими параметрами.
Добавить правильные XSLT-функции и элементы в xsl:template
из шага 1 так, чтобы xsl:template
при необходимости мог создать необходимые элементы для ввода.
Этот пример кода показывает, как может выглядеть возможный MetaXSLGUI. В W3C XML Schema есть много возможностей, и хотя достаточно сложно создать стиль, который учитывает все эти возможности, теоретически это возможно. Это всего лишь вопрос времени, которое уйдет на создание стиля с такой функциональностью. Мы надеемся, что этот простой MetaXSLGUI может послужить началом движения в этом направлении.
В этой статье была кратко описана новая перспектива создания основанного на формах GUI, использующая XML Schema и единственный XSLT-стиль, при помощи которых возможно редактирование XML-данных. Конечно, некоторые темы остались открытыми, например, как добавить новый элемент в документ с данными, как инициировать минимальную структуру данных по схеме. Эти вопросы будут обсуждаться в одной из следующих статей.
Дополнительная информация
|
Редактирование XML-данных через Web при помощи W3C XML Schema и XSLT, часть 2
В предыдущей статье мы обсуждали способ автоматической генерации основанного на формах GUI с использованием XML Schema -- способ, который использует только один XSLT-стиль, с помощью которого становится возможным редактирование XML-данных. Остались открытыми такие вопросы, как добавление нового элемента в документ с данными, а также создание (инициализация) первичной структуры данных по нашей схеме.
Один из самых распространенных способов использования схем - проверка XML-документа на корректность по определенным правилам. Схемы также используют для того, чтобы задать порядок следования элементов или их тип. Ткже мы можем определить приоритет, важность элементов в схеме. Эту информацию можно использовать для того, чтобы вставлять или удалять элементы документа, сохраняя при этом его корректность.
В этой статье описывается способ вставки элементов в xML-документ через автоматически сгенеренный основанный на формах GUI, использующий XML Schema документа данных.
В предыдущей статье была описана концепция редактироания существующего документа с использованием соответствующей ему схемы. Эта концепция представлена на следующей схеме.
Схема 1. Редактирование XML-данных
В этой концепции значения элементов документа можно редактировать, но она не обеспечивает способа вставить или удалить элемент документа.
Рассмотрим предыдущий пример (с некоторыми изменениями, выделенными жирным шрифтом) схемы (ранее помеченной как XSD) Person.xsd, в которой мы определили элементы, описыващие личность, плюс вложенность (важность? обязательность?) каждого элемента:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema version="1.0"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="person">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name"
type="xsd:string"/>
<xsd:element name="phone"
type="xsd:string"
maxOccurs="3"/>
<xsd:element name="date_of_birth"
type="xsd:date"/>
<xsd:element name="course"
minOccurs="0"
maxOccurs="3">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="course_name"
type="xsd:string"/>
<xsd:element name="course_code"
type="xsd:string"
minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Представим также, что мы уже опять создали документ, описывающий воображаемую персону по имени Marc (Marc.xml) при помощи Person.xsd:
<?xml version="1.0" encoding="UTF-8"?>
<person
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="Person.xsd">
<name>Marc</name>
<phone>
0153816546
</phone>
<phone>
0630458920
</phone>
<date_of_birth>
1978-01-21
</date_of_birth>
<course>
<course_name>
TCP/IP
</course_name>
<course_code>
T465
</course_code>
</course>
<course>
<course_name>
Java Programming
</course_name>
<course_code>
J867
</course_code>
</course>
</person>
Допустим, у нас есть документ с данными, в котором содержатся несколько элементов одного типа. Мы хотим вставить еще один элемент этого типа в документ. Общая идея вставки документа через GUI описывается так:
Теперь, используя пример, мы можем выработать концепию, которая может применяться с использованием XSLT и XML Schema.
В примере Person.xsd мы определили элемент course
как имеющий параметр minOccurs
, равный нулю, и параметр maxOccurs
, равный 3. Т.о., в Marc.xml элемент courses может встречаться 3 раза.
Имея в схеме эту информацию о допустимом числе элементов, мы могли бы захотеть найти способ вставить элементы в XML-файл через GUI, сохранив при этом корректность документа с данными.
Чтобы получить возможность вставлять элементы, мы будем использовать "кардинальность"
(minOccurs
и maxOccurs
), определенную в XSD, и ставить знак "+" после каждого элемента, кардинальность которого выше, чем число элементов, представленных в документе с XML-данными. Например, для Marc.xml GUI поставит "+" после каждого course, потому что в
Marc есть два course, а значение атрибута maxOccurs
элемента course
равно 3.
Авторы - Ali Mesbah, Arjan Vermeij
Первое, что мы должны сделать, это расширить MetaXSLGUI, представленный в предыдущей статье, таким образом, чтобы сгенеренный XSLGUI знал, где и когда ставить "+". Вот так может выглядеть XSLGUI после такого расширения:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
...
<xsl:template match="course">
<xsl:param name="path"/>
<xsl:variable name="index">
<xsl:number count="course"/>
</xsl:variable>
<xsl:variable name="maxOccurs" select="3"/>
<xsl:variable name="nodeCount"
select="count(../course)"/>
<b>course </b>
<xsl:if test="$nodeCount < $maxOccurs">
<a>
<xsl:attribute name="href">
<xsl:value-of
select="concat('javascript:submitForm(',
"'",$path,
'/course[', $index,']',
"'", ',',
"'",'insert',
"'",');')"/>
</xsl:attribute>
<xsl:attribute name="onClick">
<xsl:value-of
select="concat('submitForm(',"'",
$path,'/course[', $index,
']', "'", ',',
"'", 'insert',
"'", ');
return false;')"/>
</xsl:attribute>
+
</a>
</xsl:if>
<xsl:apply-templates select="*">
<xsl:with-param name="path"
select="concat($path,'/course[', $index,']')"/>
</xsl:apply-templates>
</xsl:template>
...
<xsl:template match="phone">
<xsl:param name="path"/>
<xsl:variable name="index">
<xsl:number count="phone"/>
</xsl:variable>
<xsl:variable name="maxOccurs" select="3"/>
<xsl:variable name="nodeCount"
select="count(../phone)"/>
<b>phone: </b>
<!-- The output of the following will look like
this: <input name="/person/phone[2]"
value="0630458920"/>
-->
<input>
<xsl:attribute name="name">
<xsl:value-of
select="concat($path,'/phone[',
$index,']')"/>
</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="text()"/>
</xsl:attribute>
</input>
<xsl:if test="$nodeCount < $maxOccurs">
<!-- The output of the following will look
like:
<a href="javascript:submitForm(
'/person/phone[2]',
'insert');"
onClick="submitForm('
/person/phone[2]',
'insert');
return false;">
+</a>
-->
<a>
<xsl:attribute name="href">
<xsl:value-of
select="concat('javascript:submitForm(',
"'",$path,
'/phone[', $index, ']',
"'", ',',
"'", 'insert',
"'", ');')"/>
</xsl:attribute>
<xsl:attribute name="onClick">
<xsl:value-of
select="concat('submitForm(',"'",
$path,'/phone[', $index,']',
"'", ',',
"'", 'insert',
"'",');
return false;')"/>
</xsl:attribute>
+
</a>
</xsl:if>
</xsl:template>
...
</xsl:stylesheet>
Это - расширенный MetaXSLGUI.
Значение атрибута maxOccurs
в XSD используется в шаблоне элемента. При каждом прогоне (match) число элементов в данном месте документа подсчитывается и устанавливается значением nodeCount
. Потом проверяется, действительно ли nodeCount
меньше, чем атрибут maxOccurs
элемента. Если это так, элемент получает свой плюс. После этого знак "+" залинковывается на ссылку, отправляющую нашу форму с соответствующими параметрами. (Мы могли бы использовать этот же прием для проставления минуса и удаления элемента из структуры данных.)
Когда пользователь кликает на знак "+" рядом со вторым course, на сервер отправляется запрос с XPath-позицией вставляемого элемента. Можно вставлять элемент до или после элемента с плюсом. В этом примере мы вставляем новый элемент перед элементом с плюсом. Используя нотацию XPath, мы знаем, что новый элемент course должен быть вставлен перед вторым course
в элементе
person
. Сервер создает документ XUpdate с командой "вставки перед":
<?xml version="1.0" encoding="UTF-8"?>
<xu:modifications
xmlns:xu="http://www.xmldb.org/xupdate">
<xu:insert-before select="/person/course[2]">
<insert-course/>
</xu:insert-before>
</xu:modifications>
Мы вставляем не сам элемент course, а элемент insert-course
. Причины этого в том, что на стороне сервера мы не знаем ничего о структуре вставляемого элемента. Все, что нам известно из пришедшего запроса, это то, что пользователь хочет вставить элемент course
перед уже имеющимся вторым элементом course
(/person/phone[2]
).
Этот XUpdate выполняется на временной копии исходного документа с данными (Marc.xml). Теперь у нас есть XML-документ (обозначим его как XML+) с дополнительным тегом, не определенным в нашем XSD, и являющимся просто дополнительным временным тегом:
<?xml version="1.0" encoding="UTF-8"?>
<person
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="Person.xsd">
<name>Marc</name>
<phone>0153816546</phone>
<phone>0630458920</phone>
<date_of_birth>1978-01-21</date_of_birth>
<course>
<course_name>TCP/IP</course_name>
<course_code>T465</course_code>
</course>
<insert-course/>
<course>
<course_name>Java Programming</course_name>
<course_code>J867</course_code>
</course>
</person>
См. следующий рисунок:
Схема 2. Вставка элементов
Чтобы получить возможность трансформировать XML+ в XML, необходимо иметь XSLT с информацией о том, как заменить тег <insert-elementName/>
на тег элемента, который он представляет. Этот XSLT (назовем его XSL+) создан с использованием XSD. В этом XSLT для каждого элемента из XSD создан соответствующий match с элементом(ами), который должен заменить insert-тэг в XML+.
В XSL+ есть функция подстановки insert-тэга с сохранением исходной структуры и значений прочих элементов.
Ниже показаны части XSL+:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="person">
<xsl:element name="person">
<xsl:apply-templates select="*"/>
</xsl:element>
</xsl:template>
...
<xsl:template match="insert-phone">
<xsl:element name="phone"/>
</xsl:template>
<xsl:template match="insert-course">
<xsl:element name="course">
<xsl:element name="course_name"/>
</xsl:element>
</xsl:template>
<xsl:template match="insert-person">
<xsl:element name="person">
<xsl:element name="name"/>
<xsl:element name="date_of_birth"/>
<xsl:element name="phone"/>
</xsl:element>
</xsl:template>
...
</xsl:stylesheet>
XML+ с тегом insert-course
будет трансформирован в корректный документ, отличающийся от исходного XML-документа только наличием дополнительного элемента course
. Marc.xml будет выглядеть примерно так:
<?xml version="1.0" encoding="UTF-8"?>
<person
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="Person.xsd">
<name>Marc</name>
<phone>0153816546</phone>
<phone>0630458920</phone>
<date_of_birth>1978-01-21</date_of_birth>
<course>
<course_name>TCP/IP</course_name>
<course_code>T465</course_code>
</course>
<course>
<course_name/>
</course>
<course>
<course_name>
Java Programming
</course_name>
<course_code>
J867
</course_code>
</course>
</person>
В элемент course
добавлен только элемент course_name
. Это потому, что у course_name
в схеме параметр minOccurs равен 1 (значение по умолчанию), а у course_code
параметр minOccurs равен 0, что означает, что это не обязательный элемент. После проверки на корректность этот XML-документ может быть трансформирован в
GUI с использованием XSLGUI, как и любой другой документ с данными.
Авторы - Ali Mesbah, Arjan Vermeij
Все, что нам нужно - это XSLT, берущий наш XSD и преобразовывающий его в соответствующий XSL+. Здесь применяется та же концепция, что использовалась для создания XSLGUI. Стиль, генерящий XSL+, назовем MetaXSL+.
Схема 3. Преобразование XML Schema в XSL+
Основная задача MetaXSL+ состоит в следующем:
xsl:template
с атрибутом
match
, эквивалентным имени элемента.
xsl:template
xsl:apply-templates
select="*"
xsl:template
с атрибутом match
, равным insert-elementName
, где elementName - название элемента.
Как мы видим, XSL+ может трансформировать тэг insert-elementName
в соответствующийй элемент с правильным содержимым. Теперь создание документа с данными по схеме Person.xsd есть не что иное как тег insert-person
. Все, что нам нужно - это XSLT, который находит первый элемент в нашем XSD (person) и создает XML+, в котором содержится только одна строка, а именно:
<insert-person>
Это делает следующий XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="xsd:element">
<xsl:variable name="inserttag"
select="concat('insert-', @name)"/>
<xsl:element name="{$inserttag}"/>
</xsl:template>
</xsl:stylesheet>
Используя тот же цикл, что описан выше, этот новый XML+ трансформируется в документ с данными при помощи XSL+. Результатом будет следующий код:
<xsl:element name="person">
<xsl:element name="name"/>
<xsl:element name="date_of_birth"/>
<xsl:element name="phone"/>
</xsl:element>
Это - минимальный корректный документ, построенный по схеме Person.xsd.
Теперь научимся добавлять элемент, отсутствующий минимальном корректном документе (т.е. элемент с "minOccurs=0"), например, элемент course
в информации о новой личноссти, или элемент course_code
в новом элементе course
.
Существуют разные варианты действий:
course
после name
, один - после date_of_birth
, и один - после phone
. В этом случае если пользователь кликает на любой из двух первых плюсов, элемент course будет вставлен на место, не разрешенное в XSD. Элемент
insert-course
после элемента phone будет корректным. Например, документ с большим числом элементов будет неудобен для пользователя, поскольку надо будет сделать слишком много попыток, чтобы найти корректное место вставки элемента.
В нашем примере person
- complexType-элемент, и его наследник course
имеет minOccurs равный 0. XSLGUI будет создан так:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="person">
<xsl:param name="root">
/person
</xsl:param>
<xsl:variable name="index">
1
</xsl:variable>
<html>
<head>
<title>person</title>
</head>
<body>
<form name="xmsForm" action="xms.InputPage"
method="post">
<!-- The output of the following will look
like:
<a href="javascript:submitForm(
'/person[1]/course',
'insertfirstposition');"
onClick="submitForm(
'/person[1]/course',
'insertfirstposition');
return false;">
Add course +
</a>
-->
<xsl:variable name="courseCount"
select="count(course)"/>
<xsl:if test="$courseCount='0'">
<a>
<xsl:attribute name="href">
<xsl:value-of
select="concat('javascript:submitForm(',
"'",'/person[',
$index,']','/course',
"'",',',
"'",
'insertfirstposition',
"'",');')"/>
</xsl:attribute>
<xsl:attribute name="onClick">
<xsl:value-of
select="concat('submitForm(',
"'",'/person[',
$index,']','/course',
"'",',',
"'",
'insertfirstposition',
"'",');
return false;')"/>
</xsl:attribute>Add course +
</a>
</xsl:if>
<xsl:apply-templates>
<xsl:with-param name="path"
select="$root"/>
</xsl:apply-templates>
<input type="submit" name="action"
value="save"/>
</form>
</body>
</html>
</xsl:template>
...
</xsl:stylesheet>
Теперь на уровне элемента person (верхний уровень документа), если пользователь кликает на знак "+" для вставки course, к серверу посылается запрос на действие
insertfirstposition
с XPath-параметром /person/course
. Мы знаем, что вновь созданный документ не содержит элементов course (иначе у нас не было бы знака "+" для
course
), так что нет способа, которым мы могли бы определить, куда вставлять элемент course. Все, что нам известно, это то, что элемент должен быть вставлен в /person
.
Затем, начиная с первой позиции внутри /person
, вставляем course
и проверяем документ. Если результат корректен, используем
XSLGUI для создания GUI; в противном случае вставляем элемент в следующую позицию, и так до тех пор, пока не найдем корректную позицию для course
.
Этот способ позволяет вставить элемент в первую допустимую позицию исходного документа. Заметим, что может быть предпочтительно вставить элемент не в первую допустимую позицию, а куда-то еще. Это может быть довольно сложной задачей.
XUpdate используется для вставки нового элемента в разные позиции, как показано ниже:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xu:modifications
xmlns:xu="http://www.xmldb.org/xupdate">
<xu:append select="/person[1]"
child=index>
<xu:element name="insert-course"/>
</xu:append>
</xu:modifications>
Здесь index инициализируется в 0 и возрастает до тех пор, пока не обнаруживается корректная позиция.
В этой статье описан способ вставки элементов в XML-документ через автоматически генерящийся, основанный на формах GUI с использованием XML Schema документа с данными и XSLT. Возможность редактирования и вставки или удаления элементов с использованием соответствующего XML Schema обеспечивает полнофункциональный метод создания web-ориентированного XML-редактора.
XML.com Copyright © 1998-2003 O'Reilly & Associates, Inc.