Appendix B: XSLT from Simple to Schema Syntax


Contents

B.1 XSLT

The following non-normative XSLT can be used to convert XForms simple syntax into XML Schema syntax.

<?xml version='1.0'?>

<!-- NOTE: this XSLT transforms a XForms simple syntax into an
     XML Schema conforming to the October 24, 2000 candidate
     recomendation -->

<xsl:transform version="1.0"
               xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
               xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"
               xmlns="http://www.w3.org/2000/10/XMLSchema"
               xmlns:xfm="http://www.w3.org/2000/12/xforms" >

<xsl:strip-space elements="xform"/>

<xsl:output method="xml" indent="yes" encoding="UTF-8" 
            standalone="no" />


<!-- the special indicator used for maxOccurs to mean unbounded -->
<xsl:variable name="maxOccursSpecial">*</xsl:variable>
<!-- the special value used for maxLength to mean unbounded -->
<xsl:variable name="maxLengthSpecial">unlimited</xsl:variable>
<!-- the special value used for min to mean minus infinity -->
<xsl:variable name="minInfinity">minus infinity</xsl:variable>
<!-- the special value used for max to mean plus infinity -->
<xsl:variable name="maxInfinity">plus infinity</xsl:variable>
<!-- the special value used for scale to mean unlimited decimals -->
<xsl:variable name="unlimitedScale">unlimited</xsl:variable>
<!-- the special value used for precision to mean unlimited precision -->
<xsl:variable name="unlimitedPrecision">unlimited</xsl:variable>

<!-- the list of WML classes -->
<xsl:variable name="classesList" >AaNnXxMm</xsl:variable>
<xsl:variable name="classesTrans">01234567</xsl:variable>

<!-- special characters to escape in patterns -->
<xsl:variable name="specialCharacters">\|.-^?*+{}()[]</xsl:variable>


<!-- template:   match="/"
     function:   matches the root node, calls the template "xform" for
                 all &lt;xform> elements. drops any other elements.
     parameters: none
     output:     &lt;schema> skeleton.
-->
<xsl:template match="/">
    <xsl:element name="xsd:schema">
        <xsl:element name="xsd:annotation">
            <xsl:element name="xsd:documentation">
<xsl:text>Automatically generated from an XForms data model.</xsl:text>

<xsl:text>Using</xsl:text>
<xsl:value-of select="system-property('xsl:vendor')"/>
<xsl:text>at XSL version</xsl:text>
<xsl:value-of select="format-number(system-property('xsl:version'),
                                    '#0.0')"/>.
              
<xsl:if test="system-property('xsl:version') &gt; 1.0">
Note, the stylesheet was designed for a XSLT version 1.0 processor.
</xsl:if>
            </xsl:element>
        </xsl:element>
        <!-- output the xform -->
        <xsl:apply-templates />
    </xsl:element>
</xsl:template>


<!--
xform element                                    
-->
<!-- template:   match="xform"
     function:   matches an xform, calls the templates for all childs
     parameters: none
     output:     none of it's own
-->
<xsl:template match="xform">
  <!-- output the elements -->
  <xsl:apply-templates />
</xsl:template>


<!--
model element                                   
-->
<!-- template:   match="model"
     function:   matches an xform, calls the templates for all childs
     parameters: none
     output:     none of it's own
-->
<xsl:template match="model">
  <!-- output the elements -->
  <xsl:apply-templates />
</xsl:template>


<!--
schema element
-->
<!-- template:   match="schema"
     function:   matches an schema, and copies the inlined schema definition
                 to the result tree
     parameters: none
     output:     copy of the input
-->
<xsl:template match="xsd:schema">
  <!-- copy XML Schema definition -->
  <xsl:copy-of select="node()"/>
</xsl:template>


<!--
simple element
-->
<!-- template:   match="simple"
     function:   matches an simple, and processes the child elements
     parameters: none
     output:     none of its own
-->

<xsl:template match="simple">
  <!-- output the elements -->
  <xsl:apply-templates />
</xsl:template>


<!--
isntance element                          
-->

<!-- template:   match="instance"
     function:   filters the instance
     parameters: none
     output:     none
-->
<xsl:template match="instance"/>


<
binding element
-->
<!-- template:   match="binding"
     function:   filters the binding
     parameters: none
     output:     none
-->
<xsl:template match="binding"/>



<!--
submit element                                
-->

<!-- template:   match="submit"
     function:   filters the submit elements
     parameters: none
     output:     none
-->
<xsl:template match="submit"/>




<!--
group element
-->
<!-- template:   matches="group"
     function:   converts the group into a complex type and processes
                 all childs
     parameters: none
     output:     a complex type representing the group
-->
<xsl:template match="group">
  <xsl:element name="xsd:element">
    <xsl:attribute name="name">
      <xsl:value-of select="@name"/>
    </xsl:attribute>
    <!-- check attributes -->
    <xsl:call-template name="checkAttributes"/>
    
    <xsl:element name="xsd:complexType">
      <xsl:element name="xsd:complexContent">
        <xsl:element name="xsd:extension">
          <!-- check for a base -->
          <xsl:attribute name="base">xsd:anyType</xsl:attribute>
          <!-- the rest of the elements are always a sequence -->
          <xsl:element name="xsd:sequence">
            <!-- include all chile elements -->
            <xsl:apply-templates/>
          </xsl:element>
        </xsl:element>
      </xsl:element>
    </xsl:element>
  </xsl:element>
</xsl:template>



<!--
union element                  
-->
<!-- template:   matches="union"
     function:   converts a union into a union of simpleTypes.
     parameters: none
     output:     converted definition
-->
<xsl:template match="union">
  <xsl:choose>
    <xsl:when test="string-length(@name)=0">
      <xsl:message terminate="no">
        An anonymous union definition is not supported.
      </xsl:message>
      <xsl:comment> Anonymous union definition dropped </xsl:comment>
    </xsl:when>
    <xsl:otherwise>
      <xsl:element name="xsd:element">
        <xsl:attribute name="name">
          <xsl:value-of select="@name"/>
        </xsl:attribute>
        <!-- check common attributes -->
        <xsl:call-template name="checkAttributes"/>
    
        <xsl:element name="xsd:simpleType">
          <xsl:element name="xsd:union">
            <xsl:apply-templates />
          </xsl:element>
        </xsl:element>
      </xsl:element>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>



<!--
switch element                                       
-->

<!-- template:   matches="switch"
     function:   converts the switch into a choice and processes all
                 cases
     parameters: none
     output:     a choice representing the variant
-->
<xsl:template match="switch">
  <xsl:choose>
    <xsl:when test="string-length(@name)=0">
      <xsl:message terminate="no">
        An anonymous variant definition is not supported.
      </xsl:message>
      <xsl:comment> Anonymous variant definition dropped </xsl:comment>
    </xsl:when>
    <xsl:otherwise>
      <xsl:element name="xsd:element">
        <xsl:attribute name="name">
          <xsl:value-of select="@name"/>
        </xsl:attribute>
        <!-- check common attributes -->
        <xsl:call-template name="checkAttributes"/>
    
        <xsl:element name="xsd:complexType">
          <xsl:element name="xsd:complexContent">
            <xsl:element name="xsd:extension">
              <xsl:attribute name="base">xsd:anyType</xsl:attribute>
              <xsl:element name="xsd:choice">
                <xsl:apply-templates select="case"/>
              </xsl:element>
            </xsl:element>
          </xsl:element>
        </xsl:element>
      </xsl:element>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!--
case element
-->

<!-- template:   matches="caase"
     function:   converts the case into a sequence of other elements
     parameters: none
     output:     a sequence representing the case
-->
<xsl:template match="case">
  <xsl:element name="xsd:sequence">
    <xsl:if test="string-length(@name) &gt; 0">
      <xsl:attribute name="xfm:name">
        <xsl:value-of select="@name"/>
      </xsl:attribute>
    </xsl:if>
    <xsl:if test="string-length(@condition) &gt; 0">
      <xsl:attribute name="xfm:condition">
        <xsl:value-of select="@condition"/>
      </xsl:attribute>
    </xsl:if>

    <!-- include elements -->
    <xsl:apply-templates />

  </xsl:element>
</xsl:template>




<!--
string element
-->

<!-- template:   matches="string"
     function:   converts a string.
     parameters: none
     output:     converted definition
     note:       it is assumed that all value childs
                 conform to all other restrictions, otherwise their
                 value will be allowed despide the further 
                 restrictions.
-->
<xsl:template match="string">
  <!-- create definition -->
  <xsl:variable name="definition">
  
    <xsl:element name="xsd:simpleType">
      <xsl:choose>
        <!-- if we have a closed range, or no enumeration value, we can
             create a simple type -->
        <xsl:when test="@enum='closed' or 
                        count(value)=0">
          <xsl:element name="xsd:restriction">
            <xsl:attribute name="base">xsd:string</xsl:attribute>
            <xsl:call-template name="restrictString"/>
            <xsl:apply-templates select="value"/>
          </xsl:element>
        </xsl:when>
        <xsl:otherwise>
          <xsl:element name="xsd:union">
            <xsl:element name="xsd:simpleType">
              <xsl:element name="xsd:restriction">
                <xsl:attribute name="base">xsd:string</xsl:attribute>
                <xsl:call-template name="restrictString"/>
                <xsl:apply-templates select="value"/>
              </xsl:element>
            </xsl:element>
            <xsl:element name="xsd:simpleType">
              <xsl:element name="xsd:restriction">
                <xsl:attribute name="base">xsd:string</xsl:attribute>
                <xsl:call-template name="restrictString"/>
              </xsl:element>
            </xsl:element>
          </xsl:element>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:element>
  </xsl:variable>
  
  <!-- if we have a name, we can create an element or attribute,
       otherwise we're part of a union -->
  <xsl:choose>
    <xsl:when test="string-length(@name) &gt; 0">
      <!-- create element or attribute -->
      <xsl:element name="xsd:element">
        <xsl:attribute name="name">
          <xsl:value-of select="@name"/>
        </xsl:attribute>
        <!-- check common attributes -->
        <xsl:call-template name="checkAttributes"/>
    
        <xsl:choose>
          <!-- if we have no children, and no other restrictions,
               we can make a short definition -->
          <xsl:when test='count(child::node())=0 and @minLength="0" and
                          @maxLength="unlimited" and 
                          string-length(@pattern)=0 and
                          string-length(@mask)=0'>
            <xsl:attribute name="type">xsd:string</xsl:attribute>
          </xsl:when>
          <xsl:otherwise>
            <!-- dump full definition -->
            <xsl:copy-of select="$definition"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:element>
    </xsl:when>
    <xsl:otherwise>
      <!-- just dumpe definition -->
      <xsl:copy-of select="$definition"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<!-- template:   name="restrictString"
     function:   add erstrictions to a string
     parameters: a string context node with the following attributes
                     @maxLength
                     @minLength
                     @mask
                     @pattern
                 and the following child elements
                     <pattern/>
                     <mask/>
     output:     elements to represent the restrictions
-->
<xsl:template name="restrictString">
  <!-- create pattern -->
  <xsl:variable name="pattern">
    <xsl:for-each select="mask|pattern">
      <xsl:text>(</xsl:text>
      <xsl:choose>
         <xsl:when test='name()="mask"'>
          <xsl:call-template name="make-pattern">
            <xsl:with-param name="mask">
              <xsl:value-of select="."/>
            </xsl:with-param>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="."/>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:text>)</xsl:text>
      <xsl:if test="not(position()=last())">
        <xsl:text>|</xsl:text>
      </xsl:if>
    </xsl:for-each>
    
    <xsl:if test="@mask">
      <xsl:if test="count(mask|pattern) &gt; 0">
        <xsl:text>|</xsl:text>
      </xsl:if>
      <xsl:text>(</xsl:text>
      <xsl:call-template name="make-pattern">
        <xsl:with-param name="mask">
          <xsl:value-of select="@mask"/>
        </xsl:with-param>
      </xsl:call-template>
      <xsl:text>)</xsl:text>
    </xsl:if>
  
    <xsl:if test="@pattern">
      <xsl:if test="string-length(@mask) &gt; 0 and
                    count(mask|pattern) &gt; 0">
        <xsl:text>|</xsl:text>
      </xsl:if>
      <xsl:text>(</xsl:text>
      <xsl:value-of select="@pattern"/>
      <xsl:text>)</xsl:text>
    </xsl:if>
  </xsl:variable>

  <!-- check if @length is an non negative integer -->
  <xsl:variable name="lengthIsNNI">
    <xsl:call-template name="checkNonNegInt">
      <xsl:with-param name="test">
        <xsl:value-of select="@length"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>

  <!-- check if @max is an non negative integer -->
  <xsl:variable name="maxIsNNI">
    <xsl:call-template name="checkNonNegInt">
      <xsl:with-param name="test">
        <xsl:value-of select="@max"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>

  <!-- check if @min as an non negative integer -->
  <xsl:variable name="minIsNNI">
    <xsl:call-template name="checkNonNegInt">
      <xsl:with-param name="test">
        <xsl:value-of select="@min"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>
  
  <!-- write xfm:length restriction -->
  <xsl:if test="string-length(@length) &gt; 0 and
                not(@length=$maxLengthSpecial) and
                $lengthIsNNI='false'">
    <xsl:attribute name="xfm:length">
      <xsl:value-of select="@length"/>
    </xsl:attribute>
  </xsl:if>
  
  <!-- write xfm:maxLength restriction -->
  <xsl:if test="string-length(@max) &gt; 0 and
                not(@max=$maxLengthSpecial) and
                $maxIsNNI='false'">
    <xsl:attribute name="xfm:maxLength">
      <xsl:value-of select="@max"/>
    </xsl:attribute>
  </xsl:if>
  
  <!-- write xfm:minLength restriction -->
  <xsl:if test="string-length(@min) &gt; 0 and
                not(@min='0') and
                $minIsNNI='false'">
    <xsl:attribute name="xfm:minLength">
      <xsl:value-of select="@min"/>
    </xsl:attribute>
  </xsl:if>
  
  <!-- write xsd:length restriction -->
  <xsl:choose>
    <xsl:when test="$lengthIsNNI='true'">
      <xsl:if test="not(@length=$maxLengthSpecial)">
        <xsl:element name="xsd:length">
          <xsl:attribute name="value">
            <xsl:value-of select="@length"/>
          </xsl:attribute>
        </xsl:element>
      </xsl:if>
    </xsl:when>
    <xsl:when test="count(length) &gt; 0">
      <xsl:element name="xsd:length">
        <xsl:attribute name="value">
          <xsl:value-of select="length[1]"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>
  
  <!-- write xsd:maxLength restriction -->
  <xsl:choose>
    <xsl:when test="$maxIsNNI='true'">
      <xsl:if test="not(@max=$maxLengthSpecial)">
        <xsl:element name="xsd:maxLength">
          <xsl:attribute name="value">
            <xsl:value-of select="@max"/>
          </xsl:attribute>
        </xsl:element>
      </xsl:if>
    </xsl:when>
    <xsl:when test="count(max) &gt; 0">
      <xsl:element name="xsd:maxLength">
        <xsl:attribute name="value">
          <xsl:value-of select="max[1]"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>
  
  <!-- write xsd:minLength restriction -->
  <xsl:choose>
    <xsl:when test="$minIsNNI='true'">
      <xsl:if test="not(@min='0')">
        <xsl:element name="xsd:minLength">
          <xsl:attribute name="value">
            <xsl:value-of select="@min"/>
          </xsl:attribute>
        </xsl:element>
      </xsl:if>
    </xsl:when>
    <xsl:when test="count(min) &gt; 0">
      <xsl:element name="xsd:min">
        <xsl:attribute name="value">
          <xsl:value-of select="min[1]"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>
  
  <!-- write xsd:pattern -->
  <xsl:if test="string-length($pattern) &gt; 0">
    <xsl:element name="xsd:pattern">
      <xsl:attribute name="value">
        <xsl:value-of select="$pattern"/>
      </xsl:attribute>
    </xsl:element>
  </xsl:if>
</xsl:template>  


<!-- template:   name="make-pattern"
     function:   converts a mask to a pattern
     parameters: mask       : the mask to transform
                 i          : current position inside mask
                 last       : last source character
                 count      : how many times did the last character 
                              occur
     output:     a pattern with the same meaning
-->
<xsl:template name="make-pattern">
  <xsl:param name="mask"/>
  <xsl:param name="i">0</xsl:param>
  <xsl:param name="last"/>
  <xsl:param name="count"/>

  <xsl:choose>
    <!-- if there are characters to process, do so -->
    <xsl:when test="$i &lt; string-length($mask)">
      <!-- get current character -->
      <xsl:variable name="c">
        <xsl:value-of select="substring($mask, $i + 1, 1)"/>
      </xsl:variable>
      <!-- process it -->
      <xsl:choose>
        <!-- check for special characters first -->
        <!-- the backslash (\): the next character is ment literally -->
        <xsl:when test="$c='\'">
          <!-- output old count -->
          <xsl:if test="$count &gt; 1">
            <xsl:text>{</xsl:text>
            <xsl:value-of select="$count"/>
            <xsl:text>}</xsl:text>
          </xsl:if>
          <!-- check if the character has to be escaped -->
          <xsl:call-template name="escape-char">
            <xsl:with-param name="char">
              <xsl:value-of select="substring($mask, $i + 2, 1)"/>
            </xsl:with-param>
          </xsl:call-template>

          <!-- call recursively -->
          <xsl:call-template name="make-pattern">
            <xsl:with-param name="mask">
              <xsl:value-of select="$mask"/>
            </xsl:with-param>
            <xsl:with-param name="i">
              <xsl:value-of select="$i + 2"/>
            </xsl:with-param>
            <xsl:with-param name="last">
              <xsl:text>\</xsl:text>
            </xsl:with-param>
            <xsl:with-param name="count">
              <xsl:value-of select="0"/>
            </xsl:with-param>
          </xsl:call-template>
        </xsl:when>
        <!-- the asterix (*): any other number of the following class -->
        <xsl:when test="$c='*'">
          <!-- get next character -->
          <xsl:variable name="next">
            <xsl:value-of select="substring($mask, $i + 2, 1)"/>
          </xsl:variable>
          <xsl:choose>
            <!-- it the next is equal to the last, create special output -->
            <xsl:when test="$last=$next">
              <xsl:text>{</xsl:text>
              <xsl:value-of select="$count"/>
              <xsl:text>,}</xsl:text>
            </xsl:when>
            <xsl:otherwise>
              <!-- output old count -->
              <xsl:if test="$count &gt; 1">
                <xsl:text>{</xsl:text>
                <xsl:value-of select="$count"/>
                <xsl:text>}</xsl:text>
              </xsl:if>
              <!-- converte wml character class into unicode class -->
              <xsl:call-template name="convert-characterClass">
                <xsl:with-param name="class">
                  <xsl:value-of select="$next"/>
                </xsl:with-param>
              </xsl:call-template>
              
              <xsl:text>*</xsl:text>
            </xsl:otherwise>
          </xsl:choose>
          <!-- keep in mind, that any mask ends after a *. -->
        </xsl:when>
        <!-- a number [1-9]: repeat next character n times -->
        <xsl:when test="contains('0123456789', $c)">
          <!-- get next character -->
          <xsl:variable name="next">
            <xsl:value-of select="substring($mask, $i + 2, 1)"/>
          </xsl:variable>
          <xsl:choose>
            <!-- when the next character equals the last,
                 just increase count -->
            <xsl:when test="$last=$next">
              <xsl:call-template name="make-pattern">
                <xsl:with-param name="mask">
                  <xsl:value-of select="$mask"/>
                </xsl:with-param>
                <xsl:with-param name="i">
                  <xsl:value-of select="$i + 2"/>
                </xsl:with-param>
                <xsl:with-param name="last">
                  <xsl:value-of select="$last"/>
                </xsl:with-param>
                <xsl:with-param name="count">
                  <xsl:value-of select="$count + $c"/>
                </xsl:with-param>
              </xsl:call-template>            
            </xsl:when>
            <xsl:otherwise>
              <!-- output old count -->
              <xsl:if test="$count &gt; 1">
                <xsl:text>{</xsl:text>
                <xsl:value-of select="$count"/>
                <xsl:text>}</xsl:text>
              </xsl:if>
              <!-- convert character class -->
              <xsl:variable name="out">
                <xsl:call-template name="convert-characterClass">
                  <xsl:with-param name="class">
                    <xsl:value-of select="$next"/>
                  </xsl:with-param>
                </xsl:call-template>
              </xsl:variable>
              <!-- output unicode character classes -->
              <xsl:value-of select="$out"/>
              <!-- call recursively -->
              <xsl:call-template name="make-pattern">
                <xsl:with-param name="mask">
                  <xsl:value-of select="$mask"/>
                </xsl:with-param>
                <xsl:with-param name="i">
                  <xsl:value-of select="$i + 2"/>
                </xsl:with-param>
                <xsl:with-param name="last">
                  <xsl:value-of select="$next"/>
                </xsl:with-param>
                <xsl:with-param name="count">
                  <xsl:value-of select="$c"/>
                </xsl:with-param>
              </xsl:call-template>            
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <!-- if it's the same as the last, just increase count -->
        <xsl:when test='$c=$last'>
          <!-- call recursively -->
          <xsl:call-template name="make-pattern">
            <xsl:with-param name="mask">
              <xsl:value-of select="$mask"/>
            </xsl:with-param>
            <xsl:with-param name="i">
              <xsl:value-of select="$i + 1"/>
            </xsl:with-param>
            <xsl:with-param name="last">
              <xsl:value-of select="$last"/>
            </xsl:with-param>
            <xsl:with-param name="count">
              <xsl:value-of select="$count + 1"/>
            </xsl:with-param>
          </xsl:call-template>
        </xsl:when>
        <!-- a new/different character -->
        <xsl:otherwise>
          <!-- catches the fact that the user missed the backslash in
               front of a literal character -->
          <!-- output old count -->
          <xsl:if test="$count &gt; 1">
            <xsl:text>{</xsl:text>
            <xsl:value-of select="$count"/>
            <xsl:text>}</xsl:text>
          </xsl:if>
          <!-- convert character class -->
          <xsl:variable name="out">
            <xsl:call-template name="convert-characterClass">
              <xsl:with-param name="class">
                <xsl:value-of select="$c"/>
              </xsl:with-param>
            </xsl:call-template>
          </xsl:variable>
          <!-- output unicode character classes -->
          <xsl:value-of select="$out"/>
          <!-- call recursively -->
          <xsl:call-template name="make-pattern">
            <xsl:with-param name="mask">
              <xsl:value-of select="$mask"/>
            </xsl:with-param>
            <xsl:with-param name="i">
              <xsl:value-of select="$i + 1"/>
            </xsl:with-param>
            <xsl:with-param name="last">
              <xsl:value-of select="$c"/>
            </xsl:with-param>
            <xsl:with-param name="count">
              <xsl:value-of select="1"/>
            </xsl:with-param>
          </xsl:call-template>            
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:if test="$count &gt; 1">
        <xsl:text>{</xsl:text>
        <xsl:value-of select="$count"/>
        <xsl:text>}</xsl:text>
      </xsl:if>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<!-- template:   name="convert-characterClass"
     function:   converts a wml character class into the proper
                 unicode character classes, as defined by <characterClasses/>
     parameter:  class :wml character class
     output:     matching unicode class(es)
-->
<xsl:template name="convert-characterClass">
  <xsl:param name="class"/>
  
   
  <xsl:if test='contains($classesList, $class)'>
    <xsl:variable name="i">
      <xsl:value-of select="translate($class, $classesList, $classesTrans)"/>
    </xsl:variable>

    <xsl:value-of select="document('')//this:class[$i + 1]/this:unicode"/>
  </xsl:if> 
</xsl:template>

<!-- template:   name="escape-char"
     function:   escapes characters, to not have a special meaning in 
                 reg exp
     parameters: char  :character to escape
     output:     save version
-->
<xsl:template name="escape-char">
  <xsl:param name="char"/>
  <xsl:choose>
    <!-- check if the character must be escaped -->
    <xsl:when test='contains($specialCharacters, $char)'>
      <xsl:text>\</xsl:text>
      <xsl:value-of select="$char"/>
    </xsl:when>
    <xsl:otherwise>
      <!-- no escaping needed, just return $char -->
      <xsl:value-of select="$char"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>  



<!--
boolean element
-->

<!-- template:   match="boolean"
     function:   converts a boolean into a xsd:boolean
     parameters: none
     output:     converted definition
-->
<xsl:template match="boolean">
  <!-- create definition -->
  <xsl:variable name="definition">
    <xsl:element name="xsd:simpleType">
      <xsl:choose>
        <!-- if we have closed range, or no enumeration value, we can
             create simple type -->
        <xsl:when test="@enum='closed' or 
                        count(value)=0">
          <xsl:element name="xsd:restriction">
            <xsl:attribute name="base">xsd:boolean</xsl:attribute>
            <xsl:apply-templates select="value"/>
          </xsl:element>
        </xsl:when>
        <xsl:otherwise>
          <xsl:element name="xsd:union">
            <xsl:element name="xsd:simpleType">
              <xsl:element name="xsd:restriction">
                <xsl:attribute name="base">xsd:boolean</xsl:attribute>
                <xsl:apply-templates select="value"/>
              </xsl:element>
            </xsl:element>
            <xsl:element name="xsd:simpleType">
              <xsl:element name="xsd:restriction">
                <xsl:attribute name="base">xsd:boolean</xsl:attribute>
              </xsl:element>
            </xsl:element>
          </xsl:element>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:element>
  </xsl:variable>

  <!-- if we have a name, we can create an element or attribute,
       otherwise we're part of a union -->
  <xsl:choose>
    <xsl:when test="string-length(@name) &gt; 0">
      <!-- create element or attribute -->
      <xsl:element name="xsd:element">
        <xsl:attribute name="name">
          <xsl:value-of select="@name"/>
        </xsl:attribute>
        <!-- check common attributes -->
        <xsl:call-template name="checkAttributes"/>
    
        <xsl:choose>
          <!-- if we have no children, and no other restrictions,
               we can make a short definition -->
          <xsl:when test='count(child::node())=0'>
            <xsl:attribute name="type">xsd:boolean</xsl:attribute>
          </xsl:when>
          <xsl:otherwise>
            <!-- dump full definition -->
            <xsl:copy-of select="$definition"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:element>
    </xsl:when>
    <xsl:otherwise>
      <!-- just dumpe definition -->
      <xsl:copy-of select="$definition"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>



<!--
number element
-->

<!-- template:   matches="number"
     function:   converts a number into an xsd:number.
     parameters: none
     output:     converted definition
-->
<xsl:template match="number">
  <!-- create definition -->
  <xsl:variable name="definition">
    <xsl:element name="xsd:simpleType">
      <xsl:choose>
        <!-- if we have closed range, or no enumeration value, we can
             create simple type -->
        <xsl:when test="@enum='closed' or 
                        count(value)=0">
          <xsl:element name="xsd:restriction">
            <xsl:attribute name="base">xsd:decimal</xsl:attribute>
            <xsl:call-template name="restrictNumber"/>
            <xsl:apply-templates select="value"/>
          </xsl:element>
        </xsl:when>
        <xsl:otherwise>
          <xsl:element name="xsd:union">
            <xsl:element name="xsd:simpleType">
              <xsl:element name="xsd:restriction">
                <xsl:attribute name="base">xsd:decimal</xsl:attribute>
                <xsl:call-template name="restrictNumber"/>
                <xsl:apply-templates select="value"/>
              </xsl:element>
            </xsl:element>
            <xsl:element name="xsd:simpleType">
              <xsl:element name="xsd:restriction">
                <xsl:attribute name="base">xsd:decimal</xsl:attribute>
                <xsl:call-template name="restrictNumber"/>
              </xsl:element>
            </xsl:element>
          </xsl:element>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:element>
  </xsl:variable>

  <!-- if we have a name, we can create an element or attribute,
       otherwise we're part of a union -->
  <xsl:choose>
    <xsl:when test="string-length(@name) &gt; 0">
      <!-- create element or attribute -->
      <xsl:element name="xsd:element">
        <xsl:attribute name="name">
          <xsl:value-of select="@name"/>
        </xsl:attribute>
        <!-- check common attributes -->
        <xsl:call-template name="checkAttributes"/>
    
        <xsl:choose>
          <!-- if we have no children, and no other restrictions,
               we can make a short definition -->
          <xsl:when test='count(child::node())=0 and 
                    (string-length(@min)=0 or @min=$minInfinity) and
                    (string-length(@max)=0 or @max=$maxInfinity) and
                    (string-length(@precision)=0 or 
                     @precision=$unlimitedPrecision) and
                    (string-length(@scale)=0 or @scale=$unlimitedScale)'>
            <xsl:attribute name="type">xsd:decimal</xsl:attribute>
          </xsl:when>
          <xsl:otherwise>
            <!-- dump full definition -->
            <xsl:copy-of select="$definition"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:element>
    </xsl:when>
    <xsl:otherwise>
      <!-- just dumpe definition -->
      <xsl:copy-of select="$definition"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- template:   name="restrictNumber"
     function:   add erstrictions to a number
     parameters: a number context node with the following attributes
                     @max
                     @min
                     @precision
                     @scale
                 and the following child elements
                     <min>
                     <max>
                     <precision>
                     <scale>
     output:     elements to represent the restrictions
-->
<xsl:template name="restrictNumber">
  
  <xsl:message terminate="no">@max:<xsl:value-of select="@max"/></xsl:message>
  <!-- check if max is a number -->
  <xsl:variable name="maxIsNumber">
    <xsl:call-template name="checkNumber">
      <xsl:with-param name="test">
        <xsl:value-of select="@max"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>
  <xsl:message terminate="no">$maxIsNumber:<xsl:value-of select="$maxIsNumber"/></xsl:message>
    
  <!-- check if min is a number -->
  <xsl:variable name="minIsNumber">
    <xsl:call-template name="checkNumber">
      <xsl:with-param name="test">
        <xsl:value-of select="@min"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>
   
  <!-- check if precision is a number -->
  <xsl:variable name="precisionIsNNI">
    <xsl:call-template name="checkNonNegInt">
      <xsl:with-param name="test">
        <xsl:value-of select="@precision"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>
   
  <!-- check if scale is a number -->
  <xsl:variable name="scaleIsNNI">
    <xsl:call-template name="checkNonNegInt">
      <xsl:with-param name="test">
        <xsl:value-of select="@scale"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>
  
  <!-- write xfm:max restriction -->
  <xsl:if test="string-length(@max) &gt; 0 and 
                not(@max=$maxInfinity) and
                $maxIsNumber='false'">
    <xsl:attribute name="xfm:maxInclusive">
      <xsl:value-of select="@max"/>
    </xsl:attribute>
  </xsl:if>

  <!-- write xfm:min restriction -->
  <xsl:if test="string-length(@min) &gt; 0 and 
                not(@min=$minInfinity) and
                $minIsNumber='false'">
    <xsl:attribute name="xfm:minInclusive">
      <xsl:value-of select="@min"/>
    </xsl:attribute>
  </xsl:if>
  
  <!-- write xfm:precision restriction -->
  <xsl:if test="string-length(@precision) &gt; 0 and 
                not(@precision=$unlimitedPrecision) and
                $precisionIsNNI='false'">
    <xsl:attribute name="xfm:precision">
      <xsl:value-of select="@precision"/>
    </xsl:attribute>
  </xsl:if>

  <!-- write xfm:scale restriction -->
  <xsl:if test="string-length(@scale) &gt; 0 and 
                not(@scale=$unlimitedScale) and
                $scaleIsNNI='false'">
    <xsl:attribute name="xfm:scale">
      <xsl:value-of select="@scale"/>
    </xsl:attribute>
  </xsl:if>


  <!-- write xsd:max restriction -->
  <xsl:choose>
    <xsl:when test="$maxIsNumber='true'">
      <xsl:element name="xsd:maxInclusive">
        <xsl:attribute name="value">
          <xsl:value-of select="@max"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
    <xsl:when test="count(max) &gt; 0">
      <xsl:element name="xsd:maxInclusive">
        <xsl:attribute name="value">
          <xsl:value-of select="max[1]"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>

  <!-- write xsd:min restriction -->
  <xsl:choose>
    <xsl:when test="$minIsNumber='true'">
      <xsl:element name="xsd:minInclusive">
        <xsl:attribute name="value">
          <xsl:value-of select="@min"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
    <xsl:when test="count(min) &gt; 0">
      <xsl:element name="xsd:minInclusive">
        <xsl:attribute name="value">
          <xsl:value-of select="min[1]"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>
  
  <!-- write xsd:precision restriction -->
  <xsl:choose>
    <xsl:when test="$precisionIsNNI='true'">
      <xsl:element name="xsd:precision">
        <xsl:attribute name="value">
          <xsl:value-of select="@precision"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
    <xsl:when test="count(precision) &gt; 0">
      <xsl:element name="xsd:precision">
        <xsl:attribute name="value">
          <xsl:value-of select="precision[1]"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>

  <!-- write xsd:scale restriction -->
  <xsl:choose>
    <xsl:when test="$scaleIsNNI='true'">
      <xsl:element name="xsd:scale">
        <xsl:attribute name="value">
          <xsl:value-of select="@scale"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
    <xsl:when test="count(scale) &gt; 0">
      <xsl:element name="xsd:scale">
        <xsl:attribute name="value">
          <xsl:value-of select="scale[1]"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>

</xsl:template>  



<!--
currency element
-->

<!-- template:   matches="currency"
     function:   converts a currency into a currency.
     parameters: none
     output:     partially converted definition
-->
<xsl:template match="money">
  <!-- create definition -->
  <xsl:variable name="definition">
    <xsl:element name="xsd:simpleType">
      <xsl:choose>
        <!-- if we have closed range, or no enumeration value, we can
             create simple type -->
        <xsl:when test="@enum='closed' or 
                        count(value)=0">
          <xsl:element name="xsd:restriction">
            <xsl:attribute name="base">xfm:currency</xsl:attribute>
            <xsl:call-template name="restrictCurrency"/>
            <xsl:apply-templates select="value"/>
          </xsl:element>
        </xsl:when>
        <xsl:otherwise>
          <xsl:element name="xsd:union">
            <xsl:element name="xsd:simpleType">
              <xsl:element name="xsd:restriction">
                <xsl:attribute name="base">xfm:currency</xsl:attribute>
                <xsl:call-template name="restrictCurrency"/>
                <xsl:apply-templates select="value"/>
              </xsl:element>
            </xsl:element>
            <xsl:element name="xsd:simpleType">
              <xsl:element name="xsd:restriction">
                <xsl:attribute name="base">xfm:currency</xsl:attribute>
                <xsl:call-template name="restrictCurrency"/>
              </xsl:element>
            </xsl:element>
          </xsl:element>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:element>
  </xsl:variable>

  <!-- if we have a name, we can create an element or attribute,
       otherwise we're part of a union -->
  <xsl:choose>
    <xsl:when test="string-length(@name) &gt; 0">
      <!-- create element or attribute -->
      <xsl:element name="xsd:element">
        <xsl:attribute name="name">
          <xsl:value-of select="@name"/>
        </xsl:attribute>
        <!-- check common attributes -->
        <xsl:call-template name="checkAttributes"/>
    
        <xsl:choose>
          <!-- if we have no children, and no other restrictions,
               we can make a short definition -->
          <xsl:when test='count(child::node())=0 and 
                    (string-length(@min)=0 or @min=0) and
                    (string-length(@max)=0 or @max=$maxLengthSpecial)'>
            <xsl:attribute name="type">xfm:currency</xsl:attribute>
          </xsl:when>
          <xsl:otherwise>
            <!-- dump full definition -->
            <xsl:copy-of select="$definition"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:element>
    </xsl:when>
    <xsl:otherwise>
      <!-- just dumpe definition -->
      <xsl:copy-of select="$definition"/>
    </xsl:otherwise>
  </xsl:choose>

</xsl:template>


<!-- template:   name="restrictCurrency"
     function:   add erstrictions to a currency
     parameters: a currency context node with the following attributes
                     @max
                     @min
                     @mask
                 and the following child elements
                     <min>
                     <max>
                     <mask>
     output:     elements to represent the restrictions
-->
<xsl:template name="restrictCurrency">
<!-- this is currently not implemented, because it is unclear what min, max
     or mask are supposed to mean -->
</xsl:template>



<!--
money element
-->

<!-- template:   matches="money"
     function:   converts a money into a money.
     parameters: none
     output:     partially converted definition
-->
<xsl:template match="money">
  <!-- only elements of type money can be converted into Schemas -->
  <xsl:choose>
    <xsl:when test="string-length(@name) = 0">
      <xsl:message terminate="no">
        An anonymous money definition is not supported.
      </xsl:message>
      <xsl:comment> Anonymous money definition dropped </xsl:comment>
    </xsl:when>
    <xsl:otherwise>
      <xsl:element name="xsd:element">
        <xsl:attribute name="name">
          <xsl:value-of select="@name"/>
        </xsl:attribute>
        <!-- check common attributes -->
        <xsl:call-template name="checkAttributes"/>

        <xsl:attribute name="type">xfm:money</xsl:attribute>
        
        <!-- add allowCurrency -->
        <xsl:if test="string-length(@allowCurrency) &gt; 0">
          <xsl:attribute name="xfm:allowCurrency">
            <xsl:value-of select="@allowCurrency"/>
          </xsl:attribute>
        </xsl:if>

        <!-- add min value -->
        <xsl:if test="string-length(@min) &gt; 0 and
                      not(@min=$minInfinity)">
          <xsl:attribute name="xfm:minInclusive">
            <xsl:value-of select="@min"/>
          </xsl:attribute>
        </xsl:if>

        <!-- add max value -->
        <xsl:if test="string-length(@max) &gt; 0 and
                      not(@max=$maxInfinity)">
          <xsl:attribute name="xfm:maxInclusive">
            <xsl:value-of select="@max"/>
          </xsl:attribute>
        </xsl:if>
        
        <!-- add precision value -->
        <xsl:if test="string-length(@precision) &gt; 0 and
                      not(@precision=$unlimitedPrecision)">
          <xsl:attribute name="xfm:precision">
            <xsl:value-of select="@precision"/>
          </xsl:attribute>
        </xsl:if>
        
        <!-- add scale value -->
        <xsl:if test="string-length(@scale) &gt; 0 and
                      not(@scale=$unlimitedScale)">
          <xsl:attribute name="xfm:scale">
            <xsl:value-of select="@scale"/>
          </xsl:attribute>
        </xsl:if>
        
      </xsl:element>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>



<!--
date element
-->

<!-- template:   matches="date"
     function:   converts a date into an xsd:date.
     parameters: none
     output:     converted definition
-->
<xsl:template match="date">
  <!-- create definition -->
  <xsl:variable name="definition">
    <xsl:element name="xsd:simpleType">
      <xsl:choose>
        <!-- if we have closed range, or no enumeration value, we can
             create simple type -->
        <xsl:when test="@range='closed' or 
                        count(value)=0">
          <xsl:element name="xsd:restriction">
            <xsl:attribute name="base">xsd:date</xsl:attribute>
            <xsl:call-template name="restrictDate"/>
            <xsl:apply-templates select="value"/>
          </xsl:element>
        </xsl:when>
        <xsl:otherwise>
          <xsl:element name="xsd:union">
            <xsl:element name="xsd:simpleType">
              <xsl:element name="xsd:restriction">
                <xsl:attribute name="base">xsd:date</xsl:attribute>
                <xsl:call-template name="restrictDate"/>
                <xsl:apply-templates select="value"/>
              </xsl:element>
            </xsl:element>
            <xsl:element name="xsd:simpleType">
              <xsl:element name="xsd:restriction">
                <xsl:attribute name="base">xsd:date</xsl:attribute>
                <xsl:call-template name="restrictDate"/>
              </xsl:element>
            </xsl:element>
          </xsl:element>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:element>
  </xsl:variable>

  <!-- if we have a name, we can create an element or attribute,
       otherwise we're part of a union -->
  <xsl:choose>
    <xsl:when test="string-length(@name) &gt; 0">
      <!-- create element -->
      <xsl:element name="xsd:element">
        <xsl:attribute name="name">
          <xsl:value-of select="@name"/>
        </xsl:attribute>
        <!-- check common attributes -->
        <xsl:call-template name="checkAttributes"/>
    
        <xsl:choose>
          <!-- if we have no children, and no other restrictions,
               we can make a short definition -->
          <xsl:when test='count(child::node())=0 and 
                          string-length(@min)=0  and
                          string-length(@max)=0  and
                          (string-length(@precision)=0 or 
                           @precision="days")'>
            <xsl:attribute name="type">xsd:date</xsl:attribute>
          </xsl:when>
          <xsl:otherwise>
            <!-- dump full definition -->
            <xsl:copy-of select="$definition"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:element>
    </xsl:when>
    <xsl:otherwise>
      <!-- just dumpe definition -->
      <xsl:copy-of select="$definition"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- template:   name="restrictDate"
     function:   add erstrictions to a date
     parameters: a date context node with the following attributes
                     @max
                     @min
                     @precision
                 and the following child elements
                     <min>
                     <max>
                     <precision>
     output:     elements to represent the restrictions
-->
<xsl:template name="restrictDate">
  
  <!-- check if @max is a date -->
  <xsl:variable name="maxIsDate">
    <xsl:call-template name="checkDate">
      <xsl:with-param name="test">
        <xsl:value-of select="@max"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>
    
  <!-- check if @min is a date -->
  <xsl:variable name="minIsDate">
    <xsl:call-template name="checkDate">
      <xsl:with-param name="test">
        <xsl:value-of select="@min"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>
  
  <!-- check if precision is valid -->
  <xsl:variable name="precisionIsValid">
    <xsl:call-template name="checkDatePrecision">
      <xsl:with-param name="test">
        <xsl:value-of select="@precision"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>

  <!-- write xfm:max restriction -->
  <xsl:if test="string-length(@max) &gt; 0 and 
                $maxIsDate='false'">
    <xsl:attribute name="xfm:max">
      <xsl:value-of select="@max"/>
    </xsl:attribute>
  </xsl:if>

  <!-- write xfm:min restriction -->
  <xsl:if test="string-length(@min) &gt; 0 and 
                $minIsDate='false'">
    <xsl:attribute name="xfm:min">
      <xsl:value-of select="@min"/>
    </xsl:attribute>
  </xsl:if>
  
  <!-- write xfm:precision restriction -->
  <xsl:if test="string-length(@precision) &gt; 0 and 
                $precisionIsValid='false'">
    <xsl:attribute name="xfm:precision">
      <xsl:value-of select="@precision"/>
    </xsl:attribute>
  </xsl:if>

  <!-- write xsd:max restriction -->
  <xsl:choose>
    <xsl:when test="$maxIsDate='true'">
      <xsl:element name="xsd:max">
        <xsl:attribute name="value">
          <xsl:value-of select="@max"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
    <xsl:when test="count(max) &gt; 0">
      <xsl:element name="xsd:max">
        <xsl:attribute name="value">
          <xsl:value-of select="max[1]"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>

  <!-- write xsd:min restriction -->
  <xsl:choose>
    <xsl:when test="$minIsDate='true'">
      <xsl:element name="xsd:min">
        <xsl:attribute name="value">
          <xsl:value-of select="@min"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
    <xsl:when test="count(min) &gt; 0">
      <xsl:element name="xsd:min">
        <xsl:attribute name="value">
          <xsl:value-of select="min[1]"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>
  
  <!-- write xsd:duration restriction -->
  <xsl:choose>
    <xsl:when test="$precisionIsValid='true'">
      <xsl:call-template name="writeDatePrecision">
        <xsl:with-param name="precision">
          <xsl:value-of select="@precision"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:when>
    <xsl:when test="count(precision) &gt; 0">
      <xsl:call-template name="writeDatePrecision">
        <xsl:with-param name="precision">
          <xsl:value-of select="precision[1]"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:when>
  </xsl:choose>
</xsl:template>


<!-- template:   name="writeDatePrecision"
     function:   writes the definitions to matche the precision 
                 attribute
     parameters: $precision: one of years, months, days
     output:     proper definition to allow only the requested 
                 precision
-->
<xsl:template name="writeDatePrecision">
  <xsl:param name="precision"/>

  <xsl:choose>
    <xsl:when test="$precision='years'">
      <xsl:element name="xsd:duration">
        <xsl:attribute name="value">P1Y</xsl:attribute>
      </xsl:element>
      <xsl:element name="xsd:pattern">
        <xsl:attribute name="value">\d*\d{4}</xsl:attribute>
      </xsl:element>
    </xsl:when>
    <xsl:when test="$precision='months'">
      <xsl:element name="xsd:duration">
        <xsl:attribute name="value">P1M</xsl:attribute>
      </xsl:element>
      <xsl:element name="xsd:pattern">
        <xsl:attribute name="value">\d*\d{4}-\d{2}</xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>
</xsl:template>



<!--
time element
-->

<!-- template:   matches="time"
     function:   converts a time into an xsd:time.
     parameters: none
     output:     converted definition
-->
<xsl:template match="time">
  <!-- create definition -->
  <xsl:variable name="definition">
    <xsl:element name="xsd:simpleType">
      <xsl:choose>
        <!-- if we have closed range, or no enumeration value, we can
             create simple type -->
        <xsl:when test="@range='closed' or 
                        count(value)=0">
          <xsl:element name="xsd:restriction">
            <xsl:attribute name="base">xsd:time</xsl:attribute>
            <xsl:call-template name="restrictTime"/>
            <xsl:apply-templates select="value"/>
          </xsl:element>
        </xsl:when>
        <xsl:otherwise>
          <xsl:element name="xsd:union">
            <xsl:element name="xsd:simpleType">
              <xsl:element name="xsd:restriction">
                <xsl:attribute name="base">xsd:time</xsl:attribute>
                <xsl:call-template name="restrictTime"/>
                <xsl:apply-templates select="value"/>
              </xsl:element>
            </xsl:element>
            <xsl:element name="xsd:simpleType">
              <xsl:element name="xsd:restriction">
                <xsl:attribute name="base">xsd:time</xsl:attribute>
                <xsl:call-template name="restrictTime"/>
              </xsl:element>
            </xsl:element>
          </xsl:element>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:element>
  </xsl:variable>

  <!-- if we have a name, we can create an element or attribute,
       otherwise we're part of a union -->
  <xsl:choose>
    <xsl:when test="string-length(@name) &gt; 0">
      <!-- create element -->
      <xsl:element name="xsd:element">
        <xsl:attribute name="name">
          <xsl:value-of select="@name"/>
        </xsl:attribute>
        <!-- check common attributes -->
        <xsl:call-template name="checkAttributes"/>
    
        <xsl:choose>
          <!-- if we have no children, and no other restrictions,
               we can make a short definition -->
          <xsl:when test='count(child::node())=0 and 
                          string-length(@min)=0  and
                          string-length(@max)=0  and
                          (string-length(@precision)=0 or 
                           @precision="seconds")'>
            <xsl:attribute name="type">xsd:time</xsl:attribute>
          </xsl:when>
          <xsl:otherwise>
            <!-- dump full definition -->
            <xsl:copy-of select="$definition"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:element>
    </xsl:when>
    <xsl:otherwise>
      <!-- just dumpe definition -->
      <xsl:copy-of select="$definition"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- template:   name="restrictTime"
     function:   add erstrictions to a time
     parameters: a time context node with the following attributes
                     @max
                     @min
                     @precision
                 and the following child elements
                     <min>
                     <max>
                     <precision>
     output:     elements to represent the restrictions
-->
<xsl:template name="restrictTime">
  
  <!-- check if max is a time -->
  <xsl:variable name="maxIsTime">
    <xsl:call-template name="checkTime">
      <xsl:with-param name="test">
        <xsl:value-of select="@max"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>
    
  <!-- check if min is a time -->
  <xsl:variable name="minIsTime">
    <xsl:call-template name="checkTime">
      <xsl:with-param name="test">
        <xsl:value-of select="@min"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>
  
  <!-- check if precision is valid -->
  <xsl:variable name="precisionIsValid">
    <xsl:call-template name="checkTimePrecision">
      <xsl:with-param name="test">
        <xsl:value-of select="@precision"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>

  <!-- write xfm:max restriction -->
  <xsl:if test="string-length(@max) &gt; 0 and 
                $maxIsTime='false'">
    <xsl:attribute name="xfm:max">
      <xsl:value-of select="@max"/>
    </xsl:attribute>
  </xsl:if>

  <!-- write xfm:min restriction -->
  <xsl:if test="string-length(@min) &gt; 0 and 
                $minIsTime='false'">
    <xsl:attribute name="xfm:min">
      <xsl:value-of select="@min"/>
    </xsl:attribute>
  </xsl:if>
  
  <!-- write xfm:precision restriction -->
  <xsl:if test="string-length(@precision) &gt; 0 and 
                $precisionIsValid='false'">
    <xsl:attribute name="xfm:precision">
      <xsl:value-of select="@precision"/>
    </xsl:attribute>
  </xsl:if>

  <!-- write xsd:max restriction -->
  <xsl:choose>
    <xsl:when test="$maxIsTime='true'">
      <xsl:element name="xsd:max">
        <xsl:attribute name="value">
          <xsl:value-of select="@max"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
    <xsl:when test="count(max) &gt; 0">
      <xsl:element name="xsd:max">
        <xsl:attribute name="value">
          <xsl:value-of select="max[1]"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>

  <!-- write xsd:min restriction -->
  <xsl:choose>
    <xsl:when test="$minIsTime='true'">
      <xsl:element name="xsd:min">
        <xsl:attribute name="value">
          <xsl:value-of select="@min"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
    <xsl:when test="count(min) &gt; 0">
      <xsl:element name="xsd:min">
        <xsl:attribute name="value">
          <xsl:value-of select="min[1]"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>
  
  <!-- write xsd:duration restriction -->
  <xsl:choose>
    <xsl:when test="$precisionIsValid='true'">
      <xsl:call-template name="writeTimePrecision">
        <xsl:with-param name="precision">
          <xsl:value-of select="@precision"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:when>
    <xsl:when test="count(precision) &gt; 0">
      <xsl:call-template name="writeTimePrecision">
        <xsl:with-param name="precision">
          <xsl:value-of select="precision[1]"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:when>
  </xsl:choose>
</xsl:template>


<!-- template:   name="writeTimePrecision"
     function:   writes the definitions to matche the precision 
                 attribute
     parameters: $precision: one of hours, minutes, seconds
     output:     proper definition to allow only the requested 
                 precision
-->
<xsl:template name="writeTimePrecision">
  <xsl:param name="precision"/>

  <xsl:choose>
    <xsl:when test="$precision='hours'">
      <xsl:element name="xsd:duration">
        <xsl:attribute name="value">PT60M</xsl:attribute>
      </xsl:element>
      <xsl:element name="xsd:pattern">
        <xsl:attribute name="value">
          <xsl:text>([01][0-9]|2[0-3])(:00(:00(.000)?)?)?</xsl:text>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
    <xsl:when test="$precision='minutes'">
      <xsl:element name="xsd:duration">
        <xsl:attribute name="value">PT60S</xsl:attribute>
      </xsl:element>
      <xsl:element name="xsd:pattern">
        <xsl:attribute name="value">
          <xsl:text>([01][0-9]|2[0-3])</xsl:text>
          <xsl:text>(:[0-5][0-9](:00(.000)?)?)?</xsl:text>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>
</xsl:template>



<!--
duration element
-->

<!-- template:   matches="duration"
     function:   converts a duration into an xsd:timeDuration.
     parameters: none
     output:     converted definition
-->
<xsl:template match="duration">
  <!-- create definition -->
  <xsl:variable name="definition">
    <xsl:element name="xsd:simpleType">
      <xsl:choose>
        <!-- if we have closed range, or no enumeration value, we can
             create simple type -->
        <xsl:when test="@range='closed' or 
                        count(value)=0">
          <xsl:element name="xsd:restriction">
            <xsl:attribute name="base">xsd:timeDuration</xsl:attribute>
            <xsl:call-template name="restrictDuration"/>
            <xsl:apply-templates select="value"/>
          </xsl:element>
        </xsl:when>
        <xsl:otherwise>
          <xsl:element name="xsd:union">
            <xsl:element name="xsd:simpleType">
              <xsl:element name="xsd:restriction">
                <xsl:attribute name="base">
                  <xsl:text>xsd:timeDuration</xsl:text>
                </xsl:attribute>
                <xsl:call-template name="restrictDuration"/>
                <xsl:apply-templates select="value"/>
              </xsl:element>
            </xsl:element>
            <xsl:element name="xsd:simpleType">
              <xsl:element name="xsd:restriction">
                <xsl:attribute name="base">
                  <xsl:text>xsd:timeDuration</xsl:text>
                </xsl:attribute>
                <xsl:call-template name="restrictDuration"/>
              </xsl:element>
            </xsl:element>
          </xsl:element>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:element>
  </xsl:variable>

  <!-- if we have a name, we can create an element or attribute,
       otherwise we're part of a union -->
  <xsl:choose>
    <xsl:when test="string-length(@name) &gt; 0">
      <!-- create element or attribute -->
      <xsl:element name="xsd:{@as}">
        <xsl:attribute name="name">
          <xsl:value-of select="@name"/>
        </xsl:attribute>
        <!-- check common attributes -->
        <xsl:call-template name="checkAttributes"/>
    
        <xsl:choose>
          <!-- if we have no children, and no other restrictions,
               we can make a short definition -->
          <xsl:when test='count(child::node())=0 and 
                          string-length(@min)=0  and
                          string-length(@max)=0  and
                          (string-length(@precision)=0 or 
                           @precision="seconds")'>
            <xsl:attribute name="type">xsd:timeDuration</xsl:attribute>
          </xsl:when>
          <xsl:otherwise>
            <!-- dump full definition -->
            <xsl:copy-of select="$definition"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:element>
    </xsl:when>
    <xsl:otherwise>
      <!-- just dumpe definition -->
      <xsl:copy-of select="$definition"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- template:   name="restrictDuration"
     function:   add erstrictions to a duration
     parameters: a duration context node with the following attributes
                     @max
                     @min
                     @precision
                 and the following child elements
                     <min>
                     <max>
                     <precision>
     output:     elements to represent the restrictions
-->
<xsl:template name="restrictDuration">
  
  <!-- check if max is a duration -->
  <xsl:variable name="maxIsDuration">
    <xsl:call-template name="checkDuration">
      <xsl:with-param name="test">
        <xsl:value-of select="@max"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>
    
  <!-- check if min is a duration -->
  <xsl:variable name="minIsDuration">
    <xsl:call-template name="checkDuration">
      <xsl:with-param name="test">
        <xsl:value-of select="@min"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>
  
  <!-- check if precision is valid -->
  <xsl:variable name="precisionIsValid">
    <xsl:variable name="test">
      <xsl:call-template name="checkDatePrecision">
        <xsl:with-param name="test">
          <xsl:value-of select="@precision"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:variable>
    
    <xsl:choose>
      <xsl:when test="$test='false'">
        <xsl:call-template name="checkTimePrecision">
          <xsl:with-param name="test">
            <xsl:value-of select="@precision"/>
          </xsl:with-param>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$test"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <!-- write xfm:max restriction -->
  <xsl:if test="string-length(@max) &gt; 0 and 
                $maxIsDuration='false'">
    <xsl:attribute name="xfm:max">
      <xsl:value-of select="@max"/>
    </xsl:attribute>
  </xsl:if>

  <!-- write xfm:min restriction -->
  <xsl:if test="string-length(@min) &gt; 0 and 
                $minIsDuration='false'">
    <xsl:attribute name="xfm:min">
      <xsl:value-of select="@min"/>
    </xsl:attribute>
  </xsl:if>
  
  <!-- write xfm:precision restriction -->
  <xsl:if test="string-length(@precision) &gt; 0 and 
                $precisionIsValid='false'">
    <xsl:attribute name="xfm:precision">
      <xsl:value-of select="@precision"/>
    </xsl:attribute>
  </xsl:if>

  <!-- write xsd:max restriction -->
  <xsl:choose>
    <xsl:when test="$maxIsDuration='true'">
      <xsl:element name="xsd:max">
        <xsl:attribute name="value">
          <xsl:value-of select="@max"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
    <xsl:when test="count(max) &gt; 0">
      <xsl:element name="xsd:max">
        <xsl:attribute name="value">
          <xsl:value-of select="max[1]"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>

  <!-- write xsd:min restriction -->
  <xsl:choose>
    <xsl:when test="$minIsDuration='true'">
      <xsl:element name="xsd:min">
        <xsl:attribute name="value">
          <xsl:value-of select="@min"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
    <xsl:when test="count(min) &gt; 0">
      <xsl:element name="xsd:min">
        <xsl:attribute name="value">
          <xsl:value-of select="min[1]"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>
  
  <!-- write xsd:duration restriction -->
  <xsl:choose>
    <xsl:when test="$precisionIsValid='true'">
      <xsl:call-template name="writeDurationPrecision">
        <xsl:with-param name="precision">
          <xsl:value-of select="@precision"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:when>
    <xsl:when test="count(precision) &gt; 0">
      <xsl:call-template name="writeDurationPrecision">
        <xsl:with-param name="precision">
          <xsl:value-of select="precision[1]"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:when>
  </xsl:choose>
</xsl:template>


<!-- template:   name="writeDurationPrecision"
     function:   writes the definitions to matche the precision 
                 attribute
     parameters: $precision: one of hours, minutes, seconds
     output:     proper definition to allow only the requested 
                 precision
-->
<xsl:template name="writeDurationPrecision">
  <xsl:param name="precision"/>

  <xsl:choose>
    <xsl:when test="$precision='years'">
      <xsl:element name="xsd:pattern">
        <xsl:attribute name="value">
          <xsl:text>P(\d+(\.\d+)?|\.\d+)Y</xsl:text>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
    <xsl:when test="$precision='months'">
      <xsl:element name="xsd:pattern">
        <xsl:attribute name="value">
          <xsl:text>P(\d+(\.\d+)?|\.\d+)Y|</xsl:text>
          <xsl:text>P(\d+Y)?(\d+(\.\d+)?|\.\d+)M</xsl:text>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
    <xsl:when test="$precision='days'">
      <xsl:element name="xsd:pattern">
        <xsl:attribute name="value">
          <xsl:text>P(\d+(\.\d+)?|\.\d+)Y|</xsl:text>
          <xsl:text>P(\d+Y)?(\d+(\.\d+)?|\.\d+)M|</xsl:text>
          <xsl:text>P(\d+Y)?(\d+M)?(\d+(\.\d+)?|\.\d+)D</xsl:text>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
    <xsl:when test="$precision='hours'">
      <xsl:element name="xsd:pattern">
        <xsl:attribute name="value">
          <xsl:text>P(\d+(\.\d+)?|\.\d+)Y|</xsl:text>
          <xsl:text>P(\d+Y)?(\d+(\.\d+)?|\.\d+)M|</xsl:text>
          <xsl:text>P(\d+Y)?(\d+M)?(\d+(\.\d+)?|\.\d+)D|</xsl:text>
          <xsl:text>P(\d+Y)?(\d+M)?(\d+D)?T(\d+(\.\d+)?|</xsl:text>
          <xsl:text>\.\d+)H</xsl:text>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
    <xsl:when test="$precision='minutes'">
      <xsl:element name="xsd:pattern">
        <xsl:attribute name="value">
          <xsl:text>P(\d+(\.\d+)?|\.\d+)Y|</xsl:text>
          <xsl:text>P(\d+Y)?(\d+(\.\d+)?|\.\d+)M|</xsl:text>
          <xsl:text>P(\d+Y)?(\d+M)?(\d+(\.\d+)?|\.\d+)D|</xsl:text>
          <xsl:text>P(\d+Y)?(\d+M)?(\d+D)?T(\d+(\.\d+)?|</xsl:text>
          <xsl:text>\.\d+)H|</xsl:text>
          <xsl:text>P(\d+Y)?(\d+M)?(\d+D)?T(\d+H)?</xsl:text>
          <xsl:text>(\d(\.\d+)?|\.\d+)M</xsl:text>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>
</xsl:template>



<!--
uri element
-->

<!-- template:   matches="uri"
     function:   converts a uri into an xsd:uriReference.
     parameters: none
     output:     converted definition
-->
<xsl:template match="uri">
  <!-- create definition -->
  <xsl:variable name="definition">
    <xsl:element name="xsd:simpleType">
      <xsl:choose>
        <!-- if we have closed range, or no enumeration value, we can
             create simple type -->
        <xsl:when test="@range='closed' or 
                        count(value)=0">
          <xsl:element name="xsd:restriction">
            <xsl:attribute name="base">xsd:uriReference</xsl:attribute>
            <xsl:call-template name="restrictUri"/>
            <xsl:apply-templates select="value"/>
          </xsl:element>
        </xsl:when>
        <xsl:otherwise>
          <xsl:element name="xsd:union">
            <xsl:element name="xsd:simpleType">
              <xsl:element name="xsd:restriction">
                <xsl:attribute name="base">
                  <xsl:text>xsd:uriReference</xsl:text>
                </xsl:attribute>
                <xsl:call-template name="restrictUri"/>
                <xsl:apply-templates select="value"/>
              </xsl:element>
            </xsl:element>
            <xsl:element name="xsd:simpleType">
              <xsl:element name="xsd:restriction">
                <xsl:attribute name="base">
                  <xsl:text>xsd:uriReference</xsl:text>
                </xsl:attribute>
                <xsl:call-template name="restrictUri"/>
              </xsl:element>
            </xsl:element>
          </xsl:element>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:element>
  </xsl:variable>

  <!-- if we have a name, we can create an element or attribute,
       otherwise we're part of a union -->
  <xsl:choose>
    <xsl:when test="string-length(@name) &gt; 0">
      <!-- create element -->
      <xsl:element name="xsd:element">
        <xsl:attribute name="name">
          <xsl:value-of select="@name"/>
        </xsl:attribute>
        <!-- check common attributes -->
        <xsl:call-template name="checkAttributes"/>
    
        <xsl:choose>
          <!-- if we have no children, and no other restrictions,
               we can make a short definition -->
          <xsl:when test='count(child::node())=0 and 
                          string-length(@scheme)=0'>
            <xsl:attribute name="type">xsd:uriReference</xsl:attribute>
          </xsl:when>
          <xsl:otherwise>
            <!-- dump full definition -->
            <xsl:copy-of select="$definition"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:element>
    </xsl:when>
    <xsl:otherwise>
      <!-- just dumpe definition -->
      <xsl:copy-of select="$definition"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- template:   name="restrictUri"
     function:   add restrictions to a uri
     parameters: a duration context node with the following attributes
                     @scheme
                 and the following child elements
                     <scheme>
     output:     elements to represent the restrictions
-->
<xsl:template name="restrictUri">

  <!-- make pattern from scheme -->
  <xsl:variable name="pattern">
    <xsl:for-each select="scheme">
      <xsl:call-template name="convertScheme">
        <xsl:with-param name="scheme">
          <xsl:value-of select="."/>
        </xsl:with-param>
      </xsl:call-template>
      <xsl:if test="not(position()=last())">
        <xsl:text>|</xsl:text>
      </xsl:if>
    </xsl:for-each>
    
    <xsl:if test="@scheme">
      <xsl:if test="count(scheme) &gt; 0">
        <xsl:text>|</xsl:text>
      </xsl:if>
      <xsl:call-template name="convertScheme">
        <xsl:with-param name="scheme">
          <xsl:value-of select="@scheme"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:if>
  </xsl:variable>

  <xsl:if test="string-length($pattern) &gt; 0">
    <xsl:element name="xsd:pattern">
      <xsl:attribute name="value">
        <xsl:value-of select="$pattern"/>
      </xsl:attribute>
    </xsl:element>
  </xsl:if>
</xsl:template>


<!-- template:   name="convertScheme"
     function:   converts a scheme to a pattern
     parameters: scheme     : the scheme to transform
     output:     a pattern with the same meaning
-->
<xsl:template name="convertScheme">
  <xsl:param name="scheme"/>

  <xsl:choose>
    <xsl:when test="contains($scheme, ' ')">
      <!-- splitt scheme -->
      <xsl:call-template name="convertScheme">
        <xsl:with-param name="scheme">
          <xsl:value-of select="substring-before($scheme, ' ')"/>
        </xsl:with-param>
      </xsl:call-template>
      <xsl:text>|</xsl:text>
      <xsl:call-template name="convertScheme">
        <xsl:with-param name="scheme">
          <xsl:value-of select="substring-after($scheme, ' ')"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:text>(</xsl:text>
      <xsl:choose>
        <xsl:when test="$scheme='mailto'">
          <xsl:value-of select="$scheme"/>
          <xsl:text>:.*</xsl:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$scheme"/>
          <xsl:text>://.*</xsl:text>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:text>)</xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>



<!--
binary element
-->

<!-- template:   matches="binary"
     function:   converts a binary into an xsd:binary.
     parameters: none
     output:     converted definition
-->
<xsl:template match="binary">
  <!-- create definition -->
  <xsl:variable name="definition">
    <xsl:element name="xsd:simpleType">
       <xsl:element name="xsd:restriction">
         <xsl:attribute name="base">xsd:binary</xsl:attribute>
         <xsl:call-template name="restrictBinary"/>
       </xsl:element>
    </xsl:element>
  </xsl:variable>

  <!-- if we have a name, we can create an element or attribute,
       otherwise we're part of a union -->
  <xsl:choose>
    <xsl:when test="string-length(@name) &gt; 0">
      <!-- create element -->
      <xsl:element name="xsd:element">
        <xsl:attribute name="name">
          <xsl:value-of select="@name"/>
        </xsl:attribute>
        <!-- check common attributes -->
        <xsl:call-template name="checkAttributes"/>
    
        <xsl:choose>
          <!-- if we have no children, and no other restrictions,
               we can make a short definition -->
          <xsl:when test='count(child::node())=0 and 
                          string-length(@type)=0'>
            <xsl:attribute name="type">xsd:binary</xsl:attribute>
          </xsl:when>
          <xsl:otherwise>
            <!-- dump full definition -->
            <xsl:copy-of select="$definition"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:element>
    </xsl:when>
    <xsl:otherwise>
      <!-- just dumpe definition -->
      <xsl:copy-of select="$definition"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- template:   name="restrictBinary"
     function:   add erstrictions to a binary
     parameters: a duration context node with the following attributes
                     @length
                     @max
                     @min
                     @mediaType
                 and the following child elements
                     <length>
                     <min>
                     <max>
                     <mediaType>
     output:     elements to represent the restrictions
-->
<xsl:template name="restrictBinary">
  
  <!-- converte list of types into media attribute -->
  <xsl:attribute name="xfm:mediaType">
    <xsl:for-each select="mediaType">
      <xsl:variable name="isMedia">
        <xsl:call-template name="checkMedia">
          <xsl:with-param name="test">
            <xsl:value-of select="."/>
          </xsl:with-param>
        </xsl:call-template>
      </xsl:variable>
      <xsl:if test="$isMedia='true'">
        <xsl:value-of select="."/>
        <xsl:if test="not(position()=last())">
          <xsl:text> </xsl:text>
        </xsl:if>
      </xsl:if>
    </xsl:for-each>
    
    <xsl:if test="not(string-length(@mediaType)=0)">
      <xsl:text> </xsl:text>
      <xsl:variable name="isMedia">
        <xsl:call-template name="checkMedia">
          <xsl:with-param name="test">
            <xsl:value-of select="@mediaType"/>
          </xsl:with-param>
        </xsl:call-template>
      </xsl:variable>
      <xsl:if test="isMedia='true'">
        <xsl:value-of select="@mediaType"/>
      </xsl:if>
    </xsl:if>
  </xsl:attribute>

  <!-- check if @length is an non negative integer -->
  <xsl:variable name="lengthIsNNI">
    <xsl:call-template name="checkNonNegInt">
      <xsl:with-param name="test">
        <xsl:value-of select="@length"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>

  <!-- check if @max is an non negative integer -->
  <xsl:variable name="maxIsNNI">
    <xsl:call-template name="checkNonNegInt">
      <xsl:with-param name="test">
        <xsl:value-of select="@max"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>

  <!-- check if @min as an non negative integer -->
  <xsl:variable name="minIsNNI">
    <xsl:call-template name="checkNonNegInt">
      <xsl:with-param name="test">
        <xsl:value-of select="@min"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:variable>
  
  <!-- write xfm:length restriction -->
  <xsl:if test="string-length(@length) &gt; 0 and
                not(@length=$maxLengthSpecial) and
                $lengthIsNNI='false'">
    <xsl:attribute name="xfm:length">
      <xsl:value-of select="@length"/>
    </xsl:attribute>
  </xsl:if>
  
  <!-- write xfm:maxLength restriction -->
  <xsl:if test="string-length(@max) &gt; 0 and
                not(@max=$maxLengthSpecial) and
                $maxIsNNI='false'">
    <xsl:attribute name="xfm:maxLength">
      <xsl:value-of select="@max"/>
    </xsl:attribute>
  </xsl:if>
  
  <!-- write xfm:minLength restriction -->
  <xsl:if test="string-length(@min) &gt; 0 and
                not(@min='0') and
                $minIsNNI='false'">
    <xsl:attribute name="xfm:minLength">
      <xsl:value-of select="@min"/>
    </xsl:attribute>
  </xsl:if>
  
  <!-- write xsd:length restriction -->
  <xsl:choose>
    <xsl:when test="$lengthIsNNI='true'">
      <xsl:if test="not(@length=$maxLengthSpecial)">
        <xsl:element name="xsd:length">
          <xsl:attribute name="value">
            <xsl:value-of select="@length"/>
          </xsl:attribute>
        </xsl:element>
      </xsl:if>
    </xsl:when>
    <xsl:when test="count(length) &gt; 0">
      <xsl:element name="xsd:length">
        <xsl:attribute name="value">
          <xsl:value-of select="length[1]"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>
  
  <!-- write xsd:maxLength restriction -->
  <xsl:choose>
    <xsl:when test="$maxIsNNI='true'">
      <xsl:if test="not(@max=$maxLengthSpecial)">
        <xsl:element name="xsd:maxLength">
          <xsl:attribute name="value">
            <xsl:value-of select="@max"/>
          </xsl:attribute>
        </xsl:element>
      </xsl:if>
    </xsl:when>
    <xsl:when test="count(max) &gt; 0">
      <xsl:element name="xsd:maxLength">
        <xsl:attribute name="value">
          <xsl:value-of select="max[1]"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>
  
  <!-- write xsd:minLength restriction -->
  <xsl:choose>
    <xsl:when test="$minIsNNI='true'">
      <xsl:if test="not(@min='0')">
        <xsl:element name="xsd:minLength">
          <xsl:attribute name="value">
            <xsl:value-of select="@min"/>
          </xsl:attribute>
        </xsl:element>
      </xsl:if>
    </xsl:when>
    <xsl:when test="count(min) &gt; 0">
      <xsl:element name="xsd:min">
        <xsl:attribute name="value">
          <xsl:value-of select="min[1]"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:when>
  </xsl:choose>
</xsl:template>



<!--
element element
-->

<!-- template:   matches="element"
     function:   converts a element into an xsd:element.
     parameters: none
     output:     converted definition
-->
<xsl:template match="element">
  <xsl:choose>
    <xsl:when test="string-length(@name)=0">
      <xsl:message terminate="no">
        An anonymous element definition is not supported.
      </xsl:message>
      <xsl:comment> Anonymous element definition dropped </xsl:comment>
    </xsl:when>
    <xsl:otherwise>
      <xsl:element name="xsd:element">
        <xsl:attribute name="name">
          <xsl:value-of select="@name"/>
        </xsl:attribute>
        
        <!-- check common attributes -->
        <xsl:call-template name="checkAttributes"/>
        
        <xsl:attribute name="type">
          <xsl:value-of select="@type"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>



<!--
value element
-->

<!-- template:   matches="value"
     function:   converte value into an enumeration.
     parameters: none
     output:     <enumeration> that represents the value
-->
<xsl:template match="value">
  <xsl:element name="xsd:enumeration">
    <xsl:attribute name="value">
      <xsl:value-of select="."/>
    </xsl:attribute>
  </xsl:element>
</xsl:template>



<!--
Named templates
-->

<!--
Datatype checks
-->

<!-- template:   name="checkXpression"
     function:   checks if a given string is an Xpression or not
     parameter:  test
     output:     true   if it's an Xpression
                 false  otherwise
     note:       this can not work, it must always return true.
                 But perhapes it can be made to work later
-->
<xsl:template name="checkXpression">
  <xsl:param name="test"/>

  <!-- we can not test this, so we must return true -->
  <xsl:text>true</xsl:text>
</xsl:template>


<!-- template:   name="checkBoolean"
     function:   check if $test is a boolean
     parameters: test
     output:     true   if it's a boolean
                 false  otherwise
-->
<xsl:template name="checkBoolean">
  <xsl:param name="test"/>

  <xsl:choose>
    <xsl:when test="true">
      <xsl:text>true</xsl:text>
    </xsl:when>
    <xsl:when test="false">
      <xsl:text>true</xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:text>false</xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- template:   name="checkNumber"
     function:   check if $test is a number
     parameters: test
     output:     true   if it's a number
                 false  otherwise
-->
<xsl:template name="checkNumber">
  <xsl:param name="test"/>

  <xsl:variable name="number">
    <xsl:value-of select="number($test)"/>
  </xsl:variable>

  <xsl:choose>
    <xsl:when test="$number='NaN'">
      <xsl:text>false</xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:text>true</xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- template:   name="checkNonNegInt"
     function:   check if $test is a non negativ integer
     parameters: test
     output:     true   if it's a non negativ integer
                 false  otherwise
-->
<xsl:template name="checkNonNegInt">
  <xsl:param name="test"/>

  <xsl:variable name="number">
    <xsl:value-of select="number($test)"/>
  </xsl:variable>

  <xsl:choose>
    <xsl:when test="$number='NaN'">
      <xsl:text>false</xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="integer">
        <xsl:value-of select="round($number)"/>
      </xsl:variable>
      <xsl:choose>
        <xsl:when test="not($integer=$number)">
          <xsl:text>false</xsl:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:choose>
            <xsl:when test="$integer &lt; 0">
              <xsl:text>false</xsl:text>
            </xsl:when>
            <xsl:otherwise>
              <xsl:text>true</xsl:text>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- template:   name="checkDate"
     function:   checks if a given string is a date or not
     parameter:  test   :the string to test
     output:     true   if it's a date
                 false  otherwise
     note:       this does not work, it always returns false
-->
<xsl:template name="checkDate">
  <xsl:param name="test"/>
 
  <xsl:text>false</xsl:text>
</xsl:template>


<!-- template:   name="checkTime"
     function:   checks if a given string is a time or not
     parameter:  test   :the string to test
     output:     true   if it's a time
                 false  otherwise
     note:       this does not work, it always returns false
-->
<xsl:template name="checkTime">
  <xsl:param name="test"/>
 
  <xsl:text>false</xsl:text>
</xsl:template>


<!-- template:   name="checkDuration"
     function:   checks if a given string is a duration or not
     parameter:  test   :the string to test
     output:     true   if it's a duration
                 false  otherwise
     note:       this does not work, it always returns false
-->
<xsl:template name="checkDuration">
  <xsl:param name="test"/>
 
  <xsl:text>false</xsl:text>
</xsl:template>


<!-- template:   name="checkDatePrecision"
     function:   checks if a given string is a valid precision for a 
                 date
     parameter:  test
     output:     true   if it is 
                 false  otherwise
-->
<xsl:template name="checkDatePrecision">
  <xsl:param name="test"/>

  <xsl:choose>
    <xsl:when test="$test='years'">
      <xsl:text>true</xsl:text>
    </xsl:when>
    <xsl:when test="$test='months'">
      <xsl:text>true</xsl:text>
    </xsl:when>
    <xsl:when test="$test='dayss'">
      <xsl:text>true</xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:text>false</xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- template:   name="checkTimePrecision"
     function:   checks if a given string is a valid precision for a 
                 time
     parameter:  test
     output:     true   if it is 
                 false  otherwise
-->
<xsl:template name="checkTimePrecision">
  <xsl:param name="test"/>

  <xsl:choose>
    <xsl:when test="$test='hours'">
      <xsl:text>true</xsl:text>
    </xsl:when>
    <xsl:when test="$test='minutes'">
      <xsl:text>true</xsl:text>
    </xsl:when>
    <xsl:when test="$test='seconds'">
      <xsl:text>true</xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:text>false</xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>


<!-- template:   name="checkMedia"
     function:   checks is a string is a valid mimetype
     parameters: test       : the string to test
     output:     true       : is it's a valid mimetype
                 false      : otherwise
     note:       does not work, always returns false
-->
<xsl:template name="checkMedia">
  <xsl:param name="test"/>
  
  <xsl:text>false</xsl:text>
</xsl:template>



<!--
Common attributes
-->

<!-- template:   name="checkAttributes"
     function:   check the common XForms attributes and produces
                 apropriated attributes
     parameters: a context node, with the following attributes
                 @id        ()
                 @required  (false)
                 @relevant  (false)
                 @readOnly  (false)
                 @calc      ()
                 @choices   ()
                 @validate  ()
     glob. var.: $maxOccursSpecial            
     output:     transformation of attributes
-->
<xsl:template name="checkAttributes">
  <!-- copy ID, if any -->
  <xsl:if test="string-length(@id) &gt; 0">
    <xsl:attribute name="id">
      <xsl:value-of select="@id"/>
    </xsl:attribute>
  </xsl:if>
 
  <!-- check if this element is optional, it is optional, 
       if: it's not relevant or it's not required, or it's 
       minOccurs = 0 -->
  <xsl:choose>
    <xsl:when test="@relevant='true'">
      <xsl:choose>
        <xsl:when test="@required='true'">
          <xsl:if test="not(@minOccurs='1')">
            <!-- check if $minOccurs if a non negative integer -->
            <xsl:variable name="nn">
              <xsl:call-template name="checkNonNegInt">
                <xsl:with-param name="test">
                  <xsl:value-of select="@minOccurs"/>
                </xsl:with-param>
              </xsl:call-template>
            </xsl:variable>
            <xsl:choose>
              <xsl:when test="$nn='false'">
                <!-- if it's not, the element needs not to occur in 
                     a Schema -->
                <xsl:if test="not(name(..)='model' or name(..)='simple')">
                  <!-- root elements must not have minOccurs -->
                  <xsl:attribute name="minOccurs">foo0</xsl:attribute>
                </xsl:if>
                <!-- but preserve it in the xfm namespace -->
                <xsl:attribute name="xfm:minOccurs">
                  <xsl:value-of select="@minOccurs"/>
                </xsl:attribute>
              </xsl:when>
              <xsl:otherwise>
                <!-- minOccurs is a non negative Integer, so we can
                     have the Schema follow the restriction -->
                <xsl:if test="not(name(..)='model' or name(..)='simple')">
                  <xsl:attribute name="minOccurs">
                    <xsl:value-of select="@minOccurs"/>
                  </xsl:attribute>
                </xsl:if>
              </xsl:otherwise>
            </xsl:choose>
            <!-- there is no else, because the default for minOccurs 
                 in Schemas is 1 -->
          </xsl:if>
        </xsl:when>
        <xsl:otherwise>
          <xsl:if test="not(name(..)='model' or name(..)='simple')">
            <!-- root elements must not have minOccurs -->
            <xsl:attribute name="minOccurs">foo10</xsl:attribute>
          </xsl:if>
          <!-- preserver required and minOccirs in xfm namespace -->
          <xsl:attribute name="xfm:required">
            <xsl:value-of select="@required"/>
          </xsl:attribute>
          <xsl:attribute name="xfm:minOccurs">
            <xsl:value-of select="@minOccurs"/>
          </xsl:attribute>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:if test="not(name(..)='model' or name(..)='simple')">
        <!-- root elements must not have minOccurs -->
        <xsl:attribute name="minOccurs">foo20</xsl:attribute>
      </xsl:if>
      <!-- preserver relevant, required and minOccurs in xfm 
           namespace -->
      <xsl:if test="not(string-length(@relevant)=0 or @relevant='false')">
        <xsl:attribute name="xfm:relevant">
          <xsl:value-of select="@relevant"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:if test="not(string-length(@required)=0 or @required='false')">
        <xsl:attribute name="xfm:required">
          <xsl:value-of select="@required"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:if test="not(string-length(@minOccurs)=0 or @minOccurs='1')">
        <xsl:attribute name="xfm:minOccurs">
          <xsl:value-of select="@minOccurs"/>
        </xsl:attribute>
      </xsl:if>
    </xsl:otherwise>
  </xsl:choose>
  
  <!-- check maxOccurs, it can be: "unbounded", "1" (default), a none
       negative integer, or an expression -->
  <xsl:choose>
    <xsl:when test="@maxOccurs=$maxOccursSpecial">
      <!-- copy it into the Schema -->
      <xsl:if test="not(name(..)='model' or name(..)='simple')">
        <!-- root elements must not have maxOccurs -->
        <xsl:attribute name="maxOccurs">unbounded</xsl:attribute>
      </xsl:if>
    </xsl:when>
    <xsl:when test="not(@maxOccurs='1')">
      <!-- check if $maxOccurs if a non negative integer -->
      <xsl:variable name="nn">
        <xsl:call-template name="checkNonNegInt">
          <xsl:with-param name="test">
            <xsl:value-of select="@maxOccurs"/>
          </xsl:with-param>
        </xsl:call-template>
      </xsl:variable>
      <xsl:choose>
        <xsl:when test="$nn='false'">
          <!-- if it's not, the element may occur an unlimited number 
               of times in a Schema -->
          <xsl:if test="not(name(..)='model' or name(..)='simple')">
            <!-- root elements must not have maxOccurs -->
            <xsl:attribute name="maxOccurs">unbounded</xsl:attribute>
          </xsl:if>
          <!-- but preserve maxOccurs it in the xfm namespace -->
          <xsl:if test="not(@maxOccurs='unbounded')">
            <xsl:attribute name="xfm:maxOccurs">
              <xsl:value-of select="@maxOccurs"/>
            </xsl:attribute>
          </xsl:if>
        </xsl:when>
        <xsl:otherwise>
          <!-- maxOccurs is a non negative Integer, so we can
               have the Schema follow the restriction -->
          <xsl:if test="not(name(..)='model' or name(..)='simple')">
            <!-- root elements must not have maxOccurs -->
            <xsl:attribute name="maxOccurs">
              <xsl:value-of select="@maxOccurs"/>
            </xsl:attribute>
          </xsl:if>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <!-- there is no otherwise, because the default for maxOccurs in 
         Schemas is 1 -->
  </xsl:choose>

  <!-- readOnly is of general interest, but can only be mapped into the
       xfm namespace -->
  <xsl:if test="not(string-length(@readOnly)=0 or @readOnly='false')">
    <xsl:attribute name="xfm:readOnly">
      <xsl:value-of select="@readOnly"/>
    </xsl:attribute>
  </xsl:if>
  
  <!-- validate is of general interest, but can only be mapped into the
       xfm namespace -->
  <xsl:if test="not(string-length(@validate)=0 or @validate='true')">
    <xsl:attribute name="xfm:validate">
      <xsl:value-of select="@validate"/>
    </xsl:attribute>
  </xsl:if>
  
  <!-- calc is of general interest, but can only be mapped into the
       xfm namespace -->
  <xsl:if test="string-length(@calc) &gt; 0">
    <xsl:attribute name="xfm:calc">
      <xsl:value-of select="@calc"/>
    </xsl:attribute>
  </xsl:if>
  
  <!-- choices is of general interest, but can only be mapped into the
       xfm namespace -->
  <xsl:if test="string-length(@choices) &gt; 0">
    <xsl:attribute name="xfm:choices">
      <xsl:value-of select="@choices"/>
    </xsl:attribute>
  </xsl:if>
</xsl:template>

</xsl:transform>

B.2 Required DTD for Transformation

<?xml version="1.0"?>
<!-- DTD for XForms -->

<!-- ENTITY definitions -->

<!-- Taken from the Schema definition:
     can be overritten in the internal subset of a xforms document to
     establish a namespace prefix -->
<!ENTITY % p         ''>
<!-- add optional namespace to all elements -->
<!ENTITY % xform     "%p;xform">
<!ENTITY % model     "%p;model">
<!ENTITY % submit    "%p;submit">
<!ENTITY % instance  "%p;instance">
<!ENTITY % bind      "%p;bind">
<!ENTITY % simple    "%p;simple">

<!-- data types -->
<!ENTITY % string    "%p;string">
<!ENTITY % boolean   "%p;boolean">
<!ENTITY % number    "%p;number">
<!ENTITY % currency  "%p;currency">
<!ENTITY % money     "%p;money">
<!ENTITY % date      "%p;date">
<!ENTITY % time      "%p;time">
<!ENTITY % duration  "%p;duration">
<!ENTITY % uri       "%p;uri">
<!ENTITY % binary    "%p;binary">
<!ENTITY % element   "%p;element">
<!ENTITY % attribute "%p;attribute">
<!ENTITY % null      "%p;null">

<!ENTITY % datatype  "%string;|%boolean;|%number;|%currency;|%money;|
                      %date;|%time;|%duration;|%uri;|%binary;">

<!ENTITY % group     "%p;group">
<!ENTITY % union     "%p;union">
<!ENTITY % array     "%p;array">
<!ENTITY % switch    "%p;switch">
<!ENTITY % case      "%p;case">

<!-- facets -->
<!ENTITY % mask          "%p;mask">
<!ENTITY % pattern       "%p;pattern">
<!ENTITY % mediaType     "%p;mediaType">
<!ENTITY % scheme        "%p;scheme">
<!ENTITY % value         "%p;value">
<!ENTITY % allowCurrency "%p;allowCurrency">
<!ENTITY % length        "%p;length">
<!ENTITY % max           "%p;max">
<!ENTITY % min           "%p;min">
<!ENTITY % precision     "%p;precision">
<!ENTITY % scale         "%p;scale">
<!-- common datatype facets -->
<!ENTITY % cdf           "%value;">


<!-- attribute names -->
<!ENTITY % URIref    "CDATA">
<!ENTITY % bool      "(true|false)">
<!ENTITY % datesteps "years|months|days">
<!ENTITY % timesteps "hours|minutes|seconds">

<!ENTITY % name        "name        NMTOKEN       #IMPLIED">
<!-- NOTE: while a name is required, it can not be a required attribute
           as the union defines a name and the elements don't need a 
           name in this case -->
<!ENTITY % id          "id          ID            #IMPLIED">
<!ENTITY % ref         "ref         %URIref;      #IMPLIED"> 
<!ENTITY % readOnly    "readOnly    CDATA         'false'">
<!ENTITY % required    "required    CDATA         'true'">
<!-- NOTE: while required is a boolean field, the real value can come 
           from an expression, this is a text -->
<!ENTITY % relevant    "relevant    CDATA         'true'">
<!-- NOTE: while relevant is a boolean field, the real value can come
           from an expression, this is a text -->
<!ENTITY % enum        "enum        (open|closed) 'open'">
<!ENTITY % choices     "choices     CDATA         #IMPLIED">
<!ENTITY % calc        "calc        CDATA         #IMPLIED">
<!ENTITY % validate    "validate    CDATA         'true'">
<!ENTITY % condition   "condition   CDATA         'true'">
<!ENTITY % minOccurs   "minOccurs   CDATA         '1'">
<!ENTITY % maxOccurs   "maxOccurs   CDATA         '1'">
<!-- NOTE: The special value "unbounded" represents an unlimited 
     repetition. -->
<!ENTITY % precisiona  "precision   CDATA         'unlimited'">
<!ENTITY % scalea      "scale       CDATA         'unlimited'">

<!-- common attributes -->
<!ENTITY % comatt     "%name; 
                       %id;
                       %required;
                       %relevant;
                       %readOnly;
                       %validate;" >
<!-- data type attributes -->
<!ENTITY % dtattr     "%comatt; 
                       %enum;" >
<!-- simpel data type attributes -->
<!ENTITY % sdtattr    "%dtattr;
                       %calc; 
                       %choices;
                       %minOccurs;
                       %maxOccurs;" >
<!-- NOTE: I've added minOccurs and mxOccurs while they are not explicitely
           in the spec -->
<!-- NOTE: I would have liked to include min and max here, but there
           are element specific defaults that can not be generalised 
     -->
                      

<!-- ELEMENT definitions -->

<!ELEMENT %xform; ((%submit;)*,(%model;)*,(%instance;)*,(%bind;)*)>
<!ATTLIST %xform; action  %URIref;    #IMPLIED
                  method  CDATA       #IMPLIED
                  id      ID          #IMPLIED >
                  
<!ELEMENT %submit; ANY>
<!-- NOTE: the syntax for submit is not finalized, so I allow anything -->
<!ELEMENT %bind;   ANY>
<!-- NOTE: the syntac for bind is not finalized, so I allow anything -->
<!ELEMENT %instance; ANY>
<!-- NOTE: there's no way to tell a validating parser to ignore the 
           content of an element, if it has child elements, therefor
           no xform with an instance can ever be valid -->


<!ELEMENT %model; (%simple;|%group;|%array;|%union;|%switch;|
                   %datatype;|%element;)*>
<!ATTLIST %model; %id;
                  %ref; >


<!ELEMENT %simple; (%group;|%array;|%union;|%switch;|%datatype;|%element;)*>
<!ATTLIST %simple; %id;
                   %ref;
                   %name; >
                   

<!ELEMENT %group; (%group;|%array;|%union;|%switch;|%datatype;|
                   %element;|%attribute;)*>
<!ATTLIST %group; %comatt;
                  %minOccurs;
                  %maxOccurs; >


<!ELEMENT %switch; (%case;,(%case;)+)>
<!ATTLIST %switch; %comatt; 
                   %minOccurs;
                   %maxOccurs; >


<!ELEMENT %case; (%datatype;|%element;)*>
<!ATTLIST %case; %name;
                 %condition; >


<!ELEMENT %union; ((%datatype;)+)>
<!ATTLIST %union; %comatt;
                  %minOccurs;
                  %maxOccurs; >


<!ELEMENT %string; (%cdf;|%length;|%mask;|%max;|%min;|%pattern;)*>
<!ATTLIST %string; %sdtattr;
                   length   CDATA  #IMPLIED
                   max      CDATA  "unlimited"
                   min      CDATA  "0"
                   mask     CDATA  #IMPLIED
                   pattern  CDATA  #IMPLIED >
<!-- NOTE: there can be any number of masks and patterns, an entry 
           that matches any mask/pattern is valide 
           (e.i., they are ORed) -->

<!ELEMENT %length; (#PCDATA)*>

<!ELEMENT %mask;   (#PCDATA)*>

<!ELEMENT %max;    (#PCDATA)*>

<!ELEMENT %min;    (#PCDATA)*>

<!ELEMENT %pattern; (#PCDATA)*>


<!ELEMENT %value; (#PCDATA|%null;)*>

<!ELEMENT %null; EMPTY>


<!ELEMENT %boolean; EMPTY>
<!ATTLIST %boolean; %comatt;
                    %calc; 
                    %minOccurs;
                    %maxOccurs; >


<!ELEMENT %number; (%cdf;|%max;|%min;|%precision;|%scale;)*>
<!ATTLIST %number; %sdtattr;
                   min       CDATA  "minus infinity"
                   max       CDATA  "plus infinity"
                   %precisiona;
                   %scalea;>

<!ELEMENT %precision; (#PCDATA)*>

<!ELEMENT %scale;     (#PCDATA)*>


<!ELEMENT %currency; (%cdf;|%mask;)*>
<!ATTLIST %currency; %sdtattr;
                     mask     CDATA  #IMPLIED >


<!ELEMENT %money; (%cdf;|%allowCurrency;|%max;|%min;|%precision;|%scale;)*>
<!ATTLIST %money; %sdtattr;
                  min            CDATA  "minus infinity"
                  max            CDATA  "plus infinity"
                  %precisiona;
                  scale          CDATA  "2"
                  allowCurrency  CDATA  #IMPLIED >

<!ELEMENT %allowCurrency; (#PCDATA)*>


<!ELEMENT %date; (%cdf;|%max;|%min;|%precision;)*>
<!ATTLIST %date; %sdtattr;
                 min  CDATA   #IMPLIED
                 max  CDATA   #IMPLIED
                 precision (%datesteps;) #IMPLIED>
<!-- NOTE: the special value of "now" for min and max indecate the 
           current time -->


<!ELEMENT %time; (%cdf;|%max;|%min;|%precision;)*>
<!ATTLIST %time; %sdtattr;
                 min  CDATA   #IMPLIED
                 max  CDATA   #IMPLIED
                 precision (%timesteps;) #IMPLIED >
<!-- NOTE: The time zone is expressed as hours relative to UTC -->


<!ELEMENT %duration; (%cdf;|%max;|%min;|%precision;)*>
<!ATTLIST %duration; %sdtattr;
                     precision (%datesteps;|%timesteps;) #IMPLIED
                     min  CDATA   #IMPLIED
                     max  CDATA   #IMPLIED >


<!ELEMENT %uri; (%cdf;|%length;|%max;|%min;|%scheme;)*>
<!ATTLIST %uri; %sdtattr;
                length   CDATA  #IMPLIED
                max      CDATA  "unlimited"
                min      CDATA  "0"
                scheme   CDATA  #IMPLIED>

<!ELEMENT %scheme; (#PCDATA)>
              

<!ELEMENT %binary; (%cdf;|%mediaType;|%length;|%max;|%min;)*>
<!ATTLIST %binary; %sdtattr;
                   length    CDATA  #IMPLIED
                   max       CDATA  "unlimited"
                   min       CDATA  "0"
                   mediaType CDATA  #IMPLIED >

<!ELEMENT %mediaType; (#PCDATA)*>


<!ELEMENT %element; EMPTY>
<!ATTLIST %element; %comatt;
                    type   CDATA   #REQUIRED
                    %minOccurs;
                    %maxOccurs; >