Project

Profile

Help

Bug #6598 » xsd.xsl

Norm Tovey-Walsh, 2024-11-27 14:19

 
<!DOCTYPE xsl:stylesheet [
<!--*
<!DOCTYPE xsl:stylesheet PUBLIC 'http://www.w3.org/1999/XSL/Transform'
'../../People/cmsmcq/lib/xslt10.dtd' [
*-->
<!ATTLIST xsl:stylesheet
xmlns:xsl CDATA "http://www.w3.org/1999/XSL/Transform"
xmlns:xsd CDATA #IMPLIED
xmlns:xhtml CDATA #IMPLIED
>
<!ATTLIST xsl:text
xmlns:xsl CDATA "http://www.w3.org/1999/XSL/Transform"
>

<!ENTITY copy "&#169;" ><!--=copyright sign-->
<!ENTITY reg "&#174;" ><!--/circledR =registered sign-->
<!ENTITY rarr "&#x2192;" ><!--/rightarrow /to A: =rightward arrow-->

<!ENTITY nl "&#xA;">
<!ENTITY lsquo "&#x2018;" ><!--=single quotation mark, left-->
<!ENTITY rsquo "&#x2019;" ><!--=single quotation mark, right-->
<!ENTITY ldquo "&#x201C;" ><!--=double quotation mark, left-->
<!ENTITY rdquo "&#x201D;" ><!--=double quotation mark, right-->

]>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
>

<!--* xsd.xsl: format an XSD schema document for simple display in a Web browser.
* http://www.w3.org/XML/2004/xml-schema-test-suite/xsd.xsl
*
* Copyright © 2008-2009 World Wide Web Consortium, (Massachusetts
* Institute of Technology, European Research Consortium for
* Informatics and Mathematics, Keio University). All Rights
* Reserved. This work is distributed under the W3C® Software
* License [1] in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
*
*-->

<!--* Revisions:
* 2012-05-03 : CMSMcQ : reissue under Software License, not document
* license
* 2009-01-21 : CMSMcQ : wrap start-tags only when necessary
* 2009-01-20 : CMSMcQ : wrap start-tags
* 2008-12-19 : CMSMcQ : add toc for schema documents with more than
* five children of xsd:schema
* 2008-12-18 : CMSMcQ : fix problems with text breaking
* add rule for top-level attribute groups
* 2008-09-27 : CMSMcQ : made first version of this stylesheet
*-->

<xsl:output method="html" indent="yes"/>

<xsl:param name="line-wrap-length" select="60"/>
<xsl:param name="ind-depth" select="6"/>
<xsl:param name="additional-indent" select="substring(
' ',
1,$ind-depth)"/>

<xsl:variable name="tns">
<xsl:value-of select="/xsd:schema/@targetNamespace"/>
</xsl:variable>

<!--* 0 Document root *-->
<xsl:template match="/">
<xsl:variable name="doctitle">
<xsl:text>Schema document for </xsl:text>
<xsl:choose>
<xsl:when test="xsd:schema/@targetNamespace">
<xsl:text>namespace </xsl:text>
<xsl:value-of select="$tns"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>unspecified namespace</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>

<xsl:variable name="docHasHeading" select="
xsd:schema/xsd:annotation[1]/xsd:documentation/*[1]
[self::xhtml:h1 or self::h1]
or
xsd:schema/xsd:annotation[1]/xsd:documentation/xhtml:div/*[1]
[self::xhtml:h1 or self::h1]
"/>
<xsl:variable name="docIsProlific" select="
count(xsd:schema/child::*) &gt; 5
"/>

<xsl:element name="html">
<xsl:element name="head">
<xsl:element name="title">
<xsl:value-of select="$doctitle"/>
</xsl:element>
<xsl:element name="style">
<xsl:attribute name="type">text/css</xsl:attribute>
.bodytext .bodytext {
margin-left: 0;
margin-right: 0;
}
.bodytext {
margin-left: 15%;
margin-right: 2%;
}
.annotation {
<!--* anything special to do here? *-->
<!--* color: navy; *-->
}
.same-ns {
color: Green;
}
.diff-ns {
color: maroon;
}
.warning {
color: red;
}
p.note {
font-style: italic;
}
p.dt {
font-weight: bold;
}
span.rfc {
font-variant: small-caps;
}
</xsl:element>
</xsl:element>
<xsl:element name="body">
<xsl:choose>
<xsl:when test="$docHasHeading and not($docIsProlific)">
<!--* If the first thing in the first documentation element is a heading,
* and there are few children, then don't interfere.
*-->
<xsl:comment>* <xsl:value-of select="$doctitle"/> *</xsl:comment>
</xsl:when>
<xsl:otherwise>
<!--* either document has no heading (and needs one), or
* we're going to do a toc and need a heading anyway
*-->
<xsl:element name="h1">
<xsl:value-of select="$doctitle"/>
</xsl:element>
<xsl:if test="$docIsProlific">
<xsl:element name="div">
<xsl:element name="hr"/>
<xsl:element name="ul">
<xsl:attribute name="class">bodytext</xsl:attribute>
<xsl:apply-templates mode="toc" select="./xsd:schema/*"/>
</xsl:element>
<xsl:element name="hr"/>
</xsl:element>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates/>
</xsl:element>
</xsl:element>
</xsl:template>

<!--* 2 Schema element *-->
<xsl:template match="xsd:schema">
<!--* optional future change: write out information here about
* the attributes of xsd:schema: version, finalDefault, blockDefault,
* elementFormDefault, atgtributeFormDefault, namespace bindings ...
*-->
<xsl:apply-templates/>
</xsl:template>

<!--* 3 Anotation *-->
<xsl:template match="xsd:annotation">
<xsl:element name="div">
<xsl:attribute name="class">annotation</xsl:attribute>
<xsl:attribute name="id">
<xsl:call-template name="leid">
</xsl:call-template>
</xsl:attribute>
<xsl:if test="not(./xsd:documentation//*[@class='bodytext'])">
<xsl:element name="h3">Annotation</xsl:element>
</xsl:if>
<xsl:element name="div">
<xsl:choose>
<xsl:when test="./xsd:documentation//*[@class='bodytext']">
<!--* if the schema document is already using class=bodytext,
* let the schema author control the margins, don't
* assign the class here.
*-->
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="class">bodytext</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates/>
</xsl:element>
</xsl:element>
</xsl:template>

<xsl:template match="xsd:documentation">
<xsl:choose>
<xsl:when test=".//xhtml:* or .//div or .//p or .//li">
<xsl:copy-of select="*"/>
</xsl:when>
<xsl:when test="./*">
<xsl:message>! Unrecognized children in xs:documentation element</xsl:message>
<xsl:copy-of select="*"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="break-pcdata">
<xsl:with-param name="s" select="string(.)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template name="break-pcdata">
<xsl:param name="s"></xsl:param>

<xsl:choose>
<xsl:when test="starts-with($s,'&#xA;')">
<xsl:text>&#xA;</xsl:text>
<xsl:element name="br"/>
<xsl:call-template name="break-pcdata">
<xsl:with-param name="s" select="substring($s,2)"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="starts-with($s,' ')">
<xsl:text>&#xA0;</xsl:text>
<xsl:call-template name="break-pcdata">
<xsl:with-param name="s" select="substring($s,2)"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($s,'&#xA;')">
<xsl:value-of select="substring-before($s,'&#xA;')"/>
<xsl:text>&#xA;</xsl:text>
<xsl:element name="br"/>
<xsl:call-template name="break-pcdata">
<xsl:with-param name="s" select="substring-after($s,'&#xA;')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$s"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<!--* 4 Top-level components *-->
<xsl:template match="
xsd:schema/xsd:attribute
| xsd:schema/xsd:element
| xsd:schema/xsd:simpleType
| xsd:schema/xsd:complexType
| xsd:schema/xsd:attributeGroup
| xsd:schema/xsd:import
| xsd:schema/xsd:group
| xsd:schema/xsd:notation
">
<xsl:call-template name="show-top-level-component"/>
</xsl:template>

<xsl:template name="show-top-level-component">
<xsl:variable name="sort">
<xsl:call-template name="sort"/>
</xsl:variable>
<xsl:variable name="leid">
<xsl:call-template name="leid"/>
</xsl:variable>
<xsl:variable name="has-heading-already">
<xsl:choose>
<xsl:when test="./xsd:annotation[1]/xsd:documentation/*//*
[self::xhtml:*[starts-with(local-name(),'h')]
or
self::*[contains(' h1 h2 h3 h4 h5 ',local-name())]
]">
<xsl:value-of select="'true'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'false'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>

<xsl:element name="div">
<xsl:attribute name="id">
<xsl:value-of select="$leid"/>
</xsl:attribute>
<xsl:element name="h3">
<xsl:element name="a">
<xsl:attribute name="name">
<xsl:value-of select="$leid"/>
</xsl:attribute>
<xsl:value-of select="concat($sort,' ')"/>
<xsl:choose>
<xsl:when test="count(@name) = 1">
<xsl:element name="em">
<xsl:value-of select="@name"/>
</xsl:element>
</xsl:when>
<xsl:when test="self::xsd:import and (count(@namespace) = 1)">
<xsl:element name="code">
<xsl:value-of select="@namespace"/>
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:element>
</xsl:element>

<xsl:element name="div">
<xsl:attribute name="class">bodytext</xsl:attribute>

<xsl:if test="./xsd:annotation/xsd:documentation">
<xsl:element name="div">
<xsl:if test="$has-heading-already = 'false'">
<xsl:element name="h4">Notes</xsl:element>
</xsl:if><!-- /if .$has-heading-already *-->
<xsl:apply-templates select="xsd:annotation/xsd:documentation"/>
<xsl:if test="count(./xsd:annotation/xsd:documentation/@source) = 1">
<xsl:element name="p">
<xsl:text>External documentation at </xsl:text>
<xsl:element name="code">
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:value-of select="./xsd:annotation/xsd:documentation/@source"/>
</xsl:attribute>
<xsl:value-of select="./xsd:annotation/xsd:documentation/@source"/>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:if>
</xsl:element>
</xsl:if><!-- /if ./xsd:annotation/xsd:documentation *-->

<xsl:element name="div">
<xsl:element name="h4">Formal declaration in XSD source form</xsl:element>
<xsl:element name="pre">
<xsl:variable name="preceding-node"
select="./preceding-sibling::node()[1]"/>
<xsl:if test="not($preceding-node/self::*)
and (normalize-space($preceding-node) = '')">
<xsl:value-of select="$preceding-node"/>
</xsl:if>
<xsl:apply-templates select="." mode="echo-xml"/>
</xsl:element>
</xsl:element><!--* div for XSD source form *-->
</xsl:element><!--* div for documentation and formal description *-->

</xsl:element><!--* div for top-level component *-->
</xsl:template>


<!--* 5 xml mode *-->
<xsl:template match="*" mode="echo-xml">
<xsl:variable name="s0">
<xsl:call-template name="lastline-suffix">
<xsl:with-param name="s0" select="preceding-sibling::text()
[string-length(.) > 0][1]" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="width">
<xsl:call-template name="stag-width">
<xsl:with-param name="indent-length" select="string-length($s0)"/>
</xsl:call-template>
</xsl:variable>
<!--* <xsl:message>Start-tag width for <xsl:value-of select="name()"/>
= <xsl:value-of select="$width"/></xsl:message> *-->

<xsl:text>&lt;</xsl:text>
<xsl:value-of select="name()"/>
<xsl:apply-templates select="@*" mode="echo-xml">
<xsl:with-param name="break-or-nobreak">
<xsl:choose>
<xsl:when test="$width > $line-wrap-length">break</xsl:when>
<xsl:otherwise>nobreak</xsl:otherwise>
</xsl:choose>
</xsl:with-param>
<xsl:with-param name="s0">
<xsl:call-template name="lastline-suffix">
<xsl:with-param name="s0" select="preceding-sibling::text()
[string-length(.) > 0][1]" />
</xsl:call-template>
</xsl:with-param>
</xsl:apply-templates>
<xsl:choose>
<xsl:when test="child::node()">
<xsl:text>&gt;</xsl:text>
<xsl:apply-templates select="node()" mode="echo-xml"/>
<xsl:text>&lt;/</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>&gt;</xsl:text>
</xsl:when>
<xsl:otherwise>/&gt;</xsl:otherwise>
</xsl:choose>
<!--* </xsl:element> *-->
</xsl:template>

<xsl:template match="xsd:annotation" mode="echo-xml"/>
<xsl:template match="@xml:space" mode="echo-xml"/>

<xsl:template match="@*" mode="echo-xml">
<xsl:param name="break-or-nobreak">nobreak</xsl:param>
<xsl:param name="s0"></xsl:param>
<xsl:variable name="indent">
<xsl:choose>
<xsl:when test="normalize-space($s0) = ''">
<xsl:value-of select="concat($additional-indent,$s0)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="' '"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>

<xsl:choose>
<xsl:when test="parent::xsd:* and $break-or-nobreak = 'break'">
<xsl:text>&#xA;</xsl:text>
<xsl:value-of select="$indent"/>
</xsl:when>
<xsl:otherwise>
<xsl:text> </xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:value-of select="name()"/>
<xsl:text>="</xsl:text>
<xsl:choose>
<xsl:when test="parent::xsd:element
and namespace-uri() = ''
and local-name() = 'ref'
">
<xsl:call-template name="makelink-maybe"/>
</xsl:when>
<xsl:when test="parent::xsd:attribute
and namespace-uri() = ''
and local-name() = 'ref'
">
<xsl:call-template name="makelink-maybe"/>
</xsl:when>
<xsl:when test="parent::xsd:restriction
and namespace-uri() = ''
and local-name() = 'base'
">
<xsl:call-template name="makelink-maybe"/>
</xsl:when>
<xsl:when test="parent::xsd:extension
and namespace-uri() = ''
and local-name() = 'base'
">
<xsl:call-template name="makelink-maybe"/>
</xsl:when>
<xsl:when test="parent::xsd:group
and namespace-uri() = ''
and local-name() = 'ref'
">
<xsl:call-template name="makelink-maybe"/>
</xsl:when>
<xsl:when test="parent::xsd:list
and namespace-uri() = ''
and local-name() = 'itemType'
">
<xsl:call-template name="makelink-maybe"/>
</xsl:when>
<xsl:when test="parent::xsd:union
and namespace-uri() = ''
and local-name() = 'memberTypes'
">
<xsl:call-template name="makelink-several-maybe"/>
</xsl:when>
<xsl:when test="parent::xsd:element
and namespace-uri() = ''
and local-name() = 'type'
">
<xsl:call-template name="makelink-maybe"/>
</xsl:when>
<xsl:when test="parent::xsd:attribute
and namespace-uri() = ''
and local-name() = 'type'
">
<xsl:call-template name="makelink-maybe"/>
</xsl:when>
<xsl:when test="parent::xsd:element
and namespace-uri() = ''
and local-name() = 'substitutionGroup'
">
<xsl:call-template name="makelink-several-maybe"/>
</xsl:when>

<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
<xsl:text>"</xsl:text>
</xsl:template>
<xsl:template match="text()" mode="echo-xml">
<xsl:value-of select="."/>
</xsl:template>


<!--* 6 toc *-->
<xsl:template mode="toc" match="
xsd:schema/xsd:annotation
| xsd:schema/xsd:attribute
| xsd:schema/xsd:element
| xsd:schema/xsd:simpleType
| xsd:schema/xsd:complexType
| xsd:schema/xsd:attributeGroup
| xsd:schema/xsd:import
| xsd:schema/xsd:group
| xsd:schema/xsd:notation
">
<xsl:call-template name="toc-entry"/>
</xsl:template>

<xsl:template name="toc-entry">
<xsl:variable name="sort">
<xsl:call-template name="sort"/>
</xsl:variable>
<xsl:variable name="leid">
<xsl:call-template name="leid"/>
</xsl:variable>
<xsl:element name="li">
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:value-of select="concat('#',$leid)"/>
</xsl:attribute>
<xsl:choose>
<xsl:when test="self::xsd:annotation
and
( descendant::xhtml:h1 or descendant::xhtml:h2 or descendant::xhtml:h3
or descendant::h1 or descendant::h2 or descendant::h3)
">
<xsl:choose>
<xsl:when test="descendant::xhtml:h1">
<xsl:value-of select="descendant::xhtml:h1[1]"/>
</xsl:when>
<xsl:when test="descendant::h1">
<xsl:value-of select="descendant::h1[1]"/>
</xsl:when>
<xsl:when test="descendant::xhtml:h2">
<xsl:value-of select="descendant::xhtml:h2[1]"/>
</xsl:when>
<xsl:when test="descendant::h2">
<xsl:value-of select="descendant::h2[1]"/>
</xsl:when>
<xsl:when test="descendant::xhtml:h3">
<xsl:value-of select="descendant::xhtml:h3[1]"/>
</xsl:when>
<xsl:when test="descendant::h3">
<xsl:value-of select="descendant::h3[1]"/>
</xsl:when>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($sort,' ')"/>
<xsl:choose>
<xsl:when test="count(@name) = 1">
<xsl:element name="em">
<xsl:value-of select="@name"/>
</xsl:element>
</xsl:when>
<xsl:when test="self::xsd:annotation">
<xsl:value-of select="1 + count(preceding-sibling::xsd:annotation)"/>
</xsl:when>
<xsl:when test="self::xsd:import">
<xsl:element name="code">
<xsl:value-of select="@namespace"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<!--* fake it *-->
<xsl:variable name="gi" select="local-name()"/>
<xsl:value-of select="1 + count(preceding-sibling::*[local-name() = $gi])"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:element>

</xsl:template>

<!--* 7 common code for calculating sort and little-endian IDs *-->
<xsl:template name="sort">
<xsl:choose>
<xsl:when test="self::xsd:annotation">
<xsl:value-of select="'Annotation'"/>
</xsl:when>
<xsl:when test="self::xsd:attribute">
<xsl:value-of select="'Attribute'"/>
</xsl:when>
<xsl:when test="self::xsd:element">
<xsl:value-of select="'Element'"/>
</xsl:when>
<xsl:when test="self::xsd:simpleType">
<xsl:value-of select="'Simple type'"/>
</xsl:when>
<xsl:when test="self::xsd:complexType">
<xsl:value-of select="'Complex type'"/>
</xsl:when>
<xsl:when test="self::xsd:attributeGroup">
<xsl:value-of select="'Attribute group'"/>
</xsl:when>
<xsl:when test="self::xsd:group">
<xsl:value-of select="'Model group'"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="gi" select="local-name()"/>
<xsl:value-of select="concat(
translate(substring($gi,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
substring($gi,2)
)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="leid">
<xsl:choose>
<xsl:when test="self::xsd:annotation">
<xsl:value-of select="concat('ann_',
string(1+count(preceding-sibling::xsd:annotation)))"/>
</xsl:when>
<xsl:when test="self::xsd:attribute">
<xsl:value-of select="concat('att_',@name)"/>
</xsl:when>
<xsl:when test="self::xsd:element">
<xsl:value-of select="concat('elem_',@name)"/>
</xsl:when>
<xsl:when test="self::xsd:simpleType">
<xsl:value-of select="concat('type_',@name)"/>
</xsl:when>
<xsl:when test="self::xsd:complexType">
<xsl:value-of select="concat('type_',@name)"/>
</xsl:when>
<xsl:when test="self::xsd:attributeGroup">
<xsl:value-of select="concat('attgrp_',@name)"/>
</xsl:when>
<xsl:when test="self::xsd:group">
<xsl:value-of select="concat('grp_',@name)"/>
</xsl:when>
<xsl:when test="self::xsd:import">
<xsl:value-of select="concat('imp_',
string(1+count(preceding-sibling::xsd:import)))"/>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="@name">
<xsl:variable name="sort" select="local-name()"/>
<xsl:value-of select="concat($sort,'_',@name)"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="sort" select="local-name()"/>
<xsl:variable name="pos" select="1 + count(preceding-sibling::*[local-name() = $sort])"/>
<xsl:value-of select="concat($sort,'_',$pos)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<!--* 8 unmatched elements (mostly diagnostic for development) *-->
<xsl:template match="*|@*">
<xsl:variable name="fqgi">
<xsl:call-template name="fqgi"/>
</xsl:variable>
<xsl:message>Warning: <xsl:value-of select="$fqgi"/> not matched.</xsl:message>
<xsl:element name="div">
<xsl:attribute name="class">warning</xsl:attribute>
<xsl:value-of select="concat('&lt;',name(),'>')"/>
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<xsl:value-of select="concat('&lt;/',name(),'>')"/>
</xsl:element>
</xsl:template>

<xsl:template name="fqgi" match="*" mode="fqgi">
<xsl:param name="sBuf"/>
<xsl:variable name="sCur">
<xsl:choose>
<xsl:when test="self::*">
<!--* elements *-->
<xsl:value-of select="name()"/>
</xsl:when>
<xsl:otherwise>
<!--* attributes and other riffraff *-->
<xsl:value-of select="concat('@',name())"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!--*
<xsl:message>FQGI(<xsl:value-of select="concat($sBuf,',',$sCur)"/>)</xsl:message>
*-->
<xsl:choose>
<xsl:when test="parent::*">
<xsl:apply-templates mode="fqgi" select="parent::*">
<xsl:with-param name="sBuf">
<xsl:value-of select="concat('/',$sCur,$sBuf)"/>
</xsl:with-param>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('/',$sCur,$sBuf)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>


<!--* 9 intra-document link calculation, qname manipulation *-->
<xsl:template name="makelink-several-maybe">
<xsl:param name="lQNames" select="normalize-space(.)"/>
<xsl:choose>
<xsl:when test="contains($lQNames,' ')">
<!--* recur *-->
<xsl:call-template name="makelink-maybe">
<xsl:with-param name="qn" select="substring-before($lQNames,' ')"/>
</xsl:call-template>
<xsl:text> </xsl:text>
<xsl:call-template name="makelink-several-maybe">
<xsl:with-param name="lQNames" select="substring-after($lQNames,' ')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!--* base step, no blank so at most one QName *-->
<xsl:call-template name="makelink-maybe">
<xsl:with-param name="qn" select="$lQNames"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template name="makelink-maybe">
<xsl:param name="qn" select="."/>
<xsl:param name="refns">
<xsl:call-template name="qname-to-uri">
<xsl:with-param name="qname" select="$qn"/>
</xsl:call-template>
</xsl:param>
<xsl:param name="lname">
<xsl:call-template name="qname-to-ncname">
<xsl:with-param name="qname" select="$qn"/>
</xsl:call-template>
</xsl:param>

<xsl:variable name="linktarget">
<xsl:choose>
<xsl:when test="$tns = $refns">
<xsl:choose>
<xsl:when test="parent::xsd:element
and local-name() = 'ref'
and count(/xsd:schema/xsd:element[@name = $lname]) = 1">
<xsl:value-of select="concat('elem_',$lname)"/>
</xsl:when>
<xsl:when test="parent::xsd:element
and local-name() = 'substitutionGroup'
and count(/xsd:schema/xsd:element[@name = $lname]) = 1">
<xsl:value-of select="concat('elem_',$lname)"/>
</xsl:when>
<xsl:when test="parent::xsd:attribute
and local-name() = 'ref'
and count(/xsd:schema/xsd:attribute[@name = $lname]) = 1">
<xsl:value-of select="concat('att_',$lname)"/>
</xsl:when>
<xsl:when test="parent::xsd:restriction
and count(/xsd:schema/xsd:*[@name = $lname
and (self::xsd:simpleType or self::xsd:complexType)])
= 1">
<xsl:value-of select="concat('type_',$lname)"/>
</xsl:when>
<xsl:when test="parent::xsd:extension
and count(/xsd:schema/xsd:*[@name = $lname
and (self::xsd:simpleType or self::xsd:complexType)])
= 1">
<xsl:value-of select="concat('type_',$lname)"/>
</xsl:when>
<xsl:when test="parent::xsd:element
and local-name() = 'type'
and count(/xsd:schema/xsd:*[@name = $lname
and (self::xsd:simpleType or self::xsd:complexType)])
= 1">
<xsl:value-of select="concat('type_',$lname)"/>
</xsl:when>
<xsl:when test="parent::xsd:attribute
and local-name() = 'type'
and count(/xsd:schema/xsd:*[@name = $lname
and (self::xsd:simpleType or self::xsd:complexType)])
= 1">
<xsl:value-of select="concat('type_',$lname)"/>
</xsl:when>
<xsl:when test="parent::xsd:list
and count(/xsd:schema/xsd:*[@name = $lname
and (self::xsd:simpleType or self::xsd:complexType)])
= 1">
<xsl:value-of select="concat('type_',$lname)"/>
</xsl:when>
<xsl:when test="parent::xsd:union
and count(/xsd:schema/xsd:*[@name = $lname
and (self::xsd:simpleType or self::xsd:complexType)])
= 1">
<xsl:value-of select="concat('type_',$lname)"/>
</xsl:when>
<xsl:when test="parent::xsd:group
and count(/xsd:schema/xsd:group[@name = $lname]) = 1">
<xsl:value-of select="concat('grp_',$lname)"/>
</xsl:when>
<xsl:when test="parent::xsd:attributeGroup
and count(/xsd:schema/xsd:atributeGroup[@name = $lname]) = 1">
<xsl:value-of select="concat('attgrp_',$lname)"/>
</xsl:when>
<!--* static links to built-ins could be handled here *-->
</xsl:choose>
</xsl:when>
<xsl:when test="count(ancestor::*/namespace::*) = 0">
<!--* we are either in a no-namespace document in Opera,
* or we are in Firefox, without ns support.
*-->
<xsl:value-of select="'no-ns-support'"/>
</xsl:when>
<xsl:otherwise>
<!--* namespaces did not match, no target *-->
<xsl:value-of select="'no-target'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>

<xsl:choose>
<xsl:when test="($linktarget='no-ns-support')">
<xsl:value-of select="$qn"/>
</xsl:when>
<xsl:when test="($linktarget='no-target' or $linktarget='')
and ($tns = $refns)">
<xsl:element name="span">
<xsl:attribute name="class">external-link same-ns</xsl:attribute>
<xsl:value-of select="$qn"/>
</xsl:element>
</xsl:when>
<xsl:when test="($linktarget='no-target')
and not($tns = $refns)">
<xsl:element name="span">
<xsl:attribute name="class">external-link diff-ns</xsl:attribute>
<xsl:value-of select="$qn"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:value-of select="concat('#',$linktarget)"/>
</xsl:attribute>
<xsl:value-of select="$qn"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template name="qname-to-uri" match="*" mode="qname-to-uri">
<xsl:param name="qname" select="."/>
<xsl:variable name="prefix" select="substring-before($qname,':')"/>
<xsl:choose>
<xsl:when test="(1=1) and ($prefix='xml')">
<!--* we need to special-case 'xml', since
* Opera does not provide a ns node for it.
*-->
<xsl:value-of select="'http://www.w3.org/XML/1998/namespace'"/>
</xsl:when>
<xsl:when test="self::*">
<!--* we're an element *-->
<xsl:value-of select="string(namespace::*[name()=$prefix])"/>
</xsl:when>
<xsl:otherwise>
<!--* we're not an element *-->
<xsl:value-of select="string(parent::*/namespace::*[name()=$prefix])"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="qname-to-ncname">
<xsl:param name="qname" select="."/>
<xsl:choose>
<xsl:when test="contains($qname,':')">
<xsl:value-of select="substring-after($qname,':')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$qname"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template name="lastline-suffix">
<xsl:param name="s0"></xsl:param>
<xsl:choose>
<xsl:when test="contains($s0,'&#xA;')">
<xsl:call-template name="lastline-suffix">
<xsl:with-param name="s0" select="substring-after($s0,'&#xA;')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$s0"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>


<xsl:template name="stag-width">
<xsl:param name="indent-length" select="0"/>
<xsl:variable name="attcount" select="count(@*)"/>
<xsl:variable name="list-attname-lengths">
<xsl:call-template name="make-length-list">
<xsl:with-param name="kw">attnames</xsl:with-param>
</xsl:call-template>
</xsl:variable>

<xsl:variable name="list-attval-lengths">
<xsl:call-template name="make-length-list">
<xsl:with-param name="kw">attvals</xsl:with-param>
</xsl:call-template>
</xsl:variable>

<xsl:variable name="sum-att-lengths">
<xsl:call-template name="sum-list">
<xsl:with-param name="s0" select="concat($list-attname-lengths,' ',$list-attval-lengths)"/>
</xsl:call-template>
</xsl:variable>

<!--*
<xsl:message>indent-length = <xsl:value-of select="$indent-length"/></xsl:message>
<xsl:message>attcount = <xsl:value-of select="$attcount"/></xsl:message>
<xsl:message>sum-att-lengths = <xsl:value-of select="$sum-att-lengths"/></xsl:message>
<xsl:message>namelen = <xsl:value-of select="string-length(name())"/></xsl:message>
*-->

<xsl:value-of select="$indent-length + (4 * $attcount) + $sum-att-lengths + string-length(name()) + 3"/>

</xsl:template>


<xsl:template name="make-length-list">
<xsl:param name="kw">unknown</xsl:param>
<xsl:choose>
<xsl:when test="$kw = 'attnames'">
<xsl:apply-templates select="@*" mode="attnamelength"/>
</xsl:when>
<xsl:when test="$kw = 'attvals'">
<xsl:apply-templates select="@*" mode="attvallength"/>
</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template name="sum-list">
<xsl:param name="n0" select="0"/>
<xsl:param name="s0"/>

<xsl:variable name="s1" select="normalize-space($s0)"/>

<!--*
<xsl:message><xsl:value-of select="concat('n0 =', $n0, ', s1 = /',$s1,'/')"/></xsl:message>
*-->

<xsl:choose>
<xsl:when test="contains($s1,' ')">
<xsl:variable name="term" select="substring-before($s1,' ')"/>
<xsl:variable name="s2" select="substring-after($s1,' ')"/>
<xsl:call-template name="sum-list">
<xsl:with-param name="n0" select="$n0 + $term"/>
<xsl:with-param name="s0" select="$s2"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$n0 + $s1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="@*" mode="attnamelength">
<xsl:value-of select="concat(string-length(name()), ' ')"/>
</xsl:template>
<xsl:template match="@*" mode="attvallength">
<xsl:value-of select="concat(string-length(.), ' ')"/>
</xsl:template>

</xsl:stylesheet>
<!-- Keep this comment at the end of the file
Local variables:
mode: xml
sgml-default-dtd-file:"/Library/SGML/Public/Emacs/xslt.ced"
sgml-omittag:t
sgml-shorttag:t
sgml-indent-data:t
sgml-indent-step:1
End:
-->
(2-2/2)