From d52a3d56537b6d9a69d7069f69e3144fce7c3bf8 Mon Sep 17 00:00:00 2001 From: sb <sb> Date: Fri, 1 Feb 2008 12:43:18 +0000 Subject: [PATCH] Added adl2canonical --- schemas/adl-0.dtd | 13 +- transforms01/adl2canonical.xslt | 285 ++++++++++++++++++++++++++++++++ 2 files changed, 292 insertions(+), 6 deletions(-) create mode 100755 transforms01/adl2canonical.xslt diff --git a/schemas/adl-0.dtd b/schemas/adl-0.dtd index 78772d1..51224ef 100755 --- a/schemas/adl-0.dtd +++ b/schemas/adl-0.dtd @@ -13,7 +13,7 @@ <!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> <!-- - $Revision: 1.5 $ + $Revision: 1.6 $ --> <!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: --> @@ -130,8 +130,8 @@ name: the name of this application version: the version number of this application - assembly: C# implementation detail, should not be here - namespace: C# implementation detail, should not be here + assembly: C# implementation detail, DEPRECATED: should not be here + namespace: C# implementation detail, DEPRECATED: should not be here xmlns: XML namespace, in case required --> <!ELEMENT application ( documentation?, content?, typedef*, group*, entity*)> @@ -207,12 +207,12 @@ natural-key: if present, the name of a property of this entity which forms a natural primary key [NOTE: Only partly implemented. NOTE: much of the present implementation assumes all primary keys will be - integers. This needs to be fixed!] TODO: remove; replace with the + integers. This needs to be fixed!] DEPRECATED: remove; replace with the 'key' element, below. table: the name of the table in which this entity is stored. TODO: more thought --> -<!ELEMENT entity ( documentation?, content?, - (property | key | one-to-many | many-to-many | many-to-one)*, +<!ELEMENT entity ( documentation?, content?, key?, + (property | one-to-many | many-to-many | many-to-one)*, permission*, (form | page | list)*)> <!ATTLIST entity name CDATA #REQUIRED @@ -360,6 +360,7 @@ property[@type='link']. TODO: Not complete, not yet strictly convinced it's the cascade (%CascadeActions;) #IMPLIED column CDATA #IMPLIED unsaved-value CDATA #IMPLIED> + <!-- It may be worth extracting properties which are not 'simple' into separate elements; this is equivalent to property[@type='entity']. TODO: Not complete, not yet strictly convinced it's the right solution. --> diff --git a/transforms01/adl2canonical.xslt b/transforms01/adl2canonical.xslt new file mode 100755 index 0000000..11ec935 --- /dev/null +++ b/transforms01/adl2canonical.xslt @@ -0,0 +1,285 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!-- + C1873 SRU Hospitality + 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.1 $ + $Date: 2008-02-01 12:43:18 $ + --> + +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:exsl="http://exslt.org/common" + xmlns:adl="http://cygnets.co.uk/schemas/adl-1.2" + xmlns:msxsl="urn:schemas-microsoft-com:xslt"> + + <xsl:output encoding="UTF-8" method="text"/> + + <!-- + 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:param name="locale" select="en-UK"/> + + <xsl:template match="adl:application"> + <xsl:message terminate="no"> + Abstract key naming convention selected is '<xsl:value-of select="$abstract-key-name-convention"/>' + Locale selected is '<xsl:value-of select="$locale"/>' + </xsl:message> + <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.1 $', 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[key]"> + <xsl:comment> + entity <xsl:value-of select="@name"/> already has a key - not generating one + </xsl:comment> + <adl:entity> + <xsl:apply-templates select="@* | node()"/> + </adl: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">'@natural-key' is deprecated - use the 'key' sub element instead</xsl:message> + <adl: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"/> + </adl: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> + <adl: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"/> + <adl: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"> + 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 --> + <adl:property type="integer" distinct="system"> + <xsl:attribute name="name"> + <xsl:value-of select="normalize-space( $key)"/> + </xsl:attribute> + </adl:property> + </adl: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"/> + </adl: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']"> + <adl: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"/> + </adl: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']"> + <adl: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"/> + </adl: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']"> + <adl: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"/> + </adl: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']"> + <adl: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"/> + </adl: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']"> + <adl: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"/> + </adl: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']"> + <adl: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"/> + </adl: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"> + <adl:field> + <xsl:attribute name="property"> + <xsl:value-of select="@name"/> + </xsl:attribute> + </adl: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']"> + <adl:field> + <xsl:attribute name="property"> + <xsl:value-of select="@name"/> + </xsl:attribute> + </adl:field> + </xsl:for-each> + </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> \ No newline at end of file