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>