Data in SCXML documents

SCXML documents contain numerous expressions, such as when describing the guard conditions for <transition> elements, the expressions that are logged via the <log> element, assignments etc. The data portions in these expressions can come from a couple of sources.

The datamodel element

SCXML gives authors the ability to define a first-class data model as part of the SCXML document. A data model consists of a <datamodel> element containing one or more <data> element, each of which may contain a XML data tree. For example, the document level data model for a SCXML document defining the states in a travel reservation system may look like this:

     <scxml xmlns="http://www.w3.org/2005/07/SCXML"
               version="1.0"
               initialstate="init-travel-plan">

      <datamodel>
        <data name="airlineticket">
          <flight>
            <origin/>
            <destination/>
            <!-- default values for trip and class -->
            <trip>round</trip>
            <class>economy</class>
            <meal/>
          </flight>
        </data>
        <data name="hotelbooking">
          <hotel>
            <stay>
              <startdate/>
              <enddate/>
            </stay>
            <adults>1</adults>
            <children>0</children>
            <rooms>1</rooms>
            <rate/>
          </hotel>
        </data>
      </datamodel>

      <state id="init-travel-plan">
        <!-- content for the init-travel-plan state -->
      </state>

      <!-- and so on ... -->

     </scxml>
    

A <data> element may also contain a string literal or number, which can be considered as a degenerate XML data tree with a single leaf node:

     <data name="foo" expr='bar'" />
    

Scratch space variables

SCXML also allows document authors to define scratch space variables. These may be defined only where executable content is permissible, that is within an <onentry>, <onexit> or <transition> element. A <var> element is used for such definition, like so:

     <onentry>
      <var name="foo" expr="'bar'" />
     </onentry>
    

The difference between the use of a var element as shown above and the degenerate use of a data element (where it contains a single string literal or number, rather than an XML tree) is that the data element is part of the first class datamodel for the document (or state) but the var isn't. This subtlety manifests as different behavior when the SCXML engine is reset, whereby the scratch space variables (var) are lost or deleted, whereas the first class data model elements are restored to their initial value.

Distributing the data model

The <datamodel> element can be "distributed" through the SCXML document. It can be placed as a child element of either the <scxml> element (document root) or any <state> element. This is meant to be an authoring convenience in order to allow parts of the data model to be placed closer to the location in the document where they will be accessed (via expressions, for example).

For example, the above travel reservation datamodel may be authored as follows:

     <scxml xmlns="http://www.w3.org/2005/07/SCXML"
               version="1.0"
               initialstate="airline-ticket">

      <state id="airline-ticket">
        <datamodel>
          <data name="airlineticket">
            <flight>
              <origin/>
              <destination/>
              <!-- default values for trip and class -->
              <trip>round</trip>
              <class>economy</class>
              <meal/>
            </flight>
          </data>
        </datamodel>

        <!-- other content for the airline-ticket state -->

        <!-- event names on transitions arbitrarily chosen
                for illustration-->

        <transition event="done.flight.reservation" target="hotel-booking" />
      </state>

      <state id="hotel-booking">
        <datamodel>
          <data name="hotelbooking">
            <hotel>
              <stay>
                <startdate/>
                <enddate/>
              </stay>
              <adults>1</adults>
              <children>0</children>
              <rooms>1</rooms>
              <rate/>
            </hotel>
          </data>
        </datamodel>

        <!-- other content for the hotel-booking state -->

        <transition event="done.hotel.booking" target="hotel-booking" />
      </state>

      <!-- other states ... -->

     </scxml>
    

Commons SCXML creates a new Context for each state that needs one, and each data element may be thought of as a org.w3c.dom.Node object placed in the corresponding Context. The datamodel element at the document root populates the root context. See contexts and evaluators section of this user guide for more on contexts, evaluators and root contexts.

References to data in expressions

Since the data elements contain XML data trees, the straightforward way to refer to bits inside these in expressions is to use XPath or an equivalent language. Commons SCXML currently supports expression languages such as Commons JEXL and Commons EL, which do not have any inherent understanding of XPath. Therefore, Commons SCXML defines a Data() function for use in JEXL or EL expressions, for example:

    <var name="arrival" expr="Data(hotelbooking, 'hotel/stay/arrival')" />
   

The above expression extracts the arrival date from the hotelbooking data in the documents datamodel and stores it in a scratch space variable named "arrival". The first argument is value of the name attribute of the <data> element and the second is the String value of the XPath expression. If more than one matching nodes are found, the first one is returned.

Assignments

Assignments are done via the SCXML <assign> action, which can only be placed in an <onentry>, <onexit> or <transition> element. Based on the left hand side value (lvalue) and right hand side value (rvalue) in the assignment, Commons SCXML supports three kinds of assignments:

  1. Assigning to a scratch space variable - Here, the lvalue is a variable defined via a <var> element.

          <assign name="foo" expr="some-expression" />
        
    The expression may return a value of any type, which becomes the new value for the variable named "foo".

  2. Assigning a literal to a data subtree - In this case, the lvalue is a node in a data tree and the rvalue is a String literal or a number.

          <assign location="Data(hotelbooking, 'hotel/rooms')" expr="2" />
        
    Or more usefully, the rvalue is some expression that evaluates to the numeric constant (2). In such cases, the literal (String or number) is added as a child text node to the node the lvalue points to.

  3. Assigning a XML tree to a data subtree - Here, the lvalue is a node in a data tree and the rvalue is also a node (in a data tree or otherwise). As an illustration, consider we also had data related to car rentals in the above example, and in certain situations (probably common) the car rental reservation dates coincide with the hotel booking dates, such a data "copy" is performed as:

          <assign location="Data(carrental, 'car/dates')"
                     expr="Data(hotelbooking, 'hotel/stay')" />
    
          <!-- copies over all children of <stay>, the
                  <startdate> and <enddate> in this case -->
        
    In these cases, the node pointed by the expression is first cloned, and then added as a child node to the node the lvalue points to.