spiralcraft.data native XML format

Overview

The spiralcraft.data subsystem supports a standard internal XML format which is used to store and transfer data in suitable scenarios- ie. when a portable, human readable & writable text based format is called for.

Abstract Model

The spiralcraft.data native XML format stores DataComposites (Tuples and Aggregates) and "primitives" (immutable POJOs) in XML resources using a "relationally oriented" containership model.

The outermost element an XML file of this format always represents an instance of a non-primitive Type, and is called a Type element. Each Type element in an XML document corresponds to an instance of a "primitive" (a Java object) or a data Tuple of the specified Type.

Type elements may either contain textual data (for primitive Types) or Property elements.

A Property element defines a value for a specified field of the containing Type. A Property element may contain textual data (for single-valued properties of a primitive Type), or may contain one or more Type elements as appropriate for the cardinality of the associated Field. Each property element corresponds to the assignment of data represented by child elements to a field in the parent element.

Example #1

The following is an example of a Type element which represents a single Customer, albeit not very useful as it contains no data.

 <example:Customer
   xmlns:example="class:/com/example/meta/"
   >
 </example:Customer>

Example #2

The following is an example of a simple primitive Property element inside of a Type element, representing a Customer with a name assigned to it.

 <example:Customer
   xmlns:example="class:/com/example/meta/"
   >
   <name>Joe
   </name>
 </example:Customer>

Example #3

The following is an example of a primitive multi-valued Property element inside of a Type element. For the purposes of this example, the famousQuotes field is an array of Strings (otherwise known formally as a String.array in the spiralcraft.data type system.

 <example:Customer
   xmlns:example="class:/com/example/meta/"
   >
   <name>Joe
   </name>
   
   <famousQuotes>
     <String>Trust me, it'll work
     </String>
 
     <String>Don't worry, we'll never get that much traffic
     </String>
 
     <String>The check is in the mail
     </String>
   </famousQuotes>
 
 </example:Customer>

Example #4

The following is an example of more complex Properties:

 <example:Customer
   xmlns:example="class:/com/example/meta/"
   >
   <name>Joe
   </name>
 
   <billTo>
     <example:Address>
       <street>123 My Way Highway
       </street>
       <stop>Suite 987
       </stop>
       <city>Nowhereville
       </city>
       <state>CA
       </state>
       <zip>94001-0010
       </zip>
     </example:Address>
   </billTo>
 
   <shipTo>
     <example:Address>
       <street>456 Warehouse Ct.
       </street>
       <city>Nowhereville
       </city>
       <state>CA
       </state>
       <zip>94001-0020
       </zip>
     </example:Address>
   </shipTo>
 </example:Customer>

Type Resolution

In the native XML format, the namespace-qualified element name for Type elements constitutes a Type reference. The standardized default behavior is to resolve the local element name against the URI defined for the namespace prefix to create a Type URI.

In example #1 above, the Type URI works out to be class:/com/myexample/meta/Customer.

This URI is then resolved to a type in the standard fashion.

Naming conventions

spiralcraft.data native XML files are usually named in one of 2 ways, depending on how they are being used.

.. as part of a Store

XML data files that are part of a data Store are usually named [Type].data.xml, where [Type] is the local name of the Type being stored in the file.

Example:

 Customer.data.xml
 Order.data.xml
 Invoice.data.xml


.. as standalone data

XML data files are often used to provide application components with contextual information. In this instance, the filename suffix is derived from the contained type, and the filename prefix is application specific.

Example:

 FindMyCurrentOrders.query.xml  (contains a Query that does something application specific)
 ColorChoices.string.list.xml   (contains a list of Strings of color names)

Prototyping using the ref attribute

When creating custom Types, and in many other cases, XML data files will be authored by hand or by IDE tooling. In this scenario, the use of prototyping- a lightweight form of data inheritance- can provide flexibility and re-use.

Normally, when reading from a native XML data file, spiralcraft.data creates an empty Tuple or Aggregate for each non-primitive Type to collect the data field values and/or contents. The prototyping mechanism directs spiralcraft.data to initialize this Tuple or Aggregate from another data source before the local data field values are added.

Prototyping is accomplished by including a URI in the "ref" attribute of Type or Property element. Prototypes are always copied, and changes to the original will never be reflected in existing data (unless the data is re-read from the XML file).

The following example runs a Scan of user type MyType through a standard filter, defined in the StandardFilter.query.xml file relative to the URI of the containing resource:

Example

 <query:Query
   xmlns:query="class:/spiralcraft/data/query/"
   ref="StandardFilter.query.xml"
   >
 
   <debug>true
   </debug>
 
   <source>
     <Scan>
       <type><example:MyType.type/>
       </type>
     </Scan>
   </source>
 
 </query:Query>

Essentially, the outermost query is being defined by the referenced StandardFilter (which is probably a select of some sort), and is further specified here by turning on debugging and providing a contextually relevant source.

Example

The following example creates a meeting and associates a "typical" order of food with the meeting, as detailed in the Typical.foodOrder.xml file.

 <example:Meeting>
   <date>2009-05-23 12:00pm
   </date>
 
   <room>103
   </room>
 
   <foodOrder ref="Typical.foodOrder.xml"/>
 
 </example:Meeting>

Absolute and relative references

The syntax of the ref attribute has 3 variants:

  • Relative URI- eg. ref="MyFile.sometype.xml"
    The relative URI is resolved against the URI of the containing resource
  • Namespace qualified URI- eg. ref="myns:MyFile.sometype.xml"
    The namespace "myns" must be defined and in-scope. The URI path after the ":" is resolved against the URI mapped to the namespace.
  • Absolute URI- eg. ref=":class:/com/my/package/MyResource.sometype.xml"
    Note the ":" prefix- this is a standard URI that is resolvable to an XML resource.

Referencing a Type as metadata

Because the native XML format is used to define Types, Queries, and other metadata, it is sometimes necessary to reference a Type itself, as opposed to an instance of the Type.

By adding the ".type" suffix to a Type element name, the system will resolve the Type object itself as opposed to creating an instance of the Type.

The following example creates a Scan query, which requires a Type for its "type" property in order to know which Type to scan. In this case, we tell the Scan query to scan for all instances of the example:Customer type.

 <query:Scan>
   <type><example:Customer.type/>
   </type>
 </query:Scan>