Transforming XML Schemas
by Eric Gropp
|
Pages: 1, 2
When an
<extension> is encountered, the stylesheet
will process the extension's base and local content models in
sequence.
<xsl:template match="xs:extension" mode="findChildNodes">
<xsl:apply-templates select="/xs:schema/xs:complexType[@name=current()/@base]"
mode="findChildNodes"/>
<xsl:apply-templates select="*" mode="findChildNodes"/>
</xsl:template>
Once the definition of the child element is found, the template
determines whether it is a simple type and exempt from any
application specific restrictions. If this is true, it builds the
table row, and then applies the templates from the
childNodeInput mode to construct the input element.
<xsl:template match="xs:element[@name]" mode="findChildNodes">
<xsl:if test="not(xs:complexType|
/xs:schema/xs:complexType[@name=current()/@type]|
xs:annotation/xs:appinfo/frm:readonly)">
<tr>
<td>
<xsl:choose>
<xsl:when test="xs:annotation/xs:appinfo/frm:label">
<xsl:value-of select="xs:annotation/xs:appinfo/frm:label"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@name"/>
</xsl:otherwise>
</xsl:choose>
</td>
<td>
<xsl:apply-templates select="." mode="childNodeInput">
<xsl:with-param name="nodeName" select="@name"/>
</xsl:apply-templates>
</td>
</tr>
</xsl:if>
</xsl:template>
<xsl:template match="*" mode="findChildNodes"/>
Interpreting Simple Type Definitions
The templates of the simpleInputElement mode will
walk the schema to find the base type of each simple element and
then output the appropriate XHTML form element for the type. If
the element's type is a restriction of a base type, it will
further modify the XHTML form element with XHTML or custom
attributes.
The first two template rules are designed to match elements typed with anonymous or namespace defined simple types. The priority attribute of the first template is set to zero, so that it will have a lower priority than the template rules matching native WXS types.
<xsl:template match="xs:element[@type]" mode="childNodeInput" priority="0">
<xsl:param name="nodeName"/>
<xsl:param name="nodeValue" select="@default"/>
<xsl:apply-templates
select="/xs:schema/xs:simpleType[@name=current()/@type]/xs:restriction"
mode="childNodeInput">
<xsl:with-param name="nodeName" select="$nodeName"/>
<xsl:with-param name="nodeValue" select="$nodeValue"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="xs:element[xs:simpleType]" mode="childNodeInput">
<xsl:param name="nodeName"/>
<xsl:param name="nodeValue" select="@default"/>
<xsl:apply-templates select="xs:simpleType/xs:restriction" mode="childNodeInput">
<xsl:with-param name="nodeName" select="$nodeName"/>
<xsl:with-param name="nodeValue" select="$nodeValue"/>
</xsl:apply-templates>
</xsl:template>
The following template rules are a sample of the templates to match the native WXS types.
<xsl:template match="xs:element[@type='xs:string']|xs:restriction[@base='xs:string']"
mode="childNodeInput">
<xsl:param name="nodeName"/>
<xsl:param name="nodeValue" select="@default"/>
<xsl:choose>
<xsl:when test="xs:maxLength">
<input type="text" name="{$nodeName}" value="{$nodeValue}">
<xsl:apply-templates select="*" mode="childNodeInput"/>
</input>
</xsl:when>
<xsl:otherwise>
<textArea name="{$nodeName}">
<xsl:apply-templates select="*" mode="childNodeInput"/>
<xsl:value-of select="$nodeValue"/>
</textArea>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="xs:element[@type='xs:boolean']|xs:restriction[@base='xs:boolean']"
mode="childNodeInput">
<xsl:param name="nodeName"/>
<xsl:param name="nodeValue" select="@default"/>
<input type="radio" name="{$nodeName}" value="true">
<xsl:if test="$nodeValue='true'">
<xsl:attribute name="checked">checked</xsl:attribute>
</xsl:if>
Yes
</input>
<input type="radio" name="{$nodeName}" value="false">
<xsl:if test="$nodeValue='false'">
<xsl:attribute name="checked">checked</xsl:attribute>
</xsl:if>
No
</input>
</xsl:template>
Some
restriction facets map directly to XHTML input element
attributes. For example <xs:maxLength
value="10"> maps to maxsize="10" attribute
in an <input> element. Other restriction
facets such as <xs:pattern> and
<xs:maxInclusive> do not map to XHTML nodes.
One approach to ensure conformant input from the user is to add
custom attributes to the XHTML <input> element,
and use a client side script to validate the user's input using
the custom attributes.
<xsl:template match="xs:maxLength" mode="childNodeInput">
<xsl:attribute name="maxLength">
<xsl:value-of select="@value"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="xs:pattern" mode="childNodeInput">
<xsl:attribute name="validationRegExp">
<xsl:value-of select="@value"/>
</xsl:attribute>
</xsl:template>
This stylesheet will map restrictions that have enumeration
facets, regardless of the base type, to a
<select> XHTML element. WXS annotation
elements can useful here, when we need to associate human-readable
text with an enumeration facet:
<xs:enumeration value="AK">
<xs:annotation>
<xs:documentation>Alaska</xs:documentation>
</xs:annotation>
</xs:enumeration>
Will be transformed into:
<option value="AK">Alaska</option>
The template rule that matches each enumeration facet checks for annotation information as well as whether the enumeration is the default value.
<xsl:template match="xs:restriction[xs:enumeration]" mode="childNodeInput"
priority="1">
<xsl:param name="nodeName"/>
<xsl:param name="nodeValue"/>
<select name="{$nodeName}">
<xsl:apply-templates select="*" mode="childNodeInput">
<xsl:with-param name="nodeValue" select="$nodeValue"/>
</xsl:apply-templates>
</select>
</xsl:template>
<xsl:template match="xs:enumeration" mode="childNodeInput">
<xsl:param name="nodeValue"/>
<option value="{@value}">
<xsl:if test="@value=$nodeValue">
<xsl:attribute name="selected">
selected
</xsl:attribute>
</xsl:if>
<xsl:choose>
<xsl:when test="xs:annotation/xs:documentation">
<xsl:value-of select="xs:annotation/xs:documentation"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@value"/>
</xsl:otherwise>
</xsl:choose>
</option>
</xsl:template>
<xsl:template match="*" mode="childNodeInput"/>
Conclusion
Using WXS as the common resource for data typing in your application can have big payoffs. By allowing components and interfaces to automatically reflect changes to an application's data model, you can greatly increase the reusability and flexibility of a system. XSLT is a useful, largely platform-independent, and highly portable tool for making this possible.
- same thing for relaxNG ?
2006-11-17 03:20:34 ndeb - Which extensions needed for imports (includes)
2004-07-21 03:45:44 mattad - Which extensions needed for imports (includes)
2004-07-21 09:51:20 Eric Gropp - adding MVC and i18n
2003-05-12 11:43:15 Erik Ostermueller - Does it work?
2003-01-29 09:36:42 Rogier Peters - Does it work?
2003-01-29 12:33:13 Eric Gropp - how to handle minOccurs and maxOccurs
2003-01-21 02:03:07 Edwin van der Wal - how to handle minOccurs and maxOccurs
2003-01-29 13:42:47 Eric Gropp