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 &lt;key&gt; 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