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.
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 an XML data tree (i.e. it is recommended that each <data> element contain only one child element).
Also, SCXML documents are namespace-aware. Therefore, the root of the data tree should define one or more namespaces as needed, and must not itself be in the SCXML namespace.
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"> <!-- Note namespace declaration in line below --> <flight xmlns=""> <origin/> <destination/> <!-- default values for trip and class --> <trip>round</trip> <class>economy</class> <meal/> </flight> </data> <data name="hotelbooking"> <hotel xmlns=""> <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'" />
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.
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 xmlns=""> <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 xmlns=""> <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
for each state that needs one, and each data element may be thought of
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
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 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:
<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".
<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.
<assign location="Data(carrental, 'car/dates')" expr="Data(hotelbooking, 'hotel/stay')" /> <!-- deletes all children of <dates> and then copies over all children of <stay>, the <startdate> and <enddate> in this case -->In these cases, the children of the node pointed by the expression are first cloned, and then added as children to the node the lvalue points to.