NODAL: Document Modelling

Lee Iverson
OHS Design Group

Lee Iverson <>
Last modified: Thu May 3 11:19:39 2001

Design Strategy


To begin, we will outline a number of simple principles for organizing these data modelling primitives:

Basic Datatypes

Atomic Types

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).

boolean = xs:boolean

character = xs:character

timestamp = xs:timeDate

duration = xs:duration

octet = xs:unsignedByte

integer = xs:integer

float = xs:float

double = xs:double

name = xs:QName

Nodes: Building Blocks

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);


IDL for Types

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;

Canonical DTD for Nodal Types

       DTD for description of types in the NODAL Repository
       AUTHOR: Lee Iverson <>
       VERSION: 0.2 (2001-03-23)
       LOCATION: "" -->

<!-- The simpleType element and its constituent parts
     are defined in XML Schema: Part 2: Datatypes -->
<!ENTITY % xs-datatypes 
  PUBLIC 'datatypes' '' >

<!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 >

    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
    type IDREF   #IMPLIED
    default NMTOKEN #IMPLIED >

<!ELEMENT nodeType (%NodeType;) >
<!ATTLIST nodeType

<!-- End -->

Data Definitions for Node Classes

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">

  <xs:simpleType name="boolean">
    <xs:restriction base="xs:boolean"/>
  <xs:simpleType name="character">
    <xs:restriction base="xs:character"/>
  <xs:simpleType name="timestamp">
    <xs:restriction base="xs:dateTime"/>
  <xs:simpleType name="duration">
    <xs:restriction base="xs:duration"/>
  <xs:simpleType name="octet">
    <xs:restriction base="xs:unsignedByte"/>
  <xs:simpleType name="integer">
    <xs:restriction base="xs:integer"/>
  <xs:simpleType name="float">
    <xs:restriction base="xs:float"/>
  <xs:simpleType name="double">
    <xs:restriction base="xs:double"/>
  <xs:simpleType name="name">
    <xs:restriction base="xs:string"/>
  <nodeType name="string">
    <sequence valueType="xs:character"/>

  <nodeType name="Type">
      <property name="name" type="name"/>

  <nodeType name="NodeType">
    <node extends="Type"/>

  <nodeType name="StructType">
    <struct extends="StructType">
      <property name="extends" type="Type"/>
      <property name="properties"> 
	<map keyType="name" valueType="Type"/>

  <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"/>

  <nodeType name="MapType">
    <struct extends="NodeType">
      <!-- name always has value "map" -->
      <property name="keyType">
	<union types="name Type"/>
      <property name="valueType" type="Type"/>

  <nodeType name="UnionType">
    <struct extends="NodeType">
      <!-- name always has value "set" -->
      <property name="types">
        <xs:sequence itemType="NodeType" minLength="1"/>