4. Data Language

This document describes how to define new data types using the Jitsu Xml Data Language. It convers basic topics like defining simple records and lists. Towards the end, we also talk about some of the more advanced features required by controls.

Introduction

The Jitsu Xml Data Language is a relatively lightweight set of Xml elements for describing data types and their corresponding markup. It was designed expressly to let the page compiler convert Xml markup into JavaScript objects in a compiled Jitsu project.

The Jitsu Data Language was designed with the following goals in mind:

Types and Instances

To extend the set of types recognized by the Jitsu compiler, add a <j:module> element to your document. The <j:module> element lets you introduce new types, enums or controls. For example, here is a basic module definition:

    <j:module xmlns:j="http://www.jitsu.org/schemas/2006" 
              targetNamespace="urn:myapp">

        <j:type name="Item">
            <j:property name="title" />
            <j:property name="displayDate" type="dateTime" />
        </j:type>
                
    </j:module>

This module defines a new type called "Item", which has two properties, a "title" property (a string), and a displayDate property (a date).

Adding a module to a document does two things: it causes JavaScript code to be generated, and it extends the Xml syntax available in the document.

More specifically, the Jitsu compiler uses type modules to generate a JavaScript "class" for each of the types defined in the module - each type corresponds to a JavaScript at runtime in the final application.

As well, adding a module to a document extends the set of Xml elements the compiler recognizes in that document - once you've defined a type, in the rest of the document (i.e. outside the module definition) you can write instances of that type in Xml. For example, here's an Item instance:

    <Item xmlns="urn:myapp">
        <title>Hello world</title>
        <displayDate>2005-01-03T14:23:00Z</displayDate>
    </Item>

When the Jitsu compiler sees an Xml element in a document, it looks in its list of loaded modules to see if the element is recognized. In this case, <Item> corresponds to the Item type we defined just above - so Jitsu uses that type definition to process the element - it knows in this case that Item is an object with title and displayName properties.

Note that Jitsu uses Xml Namespaces to create associations between elements and types in Xml documents. The <j:module>'s targetNamespace attribute indicates what namespace the defined types belong to (in this case the namespace "urn:myapp"). Elements using the same namespace are recognized as instances.

As a second example, below we define a new type called Link, and then write three instances of Link:

<j:module xmlns:j="http://www.jitsu.org/schemas/2006" 
          targetNamespace="urn:myapp" >
        
    <j:type name="Link">

        <j:property name="title" type="string"/>

        <j:property name="url" type="Url">
            <j:required/>
        </j:property>
        
    </j:type>

</j:module>

<app:Link title="Hello" url="http://www.w3.org"/>

<!-- title is not "required", so this works: --/>   
<app:Link url="http://www.w3.org"/>

<!-- url is "required", so this is an error: --/>    
<app:Link/>

<!--  use elements and attribute interchangeably --/>    
<app:Link title="Another link">
    <app:url>http://www.w3.org</app:url>
</app:Link>

Instances properties

When defining an instance of a type, the following rules apply:

In Jitsu, simple properties can either be specified using an element or an attribute. For example, the following are treated as equivalent:

        <Person firstName="Joe"/>

        <Person>
            <firstName>Joe</firstName>
        </Person>    
    

Whether you use an element or an attribute for simple properties is a matter of convention.

Complex properties are properties containing either lists or nested types. These are always specified using nested elements.

Type names

By convention, types have Pascal-cased names (e.g. Person, Comment, Address). Properties in a type use a camel-cased names (e.g. fieldOne, fooBar).

When you define a type using <j:type>, the Jitsu Compiler turns this into a JavaScript class definition.The compiled version of the Person type above looks something like:

function Person() { }
Person.publicProperties = ["firstName", "lastName"];
Person.prototype = new DataObject();
Person.prototype.constructor = Person;
// Other Person metadata appears here too...

Similarly, instances of the Person on the page are code-generated into fragments of JavaScript:

<Person firstName="Joe"/>

becomes

// Create <Person> 
o = new Person();
o.firstName = 'Joe';

This means that, when creating data types, you must pick type names and property names which are valid JavaScript programming language identifier names. Avoid names like "for" or "var" or "Object" or "my name with spaces" as names.

The Jitsu compiler will produce an error if you use a language-reserved name for a data type, but it is still possible to pick a name that clashes with another piece of Javascript.

In some cases the Xml type name and JavaScript class name may differ. <j:type> and <j:property> both support an attribute called javaScriptName which lets you override the name of the type in JavaScript. e.g.

<j:type name="list" javaScriptName="MyList"  ...

You can also specify a value for javaScriptPrefix on a module:

<j:module javaScriptPrefix="Eg_" 
        targetNamespace="urn:example">

This tells the compiler to prepend "Eg_" in front of all the names it generates.

Local versus external definitions

Type modules appear at the start of a document containing instances. For example:

<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:j="http://www.jitsu.org/schemas/2006">

    <!-- Define a Person type -->
    
    <j:module xmlns="http://www.jitsu.org/schemas/2006" 
              targetNamespace="urn:app">			
        <type name="Person">
            <property name="firstName" required="true"/>
            <property name="lastName" required="true"/>
            <property name="age" type="int" />
            <property name="cool" type="bool" />
            <property name="imageUrl" type="string"/>
            <property name="activities" type="string[]"/>
            <property name="friends" type="Person[]" />
        </type>
    </j:module>

    <body>
        <j:App>
            <j:data>
                <j:DataSet id="people" xmlns:a="urn:myapp">

                    <!-- here is a Person -->

                    <a:Person firstName="Fred" lastName="Flintstone" 
                            age="50" cool="true" imageUrl="images/fred.gif">
                        <a:activities>
                            <j:di>bowling</j:di>
                            <j:di>pool</j:di>
                        </a:activities>
                        <a:friends>
                            <a:Person firstName="Barney" lastName="Rubble"/>
                        </a:friends>
                    </a:Person>

                ...

Alternatively, place the type declarations in an external Xml file and include it with a "using" directive. For example:

<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:j="http://www.jitsu.org/schemas/2006">

    <!-- Load the type module in person.xml : -->

    <j:using src="person.xml">


    ...

When the document loader encounters a j:using tag, it parses the specified src file and makes any defininitions found in the file available to the current document.

Jitsu resolves "using" directives by first looking for the file in the same directory as the document it is reading. If the file is not found there, Jitsu searches an include path looking for the file.

Simple Property Types

A Property may hold a simple of a complex value. The following table lists all the Jitsu simple types:

Type NameDescription
int32-bit integer
float64-bit IEEE floating point number
boolBoolean true and false.
dateTimeISO 8601 compliant date string. e.g. "2004-11-07T19:35:00+00:00".
stringA UTF-8 encoded string.
xmlA fragment of Xml.

To specify that a property contains a simple type, use the simple type's lower case name, e.g. here is "Person" type with a firstName property defined as a string type:

    <j:type name="Person">
        <j:property name="creationDate" type="dateTime"/>
    </j:type>        

Here's an example of how a Person element might appear in a Jitsu document:

    <Person creationDate="1968-05-22T03:35:00+00:00"/>

If a property doesn't specify a type, it defaults to string.

Bools

If a property is declared with type="bool", then when writing instances you can use an empty element to signify true. i.e. if "isDynamic" is a property with type="bool", the following are equivalent:

    <Example isDynamic="true"/>

    <Example>
        <isDynamic>true</isDynamic>
    </Example>    

    <Example>
        <isDynamic/>
    </Example>    

Restrictions

You use restrictions to add additional constraints to a property, narrowing the legal range of values.

Restrictions can only be used on string or numeric properties.

Restriction details are written using a nested <restriction> element in a property declaration. For example:

<j:property name="primaryEmail" type="string">
    <j:restriction>
        <!-- restrict the max length, regex pattern -->
        <j:maxLength>255</j:maxLength>
        <j:pattern>\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*</j:pattern>  
        <j:validationErrorMessage>Invalid email address</j:validationErrorMessage>
    </j:restriction>
</j:property>

String restrictions can specify a maxLength, minLength and pattern (a regular expression pattern). They can also specify an error message to show if the user specifies an invalid value for the property.

For numeric types (int, float) the restriction can specify a minValue and a maxValue for the number. e.g.

<j:property name="age" type="int">
    <j:restriction>
        <!-- restrict the age range -->
        <j:minValue>0</j:minValue>
        <j:maxValue>120</j:maxValue>
    </j:restriction>
</j:property>

Both minValue and maxValue are optional. i.e. you can restrict either the minimum or maximum value or both.

Enums

Enums specify a fixed set of possible textual values for a property. By convention, Enum types have a Pascal-cased names (UserCode, PriceType, EntryMode etc.). The values in an enum type are camelCased.

Below is a module defining a PriceCode enum, and an Item type that has a priceCode property:

<j:module xmlns:j="http://www.jitsu.org/schemas/2006" 
        targetNamespace="urn:app">

    <j:enum name="PriceCode">
        <j:values>
            <j:di>cheap</j:di>
            <j:di>notSoCheap</j:di>
            <j:di>veryUnCheap</j:di>
            <j:di>beyondNotCheap</j:di>
        </values>
        <j:displayNames>
            <j:di>Cheap</j:di>
            <j:di>Thrifty</j:di>
            <j:di>Moderate</j:di>
            <j:di>Expensive</j:di>
        </j:displayNames>
    </j:enum>        

    <!-- Item has a priceCode property of type PriceCode -->
    <j:type name="Item">
        <j:property name="priceCode" type="PriceCode"/>
    </j:type>        

</j:module>

(the "di" above stands for "data item" - see the section on Lists below).

When writing enum properties in instances, use any one of the values listed. e.g.

    <app:Item priceCode="notSoCheap"/>
    <app:Item priceCode="cheap"/>

    <-- causes a compile error -->
    <app:Item priceCode="free"/>

About display names

Notice that in the enum definition above, in addition to a list of values we also gave a list of displayNames. You can specify a displayName for any property or type in a module. e.g. you can write:

<j:type name="Item" displayName="Vendor Product">
    <j:property name="priceCode" displayName="Price Range" type="PriceCode"/>
</j:type>        
    

The Jitsu page compiler saves the displayName information into the compiled JavaScript class definition for a type - this allows a page to show a property name or value to the user - see the Validation quick tour.

For Enums, you provide a list of displayNames for each item. The order must match the order of the list of values. (i.e. the first member in displayNames corresponds to the first member in values).

List Types

You use List types for ordered sequences of zero or more objects.

For example, here is a type definition for an Entry, whose locations property holds a list of Addresses:

<j:module xmlns:j="http://www.jitsu.org/schemas/2006" 
        targetNamespace="urn:somenamespace">

    <j:type name="Entry">
        <j:property name="locations" type="Address[]"/>
    </j:type>

    <j:type name="Address">
        <j:property name="city" />
        <j:property name="state" />
    </j:type>
</j:module>    

Notice that the locations property type has a "[]" in the name. This indicates that the locations property holds a list of Address objects.

An instance of Entry might appear in an Xml document as:

    <Entry xmlns="urn:somenamespace">
        <locations>
            <Address>
                <city>New York</city>
                <state>NY</state>
            </Address>
            <Address>
                <city>San Francisco</city>
                <state>CA</state>
            </Address>
        </locations>
    </Entry>

Note that we've specified two addresses - you could supple zero, three or any other number of address.

By convention, list properties are camel cased and plural, e.g. "locations", "items", "comments", etc.

For lists holding simple values (i.e. int, float), as well as enums and restrictions, the individual values must be boxed in "di" ("data item") elements, e.g. consider a type with a list of Emails:

<j:module xmlns:j="http://www.jitsu.org/schemas/2006" 
          targetNamespace="urn:app">

    <j:type name="Person">
        <j:property name="emails" type="string[]">
    </j:type>

</j:module>
    

In a document, an instance of this Person looks like:

    <app:Person xmlns:app="urn:app"
              xmlns:j="http://www.jitsu.org/schemas/2006">

        <app:emails>
            <j:di>joe@yahoo.com</j:di>
            <j:di>joe@gmail.com</j:di>
            <j:di>joe@hotmail.com</j:di>
        </app:emails>

    </app:Person>

The two namespaces

Notice that the "di" element belongs to the Jitsu namespace, whereas the types you define in a module belong to whatever you set the targetNamespace to. In a Jitsu Xml document, at least two namespaces are in play: The Jitsu namespace, and the targetNamespaces of any modules you write. Since <di> is part of the Jitsu namespace, you must qualify it appropriately in Xml documents.

Dynamic Types

The "object" type

Some properties may be "dynamic", i.e. their type may not be known statically as you are writing a definition, but only dynamically at runtime.

The "object" system type supports dynamic object data.

For example, consider this Item with a content property of type="object":

<j:module xmlns:j="http://www.jitsu.org/schemas/2006"
          targetNamespace="urn:app">

    <j:type name="Item">
        <j:property name="content" type="object">
    </j:type>

</j:module>

For dynamic data, whenever a dynamic property instance appears in Xml, you can use a type attribute to disambiguate the type of the enclosed data.

The following are all valid Item instances:

    <app:Item>
         <!-- content is a string -->
        <app:content j:type="string">Hello</app:content>
    </app:Item>

    <app:Item>
         <!-- content is an int -->
        <app:content j:type="int">23</app:content>
    </app:Item>

    <app:Item>
        <!-- content is a nested Person instance -->
        <app:content>
            <Person>
                <name>Joe</name>
            </Person>
        </content>
    </app:Item>

(In the third case above, the type attribute is optional - if the content is a single nested element, the compiler looks up the element in its list of loaded modules to determine the type).

The "xml" type

Sometimes a property contains nested elements, e.g.

   <Person>
       <title>Jon <b>Meyer</b></title>
   </Person>   

To read fields containing arbitrary xml, you need the "xml" type. The "xml" type lets you embed an Xml element within a property value. e.g. consider a Blog entry struct definition like this:

    <type name="Entry">
        <property name="title"/>
        <property name="date" type="dateTime"/>                    
        <property name="text" type="xml"/>
    </type>

An instance of this might be written as:

    <Entry>
        <title>My first blog post</title>
        <date>2005-01-02T12:11:01Z</date>
        <text>
            <div>
                <h3>Hello</h3>
                Here is a my first <b>Blog Post</b>.
            <div>
        </text>
    </Entry>

A property of type "xml" must contain either a single string or a single element (which may in turn contain nested elements). It shouldn't contain a mixture of strings and elements.

Properties of type XML are converted into strings when compiled. i.e. the JavaScript generated for an Xml property looks like:

// Create <Person> (line: 211)
o2 = new Person();
o2.title = 'Jon <b>Meyer</b>';

Using "base" to extend types

In type definitions, a type may define a base, to extend another type, E.g.

    <type name="Baz" base="Foo">
        <property name="locations">
            <type>Address[]</type>
        </property>
    </control>

In OOP parlance, this defines Baz as a subclass of Foo.

Any Baz instances may use any of the properties defined in Foo and in addition, any of the new properties defined in Baz.

Control Markup

The Jitsu page compiler uses some advanced features of the Jitsu Data Language to describe user interface markup syntax.

The UI extensions add features designed to support the rich expressiveness required for writing UI markup. These features are documentated here for people writing control types - they are not necessary for writing type definitions for use in datasets.

Defining controls

To define a control, instead of using <type> you use <control>. Controls are very similar to types, but inherit from a different base class (Control instead of DataObject) and also support additional fetures that can be defined in a module, such as script and style.

For example, here's a control called PrettyDate that has a property called date and a script that adds that date to the rendered output:

    <j:control name="PrettyDate">
        <j:property name="date" type="dateTime"/>        

        <j:style>
           .pretty { font-size: x-large; color: pink; }
        <j:/style>

        <j:script><!--
                    
        // This control outputs itself as a span with a date inside it
        //
        #method renderChildren(htmlBuilder) {
            htmlBuilder.add('<span class="pretty">');
            htmlBuilder.add(this.getValue(ID_date).toPrettyDateAndTime());
            htmlBuilder.add('</span>');
        }
        --></j:script>
    </j:control>        

When a compiler generates the code for this control definition, it includes the embedded script and CSS styles in the compiled output.

Once you've written a control, you can write instances on a page using the regular instance rules:

    <myapp:PrettyDate date="2005-01-02T12:11:01Z"/>
 
    <myapp:PrettyDate>
        <date>2005-01-02T12:11:01Z</date>
    </myapp:PrettyDate>

The "mixed" type

In control definitions, you can specify that a property has a "mixed" type to supports properties containing a mixing of text, controls, instances and elements.

Whereas "object" supports either a simple typed value (string, int, float etc) or a nested instance, and "xml" supports a literal nested Xml fragment (with no instances), the "mixed" type lets you create properties that are mixtures of text, Xml and instances.

For example, consider this definition:

<module xmlns="http://www.jitsu.org/schemas/2006" 
        targetNamespace="urn:app">

    <control name="Entry">
        <property name="e1">
            <type>mixed[]</type>
        </property>
    </control>

</module>

Then the following values are legal:

    <app:Entry>
        <app:e1>
            Some text 123 
        </app:e1>
    </app:Entry>

    <app:Entry xmlns:html="http://www.w3.org/1999/xhtml">
        <app:e1>
            <html:p>Some text <html:b>With Bold Tags</html:b></html:p>
        </app:e1>
    </app:Entry>

    <app:Entry xmlns:html="http://www.w3.org/1999/xhtml">
        <app:e1>
            <html:p>Some text <html:b>With Bold Tags</html:b>
                and a nested object:
                <app:Entry>
                    <app:e1>with more nested stuff</app:e1>
                </app:Entry>
            </html:p>
        </app:e1>
    </app:Entry>

Note: A mixed property can contain either a single string, a single Xml element, or a single control or object. For that reason, controls use "mixed[]" to support a list of text, Xml and data items.

When reading a mixed property, every time the Jitsu compiler encounters an element, it first looks to see if the element name is mapped to a defined type registered with the document loader. If so, the the object's contents are read using the appropriate rules. If not, the element is read as a generic Xml "Element" instead. This is how the Jitsu compiler supports mixing XHTML elements with controls.

Inline properties

One or more "list" properties in a control may be flagged as "inline". e.g.

<module xmlns="http://www.jitsu.org/schemas/2006" 
        name="MyApp" targetNamespace="urn:app">

    <control name="Part">
        <property name="pieces" type="Piece[]" inline="true"/>
    </control>

    <type name="Piece">
        <property name="name" />
        <property name="size" />
    </type>

</module>

Once a list property has been flagged as inline, elements matching the content model of the property can occur directly within the outer parent element - i.e. you can specify pieces either nested within a <pieces> element:

<Part>
    <pieces>
        <Piece>
            <name>anchor</name>
            <size>3</size>
        </Piece>
        <Piece name="wheel" size="1"/>
    <pieces>
</Part>

or inlined, without the <pieces> element:

<Part>
    <Piece>
        <name>anchor</name>
        <size>3</size>
    </Piece>
    <Piece name="wheel" size="1"/>
</Part>

When the compiler is reading page markup, if it encounters an element that doesn't correspond to one of the control's properties, it checks to see if the element matches one of the inline list properties. If so, the element is processed accordingly. This enables you to create more readable markup, by eliminating property wrapper elements.

Inline mixed[]

The most powerful combination of all is "inline mixed[]". For example, here's a fragment from the definition of the base "Control" type in Jitsu:

    <control name="Control">
        <property name="controlId"/>

        <property name="childControls">
            <type>mixed[]</type>
            <inline/>
        </property>

        ...
    </control>

Flagging the childControls property as both inline and mixed[] tells the Jitsu compiler that <Control> can contain pretty much any kind of content:

For example, you can use:

    <j:Control controlId="foo" xmlns:html="xmlns="http://www.w3.org/1999/xhtml">

        Some text
        
        <html:p>with XHTML markup and <html:b>Bold Tags</html:b>
            and a nested object:

            <j:Control>
                <j:controlId>another</j:controlId>
                with more nested text
            </j:Control>
        </html:p>

    </j:Control>

If multiple properties in a data type are declared inline mixed[], then the last one (i.e. the lowest in a flattened list of properties) wins. This enables subtypes to specify an alternative property to receive inline mixed child content if required. See the discussion of Placeholders in Extending Controls in Markup for an example.

Expando properties

Finally, sometimes you want to be able to attach additional properties to existing types.

For example, in Jitsu on a page using a DockPanel you can write:

    <div j:dock="top">
	<j:Label text="#bind(item.name)"/> 
    </div>

the "dock" property is not defined on div - it is an expando property defined in the jitsu.dockpanel.xml:

    <j:expando name="dock">
        <j:type>DockType</j:type>
    </j:expando>

Once you've declared an expando in a module, that becomes an added property that can be attached to any element or instance in the document containing the module.