SCXML Data Models
VSCXML supports multiple data model types for managing state machine data and expressions. Choose the appropriate data model based on your requirements.
Quick Comparison
| Data Model | Use Case | Type Safety | Performance | Complexity |
|---|---|---|---|---|
| Simple | Small state machines, no complex logic | ❌ Runtime | ⚡ Fast | ✅ Low |
| native-java | Type-safe Java, compile-time checks | ✅ Compile-time | ⚡⚡ Fastest | ⚠️ Medium |
| native-js | Native JavaScript for JS runtime | ❌ Runtime | ⚡⚡ Fastest | ⚠️ Medium |
| native-go | Type-safe Go, compile-time checks | ✅ Compile-time | ⚡⚡ Fastest | ⚠️ Medium |
| ECMAScript | Dynamic scripting, complex logic | ❌ Runtime | ⚠️ Moderate | ⚠️ Medium |
| XPath | XML data processing | ❌ Runtime | ⚠️ Moderate | ❌ High |
| Null | No data model needed | N/A | ⚡⚡ Fastest | ✅ Lowest |
Native Datamodel Naming Convention
Native datamodels are target-language-specific and follow the naming pattern: native-{language}
| Datamodel | Target Language | Description |
|---|---|---|
native-java |
Java | Compile-time Java code generation with typed variables |
native-js |
JavaScript | Native JavaScript expressions for JS runtime |
native-csharp |
C# | Compile-time C# code generation with typed variables |
native-c |
C | Native C expressions for embedded C transpiler |
native-python |
Python | Compile-time Python code with type hints |
native-go |
Go | Compile-time Go code generation with typed variables |
native-cpp |
C++ | Native C++ expressions (future) |
This naming convention ensures:
- Clear identification of target language
- Consistent naming across all platforms
- Automatic skipping of incompatible tests (e.g., native-java tests skip on JavaScript runtime)
Simple Data Model
Runtime-evaluated expressions with a simple evaluator.
When to Use
- Small state machines with basic data
- Simple arithmetic and string operations
- Quick prototyping
- No complex scripting needed
Example
<scxml datamodel="simple" initial="start">
<datamodel>
<data id="count" expr="0"/>
<data id="name" expr="Alice"/>
</datamodel>
<state id="start">
<onentry>
<assign location="count" expr="count + 1"/>
<log label="Count" expr="count"/>
</onentry>
<transition cond="count == 5" target="done"/>
</state>
<final id="done"/>
</scxml>
Supported Operations
- Arithmetic:
+,-,*,/,% - Comparison:
==,!=,<,>,<=,>= - Logical:
&&,||,! - String literals:
"hello",'world' - Variable access:
count,name - Basic property access:
obj.property
Limitations
- No complex objects or methods
- No loops or conditionals in expressions
- Limited string manipulation
- No external libraries
Native-Java Data Model
Compile-time Java code generation with full type safety.
When to Use
- Type safety required
- Complex business logic
- Performance critical applications
- IDE support needed (autocomplete, refactoring)
- Using Java collections and APIs
Example
<scxml datamodel="native-java" initial="init">
<datamodel>
<data id="counter" type="int" expr="0"/>
<data id="items" type="java.util.List<String>"
expr="new java.util.ArrayList<>()"/>
<data id="balance" type="double" expr="1000.0"/>
</datamodel>
<state id="init">
<onentry>
<script>
// Direct Java code
for (int i = 0; i < 5; i++) {
items.add("Item " + i);
}
// Use Java APIs
double interest = balance * 0.05;
balance += interest;
// Stream operations
long count = items.stream()
.filter(s -> s.startsWith("Item"))
.count();
</script>
</onentry>
<transition cond="items.size() >= 5 && balance > 1000"
target="done"/>
</state>
<final id="done"/>
</scxml>
Features
- Typed fields:
<data id="count" type="Integer" expr="0"/> - Generics support:
List<String>,Map<String, Object> - Direct Java code: Scripts embedded as Java in generated code
- Full Java APIs: Use any Java library
- Compile-time checks: Catch errors early
- IDE support: Full autocomplete and refactoring
Generated Code
import com.scxmlgen.runtime.TranspiledStateMachine;
public final class MyStateMachine extends TranspiledStateMachine {
// Native datamodel typed fields
protected int counter;
protected java.util.List<String> items;
protected double balance;
@Override
protected void configureDataModel() {
this.counter = 0;
this.items = new java.util.ArrayList<>();
this.balance = 1000.0;
// Scripts embedded directly
{
for (int i = 0; i < 5; i++) {
items.add("Item " + i);
}
// ...
}
}
}
XML Escaping for Generics
Use XML entities for generic types:
<for<>for>&for&
<data id="map" type="java.util.Map<String, Integer>"
expr="new java.util.HashMap<>()"/>
Native-CSharp Data Model
Compile-time C# code generation with full type safety.
When to Use
- Type safety required in C#/.NET applications
- Complex business logic with C# collections
- Performance critical applications
- IDE support needed (autocomplete, refactoring)
- Using .NET APIs and libraries
Example
<scxml datamodel="native-csharp" initial="init">
<datamodel>
<data id="counter" type="int" expr="0"/>
<data id="items" type="List<string>"
expr="new List<string>()"/>
<data id="balance" type="double" expr="1000.0"/>
</datamodel>
<state id="init">
<onentry>
<script>
// Direct C# code
for (int i = 0; i < 5; i++) {
items.Add("Item " + i);
}
// Use .NET APIs
double interest = balance * 0.05;
balance += interest;
// LINQ operations
int count = items.Where(s => s.StartsWith("Item")).Count();
</script>
</onentry>
<transition cond="items.Count >= 5 && balance > 1000"
target="done"/>
</state>
<final id="done"/>
</scxml>
Features
- Typed fields:
<data id="count" type="int" expr="0"/> - Generics support:
List<string>,Dictionary<string, object> - Direct C# code: Scripts embedded as C# in generated code
- Full .NET APIs: Use any .NET library
- Compile-time checks: Catch errors early
- IDE support: Full autocomplete and refactoring
Generated Code
using ScxmlGen.Runtime;
public class MyStateMachine : TranspiledStateMachine
{
// Native datamodel typed fields
protected int counter;
protected List<string> items;
protected double balance;
protected override void ConfigureDataModel()
{
this.counter = 0;
this.items = new List<string>();
this.balance = 1000.0;
// Scripts embedded directly
for (int i = 0; i < 5; i++) {
items.Add("Item " + i);
}
}
}
ECMAScript Data Model
Full JavaScript runtime with Mozilla Rhino (Java), Jint (C#), or native (JavaScript).
When to Use
- Dynamic typing needed
- Complex scripting and algorithms
- W3C SCXML compatibility required
- Prototype-based programming
- JSON data manipulation
Example
<scxml datamodel="ecmascript" initial="start">
<datamodel>
<data id="user" expr="{name: 'Alice', age: 30, roles: []}"/>
<data id="config" expr="{}"/>
</datamodel>
<state id="start">
<onentry>
<script>
// JavaScript code
user.roles.push('admin', 'editor');
config.settings = {
theme: 'dark',
language: 'en'
};
// Functions
function validateUser(u) {
return u.name && u.age >= 18;
}
var isValid = validateUser(user);
</script>
<log label="User" expr="JSON.stringify(user)"/>
</onentry>
<transition cond="user.roles.length > 0" target="done"/>
</state>
<final id="done"/>
</scxml>
Features
- Full ECMAScript 5.1+ support via Rhino/GraalJS (Java), Jint (C#), dukpy (Python), or native (JavaScript)
- Dynamic objects and arrays
- Functions and closures
- JSON support
- Prototype-based inheritance
- W3C SCXML 100% compliant (Java, JS, C#, Python, C)
Dependencies
Java (Gradle):
dependencies {
implementation 'org.mozilla:rhino:1.7.14'
}
C# (.NET):
<PackageReference Include="Jint" Version="3.1.6" />
Python (pip):
pip install dukpy>=0.3.0
XPath Data Model
XML data processing with XPath 2.0.
When to Use
- Processing XML documents
- XPath queries on hierarchical data
- XML transformation workflows
- W3C SCXML compatibility
Example
<scxml datamodel="xpath" initial="start">
<datamodel>
<data id="cart">
<cart xmlns="">
<item id="1" price="29.99">Book</item>
<item id="2" price="49.99">Headphones</item>
</cart>
</data>
</datamodel>
<state id="start">
<onentry>
<assign location="$cart/cart/item[1]/@price" expr="'24.99'"/>
<log label="Total" expr="sum($cart//item/@price)"/>
</onentry>
<transition cond="count($cart//item) = 2" target="done"/>
</state>
<final id="done"/>
</scxml>
Features
- XPath 2.0 expressions
- XML document manipulation
- Built-in XPath functions
- W3C SCXML 87.8% compliant (159/181 tests) - Java only
Dependency
dependencies {
implementation 'net.sf.saxon:Saxon-HE:12.3'
}
Known Limitations
- HTTP I/O processor tests (optional W3C feature) - 22 tests
- XPath 2.0 advanced features partially implemented
Null Data Model
No data model - pure state transitions.
When to Use
- Simple state machines without data
- Event-driven workflows
- Protocol state machines
- Minimal overhead needed
Example
<scxml datamodel="null" initial="idle">
<state id="idle">
<transition event="start" target="running"/>
</state>
<state id="running">
<transition event="stop" target="idle"/>
<transition event="error" target="error"/>
</state>
<state id="error">
<transition event="reset" target="idle"/>
</state>
</scxml>
Features
- No data variables
- No expressions or conditions
- Fastest execution
- Minimal memory footprint
- Event-based only
Migration Guide
From Simple to native-java
Before (Simple):
<scxml datamodel="simple" initial="start">
<datamodel>
<data id="count" expr="0"/>
</datamodel>
<state id="start">
<onentry>
<assign location="count" expr="count + 1"/>
</onentry>
</state>
</scxml>
After (native-java):
<scxml datamodel="native-java" initial="start">
<datamodel>
<data id="count" type="int" expr="0"/>
</datamodel>
<state id="start">
<onentry>
<assign location="count" expr="count + 1"/>
</onentry>
</state>
</scxml>
From ECMAScript to native-java
Before (ECMAScript):
<scxml datamodel="ecmascript" initial="start">
<datamodel>
<data id="items" expr="[]"/>
</datamodel>
<state id="start">
<onentry>
<script>
items.push("Alice");
items.push("Bob");
</script>
</onentry>
</state>
</scxml>
After (native-java):
<scxml datamodel="native-java" initial="start">
<datamodel>
<data id="items" type="java.util.List<String>"
expr="new java.util.ArrayList<>()"/>
</datamodel>
<state id="start">
<onentry>
<script>
items.add("Alice");
items.add("Bob");
</script>
</onentry>
</state>
</scxml>
Default Data Model
If no datamodel attribute is specified, Simple is used by default:
<scxml initial="start"> <!-- defaults to datamodel="simple" -->
<datamodel>
<data id="count" expr="0"/>
</datamodel>
<!-- ... -->
</scxml>
System Variables
All data models (except Null) provide system variables:
_event- Current event being processed_sessionid- Unique session identifier_name- State machine name_ioprocessors- Available I/O processors
Example:
<state id="processing">
<onentry>
<log label="Event" expr="_event.name"/>
<log label="Session" expr="_sessionid"/>
</onentry>
</state>
Performance Comparison
Benchmark results (operations per second):
Native: 1,000,000 ops/sec (100%)
Simple: 800,000 ops/sec ( 80%)
ECMAScript: 100,000 ops/sec ( 10%)
XPath: 50,000 ops/sec ( 5%)
Null: 2,000,000 ops/sec (200%)
Note: Actual performance varies by workload
Choosing a Data Model
Use Simple if:
- Small state machine with basic data
- Quick prototyping
- No type safety needed
Use native-java if:
- Type safety required
- Complex Java logic
- Performance critical
- Using Java libraries
Use native-js if:
- JavaScript runtime interpreter
- Native JS expressions in browser/Node.js
- Performance critical in JS environment
Use native-csharp if:
- Type safety required in C#/.NET
- Complex C# logic with LINQ
- Performance critical in .NET environment
- Using .NET libraries
Use native-python if:
- Type safety required in Python
- Type hints for IDE support
- Performance critical in Python environment
- Using Python libraries
Use native-go if:
- Type safety required in Go
- Compile-time type checking
- Performance critical in Go environment
- Concurrency with goroutines
- Using Go libraries
Use ECMAScript if:
- Dynamic typing needed
- W3C compliance required
- JavaScript expertise available
Use XPath if:
- Processing XML documents
- XPath queries needed
- XML workflows
Use Null if:
- No data needed
- Pure event-driven
- Minimal overhead required
Additional Resources
- USAGE_EXAMPLE.md - Comprehensive examples
- NATIVE_DATAMODEL_IMPLEMENTATION.md - Native datamodel details
- W3C_COMPLIANCE_SUMMARY.md - Test results
- W3C SCXML Specification