Subject: [xsl] Generate instance document from schema From: "v.omprakash" <omprakashv@xxxxxxxxxxxxxxxxxx> Date: Sun, 16 Jul 2006 09:49:55 +0530 |
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) < 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[@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()[@minOccurs][@minOccurs > 0] or self::node()[not(@minOccurs)]"> <xsl:element name="{@name}"> <xsl:for-each select="$gntvar//xsd:attribute"> <xsl:attribute name="{@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[@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[@name=current()/@ref]"/> <!-- the referred-to element has anonymous type --> <xsl:if test="$refElement[(@minOccurs and @minOccurs > 0) or (not(@minOccurs))]"> <xsl:element name="{$refElement/@name}"> <xsl:text> </xsl:text> <xsl:for-each select="$refElement//xsd:attribute"> <xsl:attribute name="{@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="{@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
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
[xsl] XSLT 1.0 Muenchian Grouping, Steve Sze | Thread | [xsl] Fwd: Combing two different do, David B |
[xsl] XSLT 1.0 Muenchian Grouping, Steve Sze | Date | [xsl] Fwd: Combing two different do, David B |
Month |