xsl-list
[Top] [All Lists]

[xsl] Generate instance document from schema

2006-07-15 21:20:25
 Hi,
      Over at the schema list someone had asked if there was a xslt
stylesheet that could generate an instance from a schema. I have been trying
without much luck to get my posting across without much luck. So Iam posting
my stylesheet here for the benefit of the OP as well as the XSLT list
members.

   Here's my stylesheet that uses XSLT 2.0. Iam guessing that it should be
possible to make it work with XSLT 1.0 by changing the version attribute
though I haven't tried it myself. It is not complete as yet and still
requires some work. Hope you find it useful.



<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
xmlns:xsd="http://www.w3.org/2001/XMLSchema";>
<xsl:strip-space elements="*"/>

<!--
        purpose is to generate a transform that will lable each element in an
instance document with
        its own Normalised Universal Name (NUN), and with that of its schema 
type.

        The elementNUN will be:
                "<ns>#/element::<elementName>" if it is a global element, or
                "<typeNUN>/element::<elementName>" if it is a local element

        The typeNUN will be:
                "<ns>#/type::<typeName>" if it's a named type, or
                "<elementNUN>/type::*" if it's anonymous.

        (where "<x>" means the runtime value of "x", and "[y]+" indicates one or
more "y")

        The use of Normalized Universal Names is based on
        
http://www.w3.org/TR/2001/WD-xmlschema-formal-20010320/#section-overview-no
rmalization

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

        <xsl:key name="gnt" match="node()" use="@name"/>

        <!-- get the root element into a var so we can get back after 
recursively
processing included XSDs -->
        <xsl:variable name="root" select="/"/>

        <xsl:param name="rootelem" select="'purchaseOrder'"/>

        <!-- get XML Schema namespace -->
        <xsl:variable name="xsd-uri" select="namespace-uri(/*)" />


        <!-- now start at the top -->
        <xsl:template match="/">

                <!-- get the top level elements -->
                <xsl:comment>typeTagger generated by
typeTagger.compiler.xslt</xsl:comment>
                <!-- call the schema definition template ... -->
                <xsl:call-template name="gatherSchema">
                        <!-- ... with current current root as the $schemas 
parameter ... -->
                        <xsl:with-param name="schemas" select="/"/>
                        <!-- ... and any includes in the $include parameter -->
                        <xsl:with-param name="includes"
select="document(/xsd:schema/xsd:include/@schemaLocation)"/>
                </xsl:call-template>
        </xsl:template>
        <!-- -->
        <!-- gather all included schemas into a single parameter variable -->
        <!-- -->
        <xsl:template name="gatherSchema">
                <xsl:param name="schemas"/>
                <xsl:param name="includes"/>
                <xsl:message>in gatherSchema...</xsl:message>

                <xsl:choose>
                        <xsl:when test="count($schemas) &lt; count($schemas | 
$includes)">
                                <xsl:message>recursing back into 
gatherSchema...</xsl:message>
                                <!-- when $includes includes something new, 
recurse ... -->
                                <xsl:call-template name="gatherSchema">
                                        <!-- ... with current $includes added 
to the $schemas parameter ... -->
                                        <xsl:with-param name="schemas" 
select="$schemas | $includes"/>
                                        <!-- ... and any *new* includes in the 
$include parameter -->
                                        <xsl:with-param name="includes"
select="document($includes/xsd:schema/xsd:include/@schemaLocation)"/>
                                </xsl:call-template>
                        </xsl:when>

                        <xsl:otherwise>
                                <xsl:message>count($schemas//xsd:element): 
<xsl:value-of
select="count($schemas//xsd:element)"/>
                                </xsl:message>
                                <!-- process the schemas -->
                                <!-- start by creating our target transform 
root element -->
                                        <!-- kick off the global elements and 
type definitions -->

            <!--
                                        <xsl:apply-templates 
select="$schemas//xsd:schema/xsd:element |
$schemas//xsd:schema/xsd:complexType | $schemas//xsd:schema/xsd:simpleType"
mode="typeTag">
                                            -->


                                        <xsl:apply-templates 
select="$schemas//xsd:schema/xsd:element[(_at_)name=
$rootelem]" mode="typeTag">


                                                <xsl:with-param name="schemas" 
select="$schemas"/>
                                        </xsl:apply-templates>

                        </xsl:otherwise>
                </xsl:choose>
        </xsl:template>
        <!--
                plan is:

                for each element:
                        write a template that matches by element name and 
mode=parent-typeNUN (if
any)
                                with apply-templates to content type with 
mode=this-typeNUN
                        apply-templates to anonymous type definitions with 
this-elementNun as a
parameter

                for each type definition:
                        write mop-up template with mode=this-typeNUN for 
non-element nodes
                        apply-templates to content elements with this-typeNUN 
as a parameter

        -->
        <!-- -->
        <!-- create templates to tag elements -->
        <!-- -->


        <xsl:template match="xsd:element" mode="typeTag">
                <xsl:param name="schemas"/>
                <xsl:param name="context"/>

                <xsl:choose>
                <xsl:when test="@type[substring-before(., ':') !=
name(current()/namespace::*[. = $xsd-uri])]">
                <!-- this element has a global, named type -->

                <xsl:variable name="gntvar" select="key('gnt', @type)"/>

                <xsl:if test="self::node()[(_at_)minOccurs][@minOccurs &gt;  0] 
 or
self::node()[not(@minOccurs)]">

                <xsl:element name="{(_at_)name}">
                    <xsl:for-each select="$gntvar//xsd:attribute">
                        <xsl:attribute name="{(_at_)name}">
                            <xsl:value-of select="''"/>
                            </xsl:attribute>
                    </xsl:for-each>
                    <xsl:text> </xsl:text>

                    <xsl:apply-templates select="$gntvar/*" mode="typeTag">
                    <xsl:with-param name="schemas" select="$schemas"/>
                    </xsl:apply-templates>

                </xsl:element>

                 </xsl:if>

                </xsl:when>

                <xsl:when test="@ref">

                <!-- this element refers to a global element which may have 
named or
anonymous type -->

                <xsl:variable name="refElement"
select="$schemas//xsd:schema/xsd:element[(_at_)name=current()/@ref]"/>

                <xsl:choose>
                <xsl:when test="$refElement/@type[substring-before(., ':') !=
name($refElement/namespace::*[. = $xsd-uri])]">
            <!--  the referred-to element has a named type -->

                <xsl:apply-templates select="key('gnt',
$refElement/@type)//xsd:element" mode="typeTag">
                    <xsl:with-param name="schemas" select="$schemas"/>
                    </xsl:apply-templates>

                 </xsl:when>
                <xsl:otherwise>

                <xsl:variable name="refElement"
select="$schemas//xsd:schema/xsd:element[(_at_)name=current()/@ref]"/>

                <!--  the referred-to element has anonymous type  -->
                <xsl:if test="$refElement[(@minOccurs and @minOccurs &gt;  0)  
or
(not(@minOccurs))]">

                <xsl:element name="{$refElement/@name}">
                    <xsl:text> </xsl:text>

                    <xsl:for-each select="$refElement//xsd:attribute">
                        <xsl:attribute name="{(_at_)name}"/>
                    </xsl:for-each>
                    <xsl:apply-templates select="$refElement/*">
                    <xsl:with-param name="schemas" select="$schemas"/>
                    </xsl:apply-templates>
                    </xsl:element>

                 </xsl:if>


                </xsl:otherwise>
                </xsl:choose>

                </xsl:when>
                <xsl:otherwise>

                <!-- this element has an anonymous type -->
                        <xsl:element name="{(_at_)name}">
                            <xsl:text> </xsl:text>

                            <xsl:for-each select="xsd:attribute">
                                <xsl:value-of select="@name"/>

                                </xsl:for-each>
                                <xsl:apply-templates>
                                                     <xsl:with-param 
name="schemas"
select="$schemas"/>
                                                     </xsl:apply-templates>
                        </xsl:element>
                                </xsl:otherwise>
                </xsl:choose>

                <!-- apply templates with mode="typeTag" to the element content 
if any -->
                <xsl:apply-templates select=".//xsd:complexType[1] | 
.//xsd:simpleType[1]"
mode="typeTag">
                        <xsl:with-param name="schemas" select="$schemas"/>
                </xsl:apply-templates>

                        <!-- apply templates with mode="typeTag" to the element 
content if
any -->

        </xsl:template>

        <xsl:template match="xsd:sequence|xsd:any|xsd:all" mode="typeTag">
                <xsl:param name="schemas"/>



                <xsl:apply-templates select="*" mode="typeTag">
                        <xsl:with-param name="schemas" select="$schemas"/>
                </xsl:apply-templates>
        </xsl:template>

        <xsl:template match="text()" mode="typeTag">
            <xsl:value-of select="."/>
            </xsl:template>



</xsl:stylesheet>

cheers,
prakash


--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

<Prev in Thread] Current Thread [Next in Thread>
  • [xsl] Generate instance document from schema, v.omprakash <=