To begin, we will outline a number of simple principles for organizing these data modelling primitives:
The
XML Schema Part 2:
Datatypes has a usable set of building blocks for a general
data modelling system. It is complete, extensible and based on an
ISO 11404 specification for language-independent
datatypes. Unfortunately, it conflates encoding and data type
restrictions in a way that is very specific to XML character
encodings. We will separate the data modelling and encoding roles
and adopt a subset of the XML Schema <simpleType>
builtins for data modelling. Derivations for encoding will be
dealt with separately (and sufficiently).
interface Value { readonly attribute Type type; }; interface Node : Value { readonly attribute Name nid; readonly attribute Attribution created; readonly attribute Attribution modified; readonly attribute Node createdFrom; readonly attribute Permissions permissions; readonly attribute boolean versioned; readonly attribute Node newerVersion; readonly attribute Node olderVersion; readonly attribute Node headVersion; readonly attribute length; Value item (in int index); Notifier attachNotifier (in NotifierCallback cb); }; interface NotifierCallback { void update (in Node val); }; interface Notifier { boolean detach (); }; interface Attribution { readonly attribute User user; readonly attribute Date date; }; interface Permissions { /* Temporarily empty */ }; interface NodeFactory { Node create (in NodeType type); Node createByName (in Name name); }; interface Editor : NodeFactory { }; interface Name { readonly attribute string str; readonly attribute Namespace namespace; }; interface Namespace { readonly attribute string name; Name getName (in string name); };
interface Struct : Node { Type propertyType (in Name key); Value property (in Name key); }; interface StructEditor : Struct, Editor { boolean setProperty (Name key, Value value); };
interface Sequence : Node { Type contentType (in int index); }; interface SequenceEditor : Sequence, Editor { boolean insertBefore (in int index, in Value val); boolean insertAfter (in int index, in Value val); boolean removeRange (in int startIndex, in int endIndex); boolean replaceRange (in int startIndex, in int endIndex, in Value val); };
interface NameMap : Node { Type contentType (in int index); Struct key (in int index); Value value (in Name key); }; interface NameMapEditor : NameMap, Editor { boolean setKey (in Name key, in Value value); boolean removeKey (in Name key); }; interface NodeMap : Node { Type contentType (in int index); Node key (in int index); Value value (in Node index); }; interface NodeMapEditor : NodeMap, Editor { boolean setKey (in Node key, in Value value); boolean removeKey (in Node key); };
interface Type : Value { readonly attribute Name name; boolean allowedValue (in Value val); }; interface AtomicType : Type { }; interface NodeType : Type { }; interface StructType : NodeType { readonly attribute Sequence extends; readonly attribute NameMap properties; readonly attribute NameMap defaults; Type property (in Name name); }; interface SequenceType : NodeType { readonly attribute Type valueType; readonly attribute int minLength; readonly attribute int maxLength; }; interface MapType : NodeType { readonly attribute Type keyType; readonly attribute Type valueType; }; interface UnionType : NodeType { readonly attribute Sequence types; };
<!-- NODAL SCHEMA DTD DTD for description of types in the NODAL Repository AUTHOR: Lee Iverson <leei@ai.sri.com> VERSION: 0.2 (2001-03-23) LOCATION: "http://www.ai.sri.com/~leei/OHS/nodal-types.dtd" --> <!-- The simpleType element and its constituent parts are defined in XML Schema: Part 2: Datatypes --> <!ENTITY % xs-datatypes PUBLIC 'datatypes' 'http://www.w3.org/2001/datatypes.dtd' > <!ENTITY % p 'xs:'> <!-- can be overriden in the internal subset of a schema document to establish a different namespace prefix --> <!ENTITY % s ':xs'> <!-- if %p is defined (e.g. as foo:) then you must also define %s as the suffix for the appropriate namespace declaration (e.g. :foo) --> <!ENTITY % nds 'xmlns%s;'> <!-- Entities --> <!ENTITY % simpleType '%p;simpleType' > <!ENTITY % NodeType "(struct | sequence | map | union)" > <!ENTITY % Type "(%simpleType; | %NodeType;)" > <!-- Nodal building blocks --> <!ELEMENT schema (%simpleType; | nodeType)* > <!ELEMENT sequence EMPTY> <!ATTLIST sequence valueType IDREF #REQUIRED minLength NMTOKEN #IMPLIED maxLength NMTOKEN #IMPLIED > <!ELEMENT map EMPTY> <!ATTLIST map keyType IDREF #REQUIRED valueType IDREF #REQUIRED > <!ELEMENT union (%NodeType;)+ > <!ATTLIST union types IDREFS #IMPLIED > <!-- Define a new node type --> <!ELEMENT struct (property)* > <!ATTLIST struct extends IDREF #IMPLIED > <!ELEMENT property (%Type;)? > <!ATTLIST property name NMTOKEN #REQUIRED type IDREF #IMPLIED default NMTOKEN #IMPLIED > <!ELEMENT nodeType (%NodeType;) > <!ATTLIST nodeType name NMTOKEN #REQUIRED> <!-- End -->
As a sample application, we can provide a data model that
corresponds to the object model defined for the interfaces
Node
and Attribution
.
The first observation is that even though they both implement
the same interface, there are two kinds of Nodes:
head nodes, which contain are referenced by other
nodes and contain all of the data shared by the different
versions, and version nodes which contain all of the
content and metadata fields which change on editing.
A simple data model reflecting this is outlined below:
<?xml version="1.0"?> <!DOCTYPE schema SYSTEM "/homedir/leei/public_html/OHS/nodal-types.dtd"> <schema xmlns="http://www.ai.sri.com/~leei/OHS/nodal-types.dtd" xmlns:xs="http://www.w3.org/2001/datatypes.dtd"> <xs:simpleType name="boolean"> <xs:restriction base="xs:boolean"/> </xs:simpleType> <xs:simpleType name="character"> <xs:restriction base="xs:character"/> </xs:simpleType> <xs:simpleType name="timestamp"> <xs:restriction base="xs:dateTime"/> </xs:simpleType> <xs:simpleType name="duration"> <xs:restriction base="xs:duration"/> </xs:simpleType> <xs:simpleType name="octet"> <xs:restriction base="xs:unsignedByte"/> </xs:simpleType> <xs:simpleType name="integer"> <xs:restriction base="xs:integer"/> </xs:simpleType> <xs:simpleType name="float"> <xs:restriction base="xs:float"/> </xs:simpleType> <xs:simpleType name="double"> <xs:restriction base="xs:double"/> </xs:simpleType> <xs:simpleType name="name"> <xs:restriction base="xs:string"/> </xs:simpleType> <nodeType name="string"> <sequence valueType="xs:character"/> </nodeType> <nodeType name="Type"> <struct> <property name="name" type="name"/> </struct> </nodeType> <nodeType name="NodeType"> <node extends="Type"/> </nodeType> <nodeType name="StructType"> <struct extends="StructType"> <property name="extends" type="Type"/> <property name="properties"> <map keyType="name" valueType="Type"/> </property> </struct> </nodeType> <nodeType name="SequenceType"> <struct extends="NodeType"> <!-- name always has value "sequence" --> <property name="contentType" type="Type"/> <property name="minLength" type="xs:integer"/> <property name="maxLength" type="xs:integer"/> </struct> </nodeType> <nodeType name="MapType"> <struct extends="NodeType"> <!-- name always has value "map" --> <property name="keyType"> <union types="name Type"/> </property> <property name="valueType" type="Type"/> </struct> </nodeType> <nodeType name="UnionType"> <struct extends="NodeType"> <!-- name always has value "set" --> <property name="types"> <xs:sequence itemType="NodeType" minLength="1"/> </property> </struct> </nodeType> </schema>