<?xml version="1.0" encoding="utf-8" ?> <!-- Application Description Language framework adl2canonical.xsl (c) 2007 Cygnet Solutions Ltd Transform ADL into a canonical form, expanding and making explicit things left implicit in the manually maintained form. Specifically, in the canonicalised form (i) every entity element has a key subelement. If it did not have one in the supplied ADL, then a formal primary key is auto generated (ii) every form, page or list has properties='listed'; where the supplied ADL had properties='all' or properties='user-distinct' the correct fields are generated. $Author: sb $ $Revision: 1.3 $ $Date: 2008-02-04 15:54:46 $ --> <xsl:stylesheet version="1.0" xmlns="http://cygnets.co.uk/schemas/adl-1.2" xmlns:adl="http://cygnets.co.uk/schemas/adl-1.2" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="adl"> <xsl:output encoding="UTF-8" indent="yes" method="xml" /> <!-- The convention to use for naming auto-generated abstract primary keys. Known values are Id - the autogenerated primary key, if any, is called just 'Id' Name - the autogenerated primary key has the same name as the entity NameId - the name of the auto generated primary key is the name of the entity followed by 'Id' Name_Id - the name of the auto generated primary key is the name of the entity followed by '_Id' --> <xsl:param name="abstract-key-name-convention" select="Id"/> <xsl:template match="adl:application"> <xsl:copy> <xsl:comment> *************************************************************************** * * ©2007 Cygnet Solutions Ltd * * THIS FILE IS AUTOMATICALLY GENERATED AND SHOULD NOT * BE MANUALLY EDITED. * * Generated using adl2canonical.xsl revision <xsl:value-of select="substring('$Revision: 1.3 $', 12)"/> * *************************************************************************** </xsl:comment> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <!-- an entity which already has a key tag - just copy it through --> <xsl:template match="adl:entity[adl:key]"> <xsl:comment> entity <xsl:value-of select="@name"/> already has a key - not generating one </xsl:comment> <entity> <xsl:apply-templates select="@* | node()"/> </entity> </xsl:template> <!-- an entity which has a '@natural-key' attribute. Since we've got the key tag, I think this should be disallowed --> <xsl:template match="adl:entity[@natural-key]"> <xsl:message terminate="no"> ADL WARNING: [In entity '<xsl:value-of select="@name"/>']: '@natural-key' is deprecated - use the 'key' sub element instead</xsl:message> <entity> <xsl:variable name="nkey" select="@natural-key"/> <xsl:apply-templates select="@*"/> <!-- children copied through in legal order, to ensure the document remains valid --> <xsl:apply-templates select="adl:documentation"/> <xsl:apply-templates select="adl:content"/> <key> <xsl:apply-templates select="adl:property[@name=$nkey]"/> <xsl:apply-templates select="adl:key/adl:property"/> </key> <xsl:apply-templates select="adl:property[not(@name=$nkey)] | adl:one-to-many | adl:many-to-many | adl:many-to-one"/> <xsl:apply-templates select="adl:permission"/> <xsl:apply-templates select="adl:form | adl:page | adl:list"/> </entity> </xsl:template> <!-- an entity which has no explicit key: auto-generate one --> <xsl:template match="adl:entity"> <xsl:comment> entity <xsl:value-of select="@name"/> has no key - generating one </xsl:comment> <entity> <!-- copy attributes through --> <xsl:apply-templates select="@*"/> <!-- children copied through in legal order, to ensure the document remains valid --> <xsl:apply-templates select="adl:documentation"/> <xsl:apply-templates select="adl:content"/> <key> <!-- autogenerate a key element... --> <!-- select a name... --> <xsl:variable name="key"> <xsl:choose> <xsl:when test="$abstract-key-name-convention='Name'"> <xsl:value-of select="@name"/> </xsl:when> <xsl:when test="$abstract-key-name-convention = 'NameId'"> <xsl:value-of select="concat( @name, 'Id')"/> </xsl:when> <xsl:when test="$abstract-key-name-convention = 'Name_Id'"> <xsl:value-of select="concat( @name, '_Id')"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="'Id'"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <!-- check that it is unique, and abort hard if not... --> <xsl:if test="descendant::adl:property[@name=$key]"> <xsl:message terminate="yes"> ADL ERROR: Entity '<xsl:value-of select="@name"/>' has a property '<xsl:value-of select="$key"/>' which conflicts with your chosen key naming convention <xsl:value-of select="$abstract-key-name-convention"/>. Either: (i) Make property '<xsl:value-of select="$key"/>' an explicit key by putting it in the <key> tag; (ii) Name property '<xsl:value-of select="$key"/>' something else; or (iii) Choose a different key naming convention. </xsl:message> </xsl:if> <!-- generate one property, the abstract primary key --> <property type="integer" distinct="system"> <xsl:attribute name="name"> <xsl:value-of select="normalize-space( $key)"/> </xsl:attribute> <generator action="native"/> </property> </key> <xsl:apply-templates select="adl:property | adl:one-to-many | adl:many-to-many | adl:many-to-one"/> <xsl:apply-templates select="adl:permission"/> <xsl:apply-templates select="adl:form | adl:page | adl:list"/> </entity> </xsl:template> <!-- If properties='all', unroll them into a properties='listed' form. We need to do this for lists, pages and forms; there's probably some clever way of doing it all in a oner, but I don't know what that is --> <xsl:template match="adl:form[ @properties='all']"> <form properties='listed'> <!-- copy the name attribute through --> <xsl:apply-templates select="@name"/> <!-- children copied through in legal order, to ensure the document remains valid --> <xsl:apply-templates select="adl:documentation"/> <!-- unroll the properties --> <xsl:call-template name="unroll-properties"/> <xsl:apply-templates select="adl:head|adl:top|adl:foot|adl:field| adl:fieldgroup|adl:auxlist|adl:verb| adl:permission|adl:pragma"/> </form> </xsl:template> <!-- If properties='all', unroll them into a properties='listed' form. We need to do this for lists, pages and forms; there's probably some clever way of doing it all in a oner, but I don't know what that is --> <xsl:template match="adl:page[ @properties='all']"> <page properties='listed'> <!-- copy the name attribute through --> <xsl:apply-templates select="@name"/> <!-- children copied through in legal order, to ensure the document remains valid --> <xsl:apply-templates select="adl:documentation"/> <!-- unroll the properties --> <xsl:call-template name="unroll-properties"/> <xsl:apply-templates select="adl:head|adl:top|adl:foot|adl:field| adl:fieldgroup|adl:auxlist|adl:verb| adl:permission|adl:pragma"/> </page> </xsl:template> <!-- If properties='all', unroll them into a properties='listed' form. We need to do this for lists, pages and forms; there's probably some clever way of doing it all in a oner, but I don't know what that is --> <xsl:template match="adl:list[ @properties='all']"> <list properties='listed'> <!-- copy the name attribute through --> <xsl:apply-templates select="@name"/> <!-- children copied through in legal order, to ensure the document remains valid --> <xsl:apply-templates select="adl:documentation"/> <!-- unroll the properties --> <xsl:call-template name="unroll-properties"/> <xsl:apply-templates select="adl:head|adl:top|adl:foot|adl:field| adl:fieldgroup|adl:auxlist|adl:verb| adl:permission|adl:pragma"/> </list> </xsl:template> <!-- In practice it's likely only to be lists which have properties='user-distinct', but the grammar allows this for pages and forms as well so we'll deal with it --> <xsl:template match="adl:form[ @properties='user-distinct']"> <form properties='listed'> <!-- copy the name attribute through --> <xsl:apply-templates select="@name"/> <!-- children copied through in legal order, to ensure the document remains valid --> <xsl:apply-templates select="adl:documentation"/> <!-- unroll the properties --> <xsl:call-template name="unroll-user-distinct"/> <xsl:apply-templates select="adl:head|adl:top|adl:foot|adl:field| adl:fieldgroup|adl:auxlist|adl:verb| adl:permission|adl:pragma"/> </form> </xsl:template> <!-- In practice it's likely only to be lists which have properties='user-distinct', but the grammar allows this for pages and forms as well so we'll deal with it --> <xsl:template match="adl:page[ @properties='user-distinct']"> <page properties='listed'> <!-- copy the name attribute through --> <xsl:apply-templates select="@name"/> <!-- children copied through in legal order, to ensure the document remains valid --> <xsl:apply-templates select="adl:documentation"/> <!-- unroll the properties --> <xsl:call-template name="unroll-user-distinct"/> <xsl:apply-templates select="adl:head|adl:top|adl:foot|adl:field| adl:fieldgroup|adl:auxlist|adl:verb| adl:permission|adl:pragma"/> </page> </xsl:template> <!-- In practice it's likely only to be lists which have properties='user-distinct', but the grammar allows this for pages and forms as well so we'll deal with it --> <xsl:template match="adl:list[ @properties='user-distinct']"> <list properties='listed'> <!-- copy the name attribute through --> <xsl:apply-templates select="@name"/> <!-- children copied through in legal order, to ensure the document remains valid --> <xsl:apply-templates select="adl:documentation"/> <!-- unroll the properties --> <xsl:call-template name="unroll-user-distinct"/> <xsl:apply-templates select="adl:head|adl:top|adl:foot|adl:field| adl:fieldgroup|adl:auxlist|adl:verb| adl:permission|adl:pragma"/> </list> </xsl:template> <!-- unroll all the explicit properties in the ancestor entity of the context (assumed to be form, page or list) into a list of fields --> <xsl:template name="unroll-properties"> <xsl:for-each select="ancestor::adl:entity/descendant::adl:property | ancestor::adl:entity/descendant::adl:one-to-many | ancestor::adl:entity/descendant::adl:many-to-many | ancestor::adl:entity/descendant::adl:many-to-one"> <field> <xsl:attribute name="property"> <xsl:value-of select="@name"/> </xsl:attribute> </field> </xsl:for-each> </xsl:template> <!-- unroll all the user-distinct properties in the ancestor entity of the context (assumed to be form, page or list) into a list of fields. NOTE that n-to-n properties cannot currently be user-distinct and are therefore not inspected --> <xsl:template name="unroll-user-distinct"> <xsl:for-each select="ancestor::adl:entity/descendant::adl:property[@distinct='user']"> <field> <xsl:attribute name="property"> <xsl:value-of select="@name"/> </xsl:attribute> </field> </xsl:for-each> </xsl:template> <xsl:template match="adl:typedef[ @type = 'string' and not( @size)]"> <xsl:message terminate="yes"> ADL ERROR: Type definitions of type 'string' must have a valid value for 'size' Offending typedef: <xsl:value-of select="@name"/> </xsl:message> </xsl:template> <!-- Language constraints --> <xsl:template match="adl:property[ @type = 'string' and not( @size)]"> <xsl:message terminate="yes"> ADL ERROR: Properties of type 'string' must have a valid value for 'size' Offending property: <xsl:value-of select="@name"/> of entity <xsl:value-of select="ancestor::adl:entity/@name"/> </xsl:message> </xsl:template> <xsl:template match="adl:property[ @type = 'entity' and not( @entity)]"> <xsl:message terminate="yes"> ADL ERROR: Properties of type 'entity' must have a valid value for 'entity' Offending property: <xsl:value-of select="@name"/> of entity <xsl:value-of select="ancestor::adl:entity/@name"/> </xsl:message> </xsl:template> <xsl:template match="adl:property[ @type = 'defined' and not( @typedef)]"> <xsl:message terminate="yes"> ADL ERROR: Properties of type 'defined' must have a valid value for 'typedef' Offending property: <xsl:value-of select="@name"/> of entity <xsl:value-of select="ancestor::adl:entity/@name"/> </xsl:message> </xsl:template> <!-- copy anything that isn't explicitly matched --> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>