You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by at...@apache.org on 2015/12/26 18:50:13 UTC

[1/2] commons-scxml git commit: SCXML-242: Providing JSON base datamodel as replacement for XML/XPath See: https://issues.apache.org/jira/browse/SCXML-242 - adding FasterXML Jackson as (default) json parser - adding new ContentParser to encapsulate Data

Repository: commons-scxml
Updated Branches:
  refs/heads/master 7b3a237b2 -> 6af929eb6


http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-02.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-02.xml b/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-02.xml
deleted file mode 100644
index 6811bc6..0000000
--- a/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-02.xml
+++ /dev/null
@@ -1,90 +0,0 @@
-<?xml version="1.0"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-<!-- A fictitious state machine used by test cases. Meant to illustrate
-     prefixed XPath expressions in the Commons SCXML Data() function -->
-<scxml xmlns="http://www.w3.org/2005/07/scxml"
-       version="1.0"
-       datamodel="jexl"
-       initial="ten">
-
-    <!-- Start with same prefixes, defined in two different places -->
-    <state id="ten">
-
-        <datamodel>
-            <data id="data10" xmlns:ns1="http://namespace.test.domain/1">
-                <root xmlns="">
-                    <ns1:foo>
-                      <bar>10</bar>
-                    </ns1:foo>
-                </root>
-            </data>
-        </datamodel>
-
-        <transition xmlns:ns1="http://namespace.test.domain/1"
-                    event="done.state.ten" cond="Data('string($data10/root/ns1:foo/bar)') eq 10"
-                    target="twenty" />
-
-    </state>
-
-    <!-- Already defined (and different) prefixes -->
-    <state id="twenty" xmlns:ns1="http://namespace.test.domain/1"
-                       xmlns:ns2="http://namespace.test.domain/2"
-                       xmlns:ns3="http://namespace.test.domain/1"
-                       xmlns:ns4="http://namespace.test.domain/2">
-
-        <datamodel>
-            <!-- Start with a prefixless XPath -->
-            <data id="data20">
-                <ns1:root>
-                    <ns2:foo>20</ns2:foo>
-                </ns1:root>
-            </data>
-        </datamodel>
-
-        <transition event="done.state.twenty" cond="Data('string($data20/ns3:root/ns4:foo)') eq 20"
-                    target="thirty" />
-
-    </state>
-
-    <!-- XPath looking at attribute -->
-    <state id="thirty">
-
-        <datamodel>
-            <!-- Start with a prefixless XPath -->
-            <data id="data30">
-                <root xmlns="http://namespace.test.domain/1">
-                    <foo xmlns="http://namespace.test.domain/2"
-                         xmlns:ns1="http://namespace.test.domain/3"
-                         ns1:content="30"/>
-                </root>
-            </data>
-        </datamodel>
-
-        <transition event="done.state.thirty"
-         xmlns:ns1="http://namespace.test.domain/1"
-         xmlns:ns2="http://namespace.test.domain/2"
-         xmlns:ns3="http://namespace.test.domain/3"
-         cond="Data('string($data30/ns1:root/ns2:foo/@ns3:content)') eq 30"
-         target="forty" />
-
-    </state>
-
-    <final id="forty"/>
-
-</scxml>
-

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-03.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-03.xml b/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-03.xml
deleted file mode 100644
index 9dcc9ad..0000000
--- a/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-03.xml
+++ /dev/null
@@ -1,255 +0,0 @@
-<?xml version="1.0"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-<!-- A fictitious state machine used by test cases. Meant to illustrate
-     prefixed XPath expressions in the Commons SCXML Data() function.
-     Used by org.apache.commons.scxml2.NamespacePrefixedPathsTest.
-     Also serves as testing the underlying functionality of the
-     underlying parsing technology -->
-<scxml xmlns="http://www.w3.org/2005/07/scxml"
-       xmlns:cs="http://commons.apache.org/scxml"
-       version="1.0"
-       datamodel="jexl"
-       initial="ten">
-
-     <!-- Root data model -->
-     <datamodel>
-
-        <!-- We'll use this for XPaths -->
-        <data id="rootdata"
-              xmlns:ns1="scheme://namespace.test.domain/1"
-              xmlns:ns2="scheme://namespace.test.domain/2"
-              xmlns:ns3="scheme://namespace.test.domain/3">
-             <ns1:root>
-                <ns2:foo>
-                  <ns3:bar>1</ns3:bar>
-                </ns2:foo>
-            </ns1:root>
-        </data>
-
-        <!-- We'll use this for the JUnit test
-             NamespacePrefixedPathsTest.java (scxml package) -->
-        <data id="retval" />
-
-    </datamodel>
-
-    <!-- State data model -->
-    <state id="ten">
-
-        <datamodel>
-
-            <data id="data10" xmlns:ns4="scheme://namespace.test.domain/1">
-                <root xmlns="">
-                    <ns4:foo>
-                      <bar>10</bar>
-                    </ns4:foo>
-                </root>
-            </data>
-
-        </datamodel>
-
-        <onentry>
-            <cs:var xmlns:pre1="scheme://namespace.test.domain/1"
-                    xmlns:pre2="scheme://namespace.test.domain/2"
-                    xmlns:pre3="scheme://namespace.test.domain/3"
-                    name="tentest"
-                    expr="Data('number($rootdata/pre1:root/pre2:foo/pre3:bar)') + Data('number($data10/root/pre1:foo/bar)')" />
-        </onentry>
-
-        <transition event="done.state.ten" cond="tentest eq 11" target="twenty" />
-
-        <onexit>
-            <assign location="retval" expr="tentest" />
-        </onexit>
-
-    </state>
-
-    <!-- Already defined (and different) prefixes -->
-    <state id="twenty" xmlns:ns1="scheme://namespace.test.domain/1"
-                       xmlns:ns2="scheme://namespace.test.domain/2"
-                       xmlns:ns3="scheme://namespace.test.domain/3">
-
-        <datamodel>
-
-            <data id="data20">
-                <ns1:root>
-                    <ns2:foo>20</ns2:foo>
-                </ns1:root>
-            </data>
-
-        </datamodel>
-
-        <onentry>
-            <assign location="Location('$rootdata/ns1:root/ns2:foo/ns3:bar')" expr="2" />
-        </onentry>
-
-
-        <!-- Redefine namespace prefixes -->
-        <transition event="done.state.twenty"
-                    xmlns:ns1="scheme://namespace.test.domain/1"
-                    xmlns:ns2="scheme://namespace.test.domain/2"
-                    cond="Data('string($data20/ns1:root/ns2:foo)') eq 20 and Data('string($rootdata/ns1:root/ns2:foo/ns3:bar)') eq 2"
-                    target="thirty" />
-
-        <onexit>
-
-            <!-- Redefine different prefixes bound to above namespaces -->
-            <if xmlns:pre1="scheme://namespace.test.domain/1"
-                xmlns:pre2="scheme://namespace.test.domain/2"
-                cond="Data('number($data20/pre1:root/pre2:foo)') lt 20">
-
-                <assign location="retval" expr="'Less than 20'" />
-
-            <elseif cond="Data('number($data20/pre1:root/pre2:foo)') eq 20" />
-
-                <assign location="retval" expr="'Equal to 20'" />
-
-            <else/>
-
-                <assign location="retval" expr="'Greater than 20'" />
-
-            </if>
-
-        </onexit>
-
-    </state>
-
-    <!-- XPath looking at attribute -->
-    <state id="thirty">
-
-        <datamodel>
-
-            <data id="data30">
-                <root xmlns="scheme://namespace.test.domain/1">
-                    <foo xmlns="scheme://namespace.test.domain/2"
-                         xmlns:ns1="scheme://namespace.test.domain/3"
-                         ns1:attfoo="30" attbar="300"/>
-                </root>
-            </data>
-
-        </datamodel>
-
-        <transition event="done.state.thirty"
-         xmlns:ns1="scheme://namespace.test.domain/1"
-         xmlns:ns2="scheme://namespace.test.domain/2"
-         xmlns:ns3="scheme://namespace.test.domain/3"
-         cond="Data('number($data30/ns1:root/ns2:foo/@ns3:attfoo)') + Data('number($data30/ns1:root/ns2:foo/@attbar)') eq 330"
-         target="forty" />
-
-    </state>
-
-    <!-- Multiple data, already defined prefixes -->
-    <state id="forty" xmlns:ns1="scheme://namespace.test.domain/1"
-                      xmlns:ns2="scheme://namespace.test.domain/2"
-                      xmlns:ns3="scheme://namespace.test.domain/3"
-                      xmlns:ns4="scheme://namespace.test.domain/4">
-
-        <datamodel>
-
-            <data id="data40">
-                <root xmlns="">
-                    <ns1:foo ns2:attfoo="40"/>
-                </root>
-            </data>
-
-            <data id="data41">
-                <ns3:root>
-                    <ns4:foo>41</ns4:foo>
-                </ns3:root>
-            </data>
-
-        </datamodel>
-
-        <transition event="done.state.forty"
-         cond="Data('number($data40/root/ns1:foo/@ns2:attfoo)') + Data('number($data41/ns3:root/ns4:foo)') eq 81"
-         target="fifty" />
-
-    </state>
-
-    <!-- Multiple data, prefixes on elements -->
-    <state id="fifty">
-
-        <datamodel>
-
-            <data id="data50"  xmlns:ns1="scheme://namespace.test.domain/1"
-                                 xmlns:ns2="scheme://namespace.test.domain/2"
-                                 xmlns:ns3="scheme://namespace.test.domain/3">
-                <ns1:root>
-                    <ns2:foo ns3:attfoo="50"/>
-                </ns1:root>
-            </data>
-
-            <data id="data51" xmlns:ns3="scheme://namespace.test.domain/3"
-                                xmlns:ns4="scheme://namespace.test.domain/4">
-                <ns3:root>
-                    <ns4:foo attfoo="51"/>
-                </ns3:root>
-            </data>
-
-        </datamodel>
-
-        <transition event="done.state.fifty"
-         xmlns:ns1="scheme://namespace.test.domain/1"
-         xmlns:ns2="scheme://namespace.test.domain/2"
-         xmlns:ns3="scheme://namespace.test.domain/3"
-         xmlns:ns4="scheme://namespace.test.domain/4"
-         cond="Data('number($data50/ns1:root/ns2:foo/@ns3:attfoo)') + Data('number($rootdata/ns1:root/ns2:foo/ns3:bar)') eq 52"
-         target="sixty" />
-
-    </state>
-
-    <!-- Multiple data, prefixes on datamodel and transition elements -->
-    <state id="sixty">
-
-        <datamodel xmlns:ns1="scheme://namespace.test.domain/1"
-                   xmlns:ns2="scheme://namespace.test.domain/2"
-                   xmlns:ns3="scheme://namespace.test.domain/3"
-                   xmlns:ns4="scheme://namespace.test.domain/4">
-
-            <data id="data60">
-                <root xmlns="">
-                    <ns1:foo ns2:attfoo="60"/>
-                </root>
-            </data>
-
-            <data id="data61">
-                <ns3:root>
-                    <ns4:foo attfoo="61"/>
-                </ns3:root>
-            </data>
-
-        </datamodel>
-
-        <transition event="done.state.sixty"
-         xmlns:pre1="scheme://namespace.test.domain/1"
-         xmlns:pre2="scheme://namespace.test.domain/2"
-         xmlns:pre3="scheme://namespace.test.domain/3"
-         xmlns:pre4="scheme://namespace.test.domain/4"
-         cond="Data('number($data60/root/pre1:foo/@pre2:attfoo)') + Data('number($data61/pre3:root/pre4:foo/@attfoo)') eq 121"
-         target="seventy">
-
-            <!-- should be 121 -->
-            <log expr="Data('number($data60/root/pre1:foo/@pre2:attfoo)') + Data('number($data61/pre3:root/pre4:foo/@attfoo)')"/>
-
-        </transition>
-
-    </state>
-
-    <final id="seventy"/>
-
-</scxml>
-

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-04.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-04.xml b/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-04.xml
deleted file mode 100644
index 85613b5..0000000
--- a/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-04.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-<!-- A fictitious state machine used by test cases.
-     Meant to illustrate the usage of SCXML <datamodel> element
-     to persist some _event.data -->
-<scxml xmlns="http://www.w3.org/2005/07/scxml"
-       version="1.0"
-       datamodel="jexl"
-       initial="ten">
-
-    <!-- Root or document datamodel -->
-    <datamodel>
-        <data id="payload"/>
-    </datamodel>
-
-    <state id="ten">
-        <transition event="done.state.ten" target="twenty">
-            <assign location="payload" expr="_event.data" />
-        </transition>
-    </state>
-
-    <state id="twenty">
-        <transition event="done.state.twenty" target="thirty" />
-        <onexit>
-            <log label="Persisted event.data.one" expr="payload.one"/>
-            <log label="Persisted event.data.two" expr="payload.two"/>
-        </onexit>
-    </state>
-
-    <final id="thirty"/>
-
-</scxml>
-

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-05.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-05.xml b/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-05.xml
index 05a1ee3..b1f0d94 100644
--- a/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-05.xml
+++ b/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-05.xml
@@ -24,44 +24,54 @@
     <datamodel>
 
       <data id="airline">
-        <flight xmlns="">
-          <origin/>
-          <destination/>
-          <trip>round</trip>
-          <class>economy</class>
-          <meal/>
-          <dates>
-            <startdate>01/01/2009</startdate>
-            <enddate>01/05/2009</enddate>
-          </dates>
-          <dates>
-            <startdate>01/26/2009</startdate>
-            <enddate>01/31/2009</enddate>
-          </dates>
-        </flight>
+        {
+          "flight" :
+          {
+            "origin" : null,
+            "destination" : null,
+            "trip" : "round",
+            "class" : "economy",
+            "meal" : null,
+            "dates" :
+            [
+              {
+                "startdate" : "01/01/2009",
+                "enddate" : "01/05/2009"
+              },
+              {
+                "startdate" : "01/26/2009",
+                "enddate" : "01/31/2009"
+              }
+            ]
+          }
+        }
       </data>
 
       <data id="hotel">
-        <hotel xmlns="">
-          <stay>
-            <delete>foo</delete>
-          </stay>
-          <adults>1</adults>
-          <children>0</children>
-          <rooms>1</rooms>
-          <rate/>
-        </hotel>
+        {
+          "hotel" :
+          {
+            "stay" :
+            {
+              "delete" : "foo"
+            },
+            "adults" : 1,
+            "children" : 0,
+            "rooms" : 1,
+            "rate" : null
+          }
+        }
       </data>
 
     </datamodel>
 
     <state id="start">
         <onentry>
-            <log label="XML subtree copy - delete (should be foo)" expr="Data('string($hotel/hotel/stay/delete)')"/>
-            <assign location="Location('$hotel/hotel/stay')" expr="Data('$airline/flight/dates[2]/*')"/>
-            <log label="XML subtree copy - delete (should be empty)" expr="Data('string($hotel/hotel/stay/delete)')"/>
+            <log label="subtree copy - delete (should be foo)" expr="hotel.hotel.stay['delete']"/>
+            <assign location="hotel.hotel.stay" expr="airline.flight.dates[1]"/>
+            <log label="subtree copy - delete (should be null)" expr="hotel.hotel.stay['delete']"/>
         </onentry>
-        <transition cond="Data('string($hotel/hotel/stay/startdate)') eq '01/26/2009'" target="end" />
+        <transition cond="hotel.hotel.stay.startdate eq '01/26/2009'" target="end" />
     </state>
 
     <final id="end"/>

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/jexl/eventdata-03.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/env/jexl/eventdata-03.xml b/src/test/java/org/apache/commons/scxml2/env/jexl/eventdata-03.xml
index f7bbb30..118bb1a 100644
--- a/src/test/java/org/apache/commons/scxml2/env/jexl/eventdata-03.xml
+++ b/src/test/java/org/apache/commons/scxml2/env/jexl/eventdata-03.xml
@@ -22,12 +22,7 @@
        initial="ten">
 
     <datamodel>
-        <data id="rootdata">
-            <root xmlns="">
-                <one>1</one>
-                <two>2</two>
-            </root>
-        </data>
+        <data id="rootdata">{ "root" : { "one" : 1, "two" : 2 } }</data>
     </datamodel>
 
     <state id="ten">
@@ -36,8 +31,8 @@
 
     <state id="twenty">
         <onentry>
-            <cs:var name="one" expr="Data('number($rootdata/root/one)')"/>
-            <cs:var name="two" expr="Data('number($rootdata/root/two)')"/>
+            <cs:var name="one" expr="rootdata.root.one"/>
+            <cs:var name="two" expr="rootdata.root.two"/>
             <send event="event.bar" namelist="one two"/>
         </onentry>
         <transition event="event.bar"

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/invoke/InvokeParamNameTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/invoke/InvokeParamNameTest.java b/src/test/java/org/apache/commons/scxml2/invoke/InvokeParamNameTest.java
index f6ea857..a3809d2 100644
--- a/src/test/java/org/apache/commons/scxml2/invoke/InvokeParamNameTest.java
+++ b/src/test/java/org/apache/commons/scxml2/invoke/InvokeParamNameTest.java
@@ -27,8 +27,6 @@ import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
 
 // Tests for 4.3.1 in WD-scxml-20080516
 public class InvokeParamNameTest {
@@ -68,15 +66,14 @@ public class InvokeParamNameTest {
         Assert.assertEquals("foo", e.getValue());
     }
 
-    // Tests "param" element with a "name" attribute and "expr" attribute locating a node
+    // Tests "param" element with a "name" attribute and "expr" attribute locating a data id
     @Test
     public void testSoleNameLocation() throws Exception {
         trigger(); trigger();
-        final Element e = (Element)lastParams.values().iterator().next();
-        Assert.assertNotNull(e);
-        Assert.assertEquals("bar", e.getNodeName());
-        Assert.assertEquals(Node.TEXT_NODE, e.getFirstChild().getNodeType());
-        Assert.assertEquals("foo", e.getFirstChild().getNodeValue());
+        final Map m = (Map)lastParams.values().iterator().next();
+        Assert.assertNotNull(m);
+        Assert.assertEquals("bar", m.keySet().iterator().next());
+        Assert.assertEquals("foo", m.get("bar"));
     }
 
     public static class DummyInvoker implements Invoker {

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/invoke/invoker-04.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/invoke/invoker-04.xml b/src/test/java/org/apache/commons/scxml2/invoke/invoker-04.xml
index e68d567..37be004 100644
--- a/src/test/java/org/apache/commons/scxml2/invoke/invoker-04.xml
+++ b/src/test/java/org/apache/commons/scxml2/invoke/invoker-04.xml
@@ -25,9 +25,7 @@
        initial="wait">
 
     <datamodel>
-        <data id="foo">
-            <bar>foo</bar>
-        </data>
+        <data id="foo">{ "bar" : "foo"}</data>
     </datamodel>
 
     <state id="wait">
@@ -36,14 +34,14 @@
     
     <state id="first">
         <invoke src="FirstTestSrc" type="x-test">
-            <param name="ding" expr="Data('string($foo)')"/>
+            <param name="ding" expr="foo.bar"/>
         </invoke>
         <transition event="test.trigger" target="second"/>
     </state>
 
     <state id="second">
         <invoke src="SecondTestSrc" type="x-test">
-            <param name="dang" expr="Data('$foo/node()')"/>
+            <param name="dang" expr="foo"/>
         </invoke>
     </state>
 </scxml>

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/io/ContentParserTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/io/ContentParserTest.java b/src/test/java/org/apache/commons/scxml2/io/ContentParserTest.java
new file mode 100644
index 0000000..5ded49c
--- /dev/null
+++ b/src/test/java/org/apache/commons/scxml2/io/ContentParserTest.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.scxml2.io;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ContentParserTest {
+
+    @Test
+    public void testTrimContent() throws Exception {
+        Assert.assertEquals(null, ContentParser.trimContent(null));
+        Assert.assertEquals("", ContentParser.trimContent(""));
+        Assert.assertEquals("", ContentParser.trimContent(" "));
+        Assert.assertEquals("", ContentParser.trimContent("  "));
+        Assert.assertEquals("", ContentParser.trimContent("   "));
+        Assert.assertEquals("", ContentParser.trimContent("\t\n\r"));
+        Assert.assertEquals("a", ContentParser.trimContent("a"));
+        Assert.assertEquals("a", ContentParser.trimContent(" a"));
+        Assert.assertEquals("a", ContentParser.trimContent("a "));
+        Assert.assertEquals("a", ContentParser.trimContent(" a "));
+    }
+
+    @Test
+    public void testSpaceNormalizeContent() throws Exception {
+        Assert.assertEquals(null, ContentParser.spaceNormalizeContent(null));
+        Assert.assertEquals("", ContentParser.spaceNormalizeContent(""));
+        Assert.assertEquals("a", ContentParser.spaceNormalizeContent("a"));
+        Assert.assertEquals("a", ContentParser.spaceNormalizeContent(" a"));
+        Assert.assertEquals("a", ContentParser.spaceNormalizeContent("a "));
+        Assert.assertEquals("a", ContentParser.spaceNormalizeContent(" a "));
+        Assert.assertEquals("a b c", ContentParser.spaceNormalizeContent("  a\tb \n \r c  "));
+    }
+
+    @Test
+    public void testParseJson() throws Exception {
+        ObjectMapper jsonObjectMapper = new ObjectMapper();
+        jsonObjectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
+        jsonObjectMapper.configure(JsonParser.Feature.ALLOW_YAML_COMMENTS, true);
+        // not by default configured, but much easier for unit-testing Java embedded JSON Strings
+        jsonObjectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
+
+        ContentParser contentParser = new ContentParser(jsonObjectMapper);
+
+        String jsonObjectString = "{ /*comment*/ 'string' : 'foobar', 'int' : 1, 'boolean' : false, 'null' : null }";
+        LinkedHashMap<String, Object> jsonObject = new LinkedHashMap<>();
+        jsonObject.put("string", "foobar");
+        jsonObject.put("int",new Integer(1));
+        jsonObject.put("boolean", Boolean.FALSE);
+        jsonObject.put("null", null);
+        Assert.assertEquals(jsonObject, contentParser.parseJson(jsonObjectString));
+
+        String jsonArrayString = "[" + jsonObjectString + "," + "# yaml comment\n" + jsonObjectString+"]";
+        ArrayList<Object> jsonArray = new ArrayList<>(2);
+        jsonArray.add(jsonObject);
+        jsonArray.add(jsonObject);
+        Assert.assertEquals(jsonArray, contentParser.parseJson(jsonArrayString));
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/model/DatamodelTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/DatamodelTest.java b/src/test/java/org/apache/commons/scxml2/model/DatamodelTest.java
index bc6b0f3..5d8b8f1 100644
--- a/src/test/java/org/apache/commons/scxml2/model/DatamodelTest.java
+++ b/src/test/java/org/apache/commons/scxml2/model/DatamodelTest.java
@@ -31,7 +31,7 @@ import org.junit.Test;
 public class DatamodelTest {
 
     /**
-     * Test the stateless model, simultaneous executions
+     * Test the stateless model (jexl), simultaneous executions
      */    
     @Test
     public void testDatamodelSimultaneousJexl() throws Exception {
@@ -42,38 +42,33 @@ public class DatamodelTest {
         Assert.assertFalse(exec01 == exec02);
         runtest(exec01, exec02);
     }
-    
+
+    /**
+     * Test the stateless model (Groovy), simultaneous executions
+     */
     @Test
-    public void testDatamodelNamespacePrefixedXPaths() throws Exception {
-        SCXMLExecutor exec01 = SCXMLTestHelper.getExecutor("org/apache/commons/scxml2/env/jexl/datamodel-02.xml");
+    public void testDatamodelSimultaneousGroovy() throws Exception {
+        SCXMLExecutor exec01 = SCXMLTestHelper.getExecutor("org/apache/commons/scxml2/env/groovy/datamodel-01.xml");
         exec01.go();
-        SCXMLExecutor exec02 = SCXMLTestHelper.getExecutor("org/apache/commons/scxml2/env/jexl/datamodel-02.xml");
+        SCXMLExecutor exec02 = SCXMLTestHelper.getExecutor("org/apache/commons/scxml2/env/groovy/datamodel-01.xml");
         exec02.go();
         Assert.assertFalse(exec01 == exec02);
         runtest(exec01, exec02);
     }
-    
+
+    /**
+     * Test the stateless model (Javascript), simultaneous executions
+     */
     @Test
-    public void testDatamodel04Jexl() throws Exception {
-        SCXMLExecutor exec01 = SCXMLTestHelper.getExecutor("org/apache/commons/scxml2/env/jexl/datamodel-04.xml");
+    public void testDatamodelSimultaneousJavascript() throws Exception {
+        SCXMLExecutor exec01 = SCXMLTestHelper.getExecutor("org/apache/commons/scxml2/env/javascript/datamodel-01.xml");
         exec01.go();
-        Set<EnterableState> currentStates = exec01.getStatus().getStates();
-        Assert.assertEquals(1, currentStates.size());
-        Assert.assertEquals("ten", currentStates.iterator().next().getId());
-        Map<String, Object> payload = new HashMap<String, Object>();
-        payload.put("one", "1");
-        payload.put("two", "2");
-        TriggerEvent te = new TriggerEvent("done.state.ten", TriggerEvent.SIGNAL_EVENT, payload);
-        SCXMLTestHelper.fireEvent(exec01, te);
-        currentStates = exec01.getStatus().getStates();
-        Assert.assertEquals(1, currentStates.size());
-        Assert.assertEquals("twenty", currentStates.iterator().next().getId());
-        SCXMLTestHelper.fireEvent(exec01, "done.state.twenty");
-        currentStates = exec01.getStatus().getStates();
-        Assert.assertEquals(1, currentStates.size());
-        Assert.assertEquals("thirty", currentStates.iterator().next().getId());
+        SCXMLExecutor exec02 = SCXMLTestHelper.getExecutor("org/apache/commons/scxml2/env/javascript/datamodel-01.xml");
+        exec02.go();
+        Assert.assertFalse(exec01 == exec02);
+        runtest(exec01, exec02);
     }
-    
+
     @Test
     public void testDatamodel05Jexl() throws Exception {
         SCXMLExecutor exec01 = SCXMLTestHelper.getExecutor("org/apache/commons/scxml2/env/jexl/datamodel-05.xml");
@@ -81,6 +76,20 @@ public class DatamodelTest {
         SCXMLTestHelper.assertState(exec01, "end");
     }
 
+    @Test
+    public void testDatamodel05Groovy() throws Exception {
+        SCXMLExecutor exec01 = SCXMLTestHelper.getExecutor("org/apache/commons/scxml2/env/groovy/datamodel-05.xml");
+        exec01.go();
+        SCXMLTestHelper.assertState(exec01, "end");
+    }
+
+    @Test
+    public void testDatamodel05Javascript() throws Exception {
+        SCXMLExecutor exec01 = SCXMLTestHelper.getExecutor("org/apache/commons/scxml2/env/javascript/datamodel-05.xml");
+        exec01.go();
+        SCXMLTestHelper.assertState(exec01, "end");
+    }
+
     private void runtest(SCXMLExecutor exec01, SCXMLExecutor exec02) throws Exception {
         //// Interleaved
         // exec01

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/model/ParallelTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/ParallelTest.java b/src/test/java/org/apache/commons/scxml2/model/ParallelTest.java
index ec3a914..020784b 100644
--- a/src/test/java/org/apache/commons/scxml2/model/ParallelTest.java
+++ b/src/test/java/org/apache/commons/scxml2/model/ParallelTest.java
@@ -43,13 +43,13 @@ public class ParallelTest {
         SCXMLExecutor exec = SCXMLTestHelper.getExecutor("org/apache/commons/scxml2/model/parallel-03.xml");
         exec.go();
         SCXMLTestHelper.assertPostTriggerStates(exec, "dummy.event", new String[] { "para11", "para21" });
-        Object count = exec.getEvaluator().eval(exec.getGlobalContext(),"Data('string(root/root/count)')");
-        Assert.assertEquals("5.0", count.toString());
-        SCXMLTestHelper.assertPostTriggerStates(exec, "foo", new String[] { "para12", "para21" });
-        count = exec.getEvaluator().eval(exec.getGlobalContext(),"Data('string(root/root/count)')");
-        Assert.assertEquals("7.0", count.toString());
+        Object count = exec.getEvaluator().eval(exec.getGlobalContext(),"root.root.count");
+        Assert.assertEquals(5, count);
+        SCXMLTestHelper.assertPostTriggerStates(exec, "foo", new String[]{"para12", "para21"});
+        count = exec.getEvaluator().eval(exec.getGlobalContext(),"root.root.count");
+        Assert.assertEquals(7, count);
         SCXMLTestHelper.assertPostTriggerState(exec, "bar", "end");
-        count = exec.getEvaluator().eval(exec.getGlobalContext(),"Data('string(root/root/count)')");
-        Assert.assertEquals("14.0", count.toString());
+        count = exec.getEvaluator().eval(exec.getGlobalContext(),"root.root.count");
+        Assert.assertEquals(14, count);
     }
 }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/model/SendTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/SendTest.java b/src/test/java/org/apache/commons/scxml2/model/SendTest.java
index 92ee6a8..2c1e5b7 100644
--- a/src/test/java/org/apache/commons/scxml2/model/SendTest.java
+++ b/src/test/java/org/apache/commons/scxml2/model/SendTest.java
@@ -52,8 +52,8 @@ public class SendTest {
         Map<String, Object> firstPayload = (Map<String, Object>) payloads.get(0);
         Assert.assertEquals("Only two in the namelist data expected.", 2, firstPayload.size());
 
-        Assert.assertEquals("Unexpected value for 'one'.", 1.0, firstPayload.get("one"));
-        Assert.assertEquals("Unexpected value for 'two'.", 2.0, firstPayload.get("two"));
+        Assert.assertEquals("Unexpected value for 'one'.", 1, firstPayload.get("one"));
+        Assert.assertEquals("Unexpected value for 'two'.", 2, firstPayload.get("two"));
 
         // Note: the standard allows specifying the value of the namelist attribute of the <send> element
         // as space-separated list of values, which implies an ordered sequence of items.

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/model/assign-src.json
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/assign-src.json b/src/test/java/org/apache/commons/scxml2/model/assign-src.json
new file mode 100644
index 0000000..ec27830
--- /dev/null
+++ b/src/test/java/org/apache/commons/scxml2/model/assign-src.json
@@ -0,0 +1,25 @@
+{
+  /*
+   * Licensed to the Apache Software Foundation (ASF) under one or more
+   * contributor license agreements.  See the NOTICE file distributed with
+   * this work for additional information regarding copyright ownership.
+   * The ASF licenses this file to You under the Apache License, Version 2.0
+   * (the "License"); you may not use this file except in compliance with
+   * the License.  You may obtain a copy of the License at
+   *
+   *     http://www.apache.org/licenses/LICENSE-2.0
+   *
+   * Unless required by applicable law or agreed to in writing, software
+   * distributed under the License is distributed on an "AS IS" BASIS,
+   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   * See the License for the specific language governing permissions and
+   * limitations under the License.
+   */
+
+  // Used in test of "src" attribute of assign element
+
+  "root" :
+  {
+    "a" : 10
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/model/assign-src.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/assign-src.xml b/src/test/java/org/apache/commons/scxml2/model/assign-src.xml
deleted file mode 100644
index cd3a214..0000000
--- a/src/test/java/org/apache/commons/scxml2/model/assign-src.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-<!-- Used in test of "src" attribute of assign element -->
-<root xmlns="">
-    <a>10</a>
-</root>

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/model/assign-test-01.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/assign-test-01.xml b/src/test/java/org/apache/commons/scxml2/model/assign-test-01.xml
index 31888ec..41ffb0e 100644
--- a/src/test/java/org/apache/commons/scxml2/model/assign-test-01.xml
+++ b/src/test/java/org/apache/commons/scxml2/model/assign-test-01.xml
@@ -17,7 +17,6 @@
 -->
 <!-- Test "src" attribute of assign element -->
 <scxml xmlns="http://www.w3.org/2005/07/scxml"
-       xmlns:rad="http://foo/bar"
        version="1.0"
        datamodel="jexl"
        initial="assign1">
@@ -25,23 +24,15 @@
   <state id="assign1">
 
     <datamodel>
-        <data id="foo">
-            <root xmlns="">
-                <foo/>
-            </root>
-        </data>
-        <data id="bar">
-            <root xmlns="">
-                <bar>5</bar>
-            </root>
-        </data>
+        <data id="foo">{ "root" : { "foo" : null } }</data>
+        <data id="bar">{ "root" : { "bar" : 5 } }</data>
     </datamodel>
 
     <onentry>
-        <assign location="Location('foo/root/foo')" src="assign-src.xml"/>
+        <assign location="foo.root.foo" src="assign-src.json"/>
     </onentry>
 
-    <transition cond="Data('number(foo/root/foo/root/a)') + Data('number(bar/root/bar)') eq 15"
+    <transition cond="foo.root.foo.root.a + bar.root.bar eq 15"
                 target="assign2" />
 
   </state>
@@ -49,19 +40,15 @@
   <state id="assign2">
 
     <datamodel>
-      <data id="jira51data1">
-          <rad:timeout>10</rad:timeout>
-      </data> 
-      <data id="jira51data2">
-          <rad:short xmlns="">20</rad:short>
-      </data>
+      <data id="jira51data1">{ "timeout" : 10 }</data>
+      <data id="jira51data2">{ "short" : 20 }</data>
     </datamodel>
 
     <onentry>
-        <assign location="Location('jira51data1/rad:timeout')" expr="Data('jira51data2/rad:short/text()')"/>
+        <assign location="jira51data1.timeout" expr="jira51data2.short"/>
     </onentry>
 
-    <transition cond="Data('number(jira51data1/rad:timeout)') eq 20"
+    <transition cond="jira51data1.timeout eq 20"
                 target="assign3" />
 
   </state>

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/model/assign-test-02.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/assign-test-02.xml b/src/test/java/org/apache/commons/scxml2/model/assign-test-02.xml
index d72dd81..b382e9b 100644
--- a/src/test/java/org/apache/commons/scxml2/model/assign-test-02.xml
+++ b/src/test/java/org/apache/commons/scxml2/model/assign-test-02.xml
@@ -15,32 +15,21 @@
    * See the License for the specific language governing permissions and
    * limitations under the License.
 -->
-<!-- Regress JIRA 89, incomplete child removal -->
-<scxml xmlns="http://www.w3.org/2005/07/scxml" xmlns:rad="http://foo/bar" version="1.0"  datamodel="jexl" initial="assign1">
+<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0"  datamodel="jexl" initial="assign1">
    <datamodel>
-       <data id="source">
-           <rad:foo>
-               <rad:a>1</rad:a>
-               <rad:b>2</rad:b>
-           </rad:foo>
-       </data>
-       <data id="destination">
-           <rad:bar>
-               <rad:a>3</rad:a>
-               <rad:b>4</rad:b>
-           </rad:bar>
-       </data>
+       <data id="source">{ "foo" : { "a" : 1, "b" : 2 } }</data>
+       <data id="destination">{ "bar" : { "a" : 3, "b" : 4 } }</data>
    </datamodel>
    <!-- verify the destination contents -->
    <state id="assign1">
-       <transition cond="Data('number(destination/rad:bar/rad:a)') eq 3 and Data('number(destination/rad:bar/rad:b)') eq 4" target="assign2" />
+       <transition cond="destination.bar.a eq 3 and destination.bar.b eq 4" target="assign2" />
    </state>
    <!-- copy the new contents and verify -->
    <state id="assign2">
        <onentry>
-           <assign location="Location('destination/rad:bar')" expr="Data('source/rad:foo/*')" />
+           <assign location="destination.bar" expr="source.foo" />
        </onentry>
-       <transition cond="Data('number(destination/rad:bar/rad:a)') eq 1 and Data('number(destination/rad:bar/rad:b)') eq 2" target="assign3" />
+       <transition cond="destination.bar.a eq 1 and destination.bar.b eq 2" target="assign3" />
    </state>
    <final id="assign3"/>
 </scxml>

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/model/cancel-test-01.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/cancel-test-01.xml b/src/test/java/org/apache/commons/scxml2/model/cancel-test-01.xml
index 2829d87..54c4bbb 100644
--- a/src/test/java/org/apache/commons/scxml2/model/cancel-test-01.xml
+++ b/src/test/java/org/apache/commons/scxml2/model/cancel-test-01.xml
@@ -22,12 +22,7 @@
        initial="ten">
 
     <datamodel>
-        <data id="rootdata">
-            <root xmlns="">
-                <one>1</one>
-                <two>2</two>
-            </root>
-        </data>
+        <data id="rootdata">{ "root" : { "one" : 1, "two" : 2 } }</data>
     </datamodel>
 
     <state id="ten">
@@ -35,8 +30,8 @@
         <transition event="event.foo" target="twenty" />
 
         <onexit>
-            <cs:var name="one" expr="Data('number($rootdata/root/one)')" />
-            <cs:var name="two" expr="Data('number($rootdata/root/two)')" />
+            <cs:var name="one" expr="rootdata.root.one" />
+            <cs:var name="two" expr="rootdata.root.two" />
             <send id="send123" event="event.bar" namelist="one two" delay="1500" />
         </onexit>
 

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/model/cancel-test-02.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/cancel-test-02.xml b/src/test/java/org/apache/commons/scxml2/model/cancel-test-02.xml
index d87b694..ac1c0d8 100644
--- a/src/test/java/org/apache/commons/scxml2/model/cancel-test-02.xml
+++ b/src/test/java/org/apache/commons/scxml2/model/cancel-test-02.xml
@@ -22,12 +22,7 @@
        initial="ten">
 
     <datamodel>
-        <data id="rootdata">
-            <root xmlns="">
-                <one>1</one>
-                <two>2</two>
-            </root>
-        </data>
+        <data id="rootdata">{ "root" : { "one" : 1, "two" : 2 } }</data>
     </datamodel>
 
     <state id="ten">
@@ -35,8 +30,8 @@
         <transition event="event.foo" target="twenty" />
 
         <onexit>
-            <cs:var name="one" expr="Data('number($rootdata/root/one)')" />
-            <cs:var name="two" expr="Data('number($rootdata/root/two)')" />
+            <cs:var name="one" expr="rootdata.root.one" />
+            <cs:var name="two" expr="rootdata.root.two" />
             <send id="send123" event="event.bar" namelist="one two" delay="1500" />
         </onexit>
 

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/model/parallel-03.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/parallel-03.xml b/src/test/java/org/apache/commons/scxml2/model/parallel-03.xml
index 72194c1..94d7cfb 100644
--- a/src/test/java/org/apache/commons/scxml2/model/parallel-03.xml
+++ b/src/test/java/org/apache/commons/scxml2/model/parallel-03.xml
@@ -21,17 +21,13 @@
        initial="para">
 
     <datamodel>
-        <data id="root">
-            <root xmlns="">
-                <count>0</count>
-            </root>
-        </data>
+        <data id="root">{ "root" : { "count" : 0 } }</data>
     </datamodel>
 
     <parallel id="para">
 
         <onentry>
-            <assign location="Location('root/root/count')" expr="Data('number(root/root/count)') + 1"/>
+            <assign location="root.root.count" expr="root.root.count + 1"/>
         </onentry>
 
         <state id="para1">
@@ -40,30 +36,30 @@
                 <transition target="para11"/>
             </initial>
             <onentry>
-                <assign location="Location('root/root/count')" expr="Data('number(root/root/count)') + 1"/>
+                <assign location="root.root.count" expr="root.root.count + 1"/>
             </onentry>
 
             <state id="para11">
                 <onentry>
-                      <assign location="Location('root/root/count')" expr="Data('number(root/root/count)') + 1"/>
+                      <assign location="root.root.count" expr="root.root.count + 1"/>
                 </onentry>
                 <transition event="foo" target="para12"/>
                 <onexit>
-                      <assign location="Location('root/root/count')" expr="Data('number(root/root/count)') + 1"/>
+                      <assign location="root.root.count" expr="root.root.count + 1"/>
                 </onexit>
             </state>
 
             <final id="para12">
                 <onentry>
-                    <assign location="Location('root/root/count')" expr="Data('number(root/root/count)') + 1"/>
+                    <assign location="root.root.count" expr="root.root.count + 1"/>
                 </onentry>
                 <onexit>
-                    <assign location="Location('root/root/count')" expr="Data('number(root/root/count)') + 1"/>
+                    <assign location="root.root.count" expr="root.root.count + 1"/>
                 </onexit>
             </final>
 
             <onexit>
-                <assign location="Location('root/root/count')" expr="Data('number(root/root/count)') + 1"/>
+                <assign location="root.root.count" expr="root.root.count + 1"/>
             </onexit>
 
         </state>
@@ -74,30 +70,30 @@
                 <transition target="para21"/>
             </initial>
             <onentry>
-                <assign location="Location('root/root/count')" expr="Data('number(root/root/count)') + 1"/>
+                <assign location="root.root.count" expr="root.root.count + 1"/>
             </onentry>
 
             <state id="para21">
                 <onentry>
-                    <assign location="Location('root/root/count')" expr="Data('number(root/root/count)') + 1"/>
+                    <assign location="root.root.count" expr="root.root.count + 1"/>
                 </onentry>
                 <transition event="bar" target="para22"/>
                 <onexit>
-                    <assign location="Location('root/root/count')" expr="Data('number(root/root/count)') + 1"/>
+                    <assign location="root.root.count" expr="root.root.count + 1"/>
                 </onexit>
             </state>
 
             <final id="para22">
                 <onentry>
-                    <assign location="Location('root/root/count')" expr="Data('number(root/root/count)') + 1"/>
+                    <assign location="root.root.count" expr="root.root.count + 1"/>
                 </onentry>
                 <onexit>
-                    <assign location="Location('root/root/count')" expr="Data('number(root/root/count)') + 1"/>
+                    <assign location="root.root.count" expr="root.root.count + 1"/>
                 </onexit>
             </final>
 
             <onexit>
-                <assign location="Location('root/root/count')" expr="Data('number(root/root/count)') + 1"/>
+                <assign location="root.root.count" expr="root.root.count + 1"/>
             </onexit>
 
         </state>
@@ -105,7 +101,7 @@
         <transition event="done.state.para" target="end"/>
 
         <onexit>
-            <assign location="Location('root/root/count')" expr="Data('number(root/root/count)') + 1"/>
+            <assign location="root.root.count" expr="root.root.count + 1"/>
         </onexit>
 
     </parallel>

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/model/send-test-01.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/model/send-test-01.xml b/src/test/java/org/apache/commons/scxml2/model/send-test-01.xml
index f7bbb30..118bb1a 100644
--- a/src/test/java/org/apache/commons/scxml2/model/send-test-01.xml
+++ b/src/test/java/org/apache/commons/scxml2/model/send-test-01.xml
@@ -22,12 +22,7 @@
        initial="ten">
 
     <datamodel>
-        <data id="rootdata">
-            <root xmlns="">
-                <one>1</one>
-                <two>2</two>
-            </root>
-        </data>
+        <data id="rootdata">{ "root" : { "one" : 1, "two" : 2 } }</data>
     </datamodel>
 
     <state id="ten">
@@ -36,8 +31,8 @@
 
     <state id="twenty">
         <onentry>
-            <cs:var name="one" expr="Data('number($rootdata/root/one)')"/>
-            <cs:var name="two" expr="Data('number($rootdata/root/two)')"/>
+            <cs:var name="one" expr="rootdata.root.one"/>
+            <cs:var name="two" expr="rootdata.root.two"/>
             <send event="event.bar" namelist="one two"/>
         </onentry>
         <transition event="event.bar"


[2/2] commons-scxml git commit: SCXML-242: Providing JSON base datamodel as replacement for XML/XPath See: https://issues.apache.org/jira/browse/SCXML-242 - adding FasterXML Jackson as (default) json parser - adding new ContentParser to encapsulate Data

Posted by at...@apache.org.
SCXML-242: Providing JSON base datamodel as replacement for XML/XPath
See: https://issues.apache.org/jira/browse/SCXML-242
- adding FasterXML Jackson as (default) json parser
- adding new ContentParser to encapsulate Data (content) parsing logic
- adding new AbstractBaseEvaluator for common new cloneData method
- replace all XML based datamodel examples with JSON and dropping all Data() and Location() usages
- dropping Data() and Location() implementations and related XPathBuiltin for Jexl, Javascript and Groovy languages
- deleting no longer relevant XPath based unit-tests


Project: http://git-wip-us.apache.org/repos/asf/commons-scxml/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-scxml/commit/6af929eb
Tree: http://git-wip-us.apache.org/repos/asf/commons-scxml/tree/6af929eb
Diff: http://git-wip-us.apache.org/repos/asf/commons-scxml/diff/6af929eb

Branch: refs/heads/master
Commit: 6af929eb622b07742d4eeac3b754c60ad6a60a3d
Parents: 7b3a237
Author: Ate Douma <at...@apache.org>
Authored: Sat Dec 26 18:49:34 2015 +0100
Committer: Ate Douma <at...@apache.org>
Committed: Sat Dec 26 18:49:34 2015 +0100

----------------------------------------------------------------------
 pom.xml                                         |  22 +-
 .../org/apache/commons/scxml2/Evaluator.java    |   6 +
 .../org/apache/commons/scxml2/SCInstance.java   |  16 +-
 .../org/apache/commons/scxml2/XPathBuiltin.java |  93 -------
 .../scxml2/env/AbstractBaseEvaluator.java       |  82 ++++++
 .../scxml2/env/groovy/GroovyEvaluator.java      |  30 +--
 .../scxml2/env/groovy/GroovySCXMLScript.java    |  27 +-
 .../scxml2/env/javascript/JSEvaluator.java      |  78 +++---
 .../scxml2/env/javascript/JSFunctions.java      |  25 +-
 .../commons/scxml2/env/jexl/JexlBuiltin.java    |  25 +-
 .../commons/scxml2/env/jexl/JexlEvaluator.java  |  30 +--
 .../scxml2/env/minimal/MinimalEvaluator.java    |   5 +
 .../scxml2/env/xpath/XPathEvaluator.java        |   4 +-
 .../apache/commons/scxml2/io/ContentParser.java | 217 ++++++++++++++++
 .../apache/commons/scxml2/io/SCXMLReader.java   |  25 +-
 .../org/apache/commons/scxml2/model/Assign.java |  31 +--
 .../org/apache/commons/scxml2/model/Data.java   |  53 ++--
 .../scxml2/NamespacePrefixedXPathsTest.java     |  89 -------
 .../commons/scxml2/env/groovy/datamodel-01.xml  |  84 ++++++
 .../commons/scxml2/env/groovy/datamodel-05.xml  |  80 ++++++
 .../scxml2/env/javascript/JSEvaluatorTest.java  |  65 +++--
 .../scxml2/env/javascript/datamodel-01.xml      |  84 ++++++
 .../scxml2/env/javascript/datamodel-05.xml      |  80 ++++++
 .../scxml2/env/javascript/example-01.xml        |  39 +--
 .../commons/scxml2/env/jexl/datamodel-01.xml    |  56 +---
 .../commons/scxml2/env/jexl/datamodel-02.xml    |  90 -------
 .../commons/scxml2/env/jexl/datamodel-03.xml    | 255 -------------------
 .../commons/scxml2/env/jexl/datamodel-04.xml    |  48 ----
 .../commons/scxml2/env/jexl/datamodel-05.xml    |  66 +++--
 .../commons/scxml2/env/jexl/eventdata-03.xml    |  11 +-
 .../scxml2/invoke/InvokeParamNameTest.java      |  13 +-
 .../apache/commons/scxml2/invoke/invoker-04.xml |   8 +-
 .../commons/scxml2/io/ContentParserTest.java    |  79 ++++++
 .../commons/scxml2/model/DatamodelTest.java     |  57 +++--
 .../commons/scxml2/model/ParallelTest.java      |  14 +-
 .../apache/commons/scxml2/model/SendTest.java   |   4 +-
 .../apache/commons/scxml2/model/assign-src.json |  25 ++
 .../apache/commons/scxml2/model/assign-src.xml  |  21 --
 .../commons/scxml2/model/assign-test-01.xml     |  29 +--
 .../commons/scxml2/model/assign-test-02.xml     |  23 +-
 .../commons/scxml2/model/cancel-test-01.xml     |  11 +-
 .../commons/scxml2/model/cancel-test-02.xml     |  11 +-
 .../apache/commons/scxml2/model/parallel-03.xml |  34 ++-
 .../commons/scxml2/model/send-test-01.xml       |  11 +-
 44 files changed, 1085 insertions(+), 1071 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index e4cdb5f..fbe52ce 100644
--- a/pom.xml
+++ b/pom.xml
@@ -143,6 +143,21 @@
       <version>1.1.3</version>
     </dependency>
     <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-core</artifactId>
+      <version>2.6.4</version>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
+      <version>2.6.4</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <version>2.4</version>
+    </dependency>
+    <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <version>4.11</version>
@@ -170,12 +185,6 @@
       <artifactId>commons-beanutils</artifactId>
       <version>1.9.2</version>
     </dependency>
-    <dependency>
-      <groupId>commons-io</groupId>
-      <artifactId>commons-io</artifactId>
-      <version>2.4</version>
-      <scope>test</scope>
-    </dependency>
   </dependencies>
 
   <distributionManagement>
@@ -211,6 +220,7 @@
         <directory>src/test/java</directory>
         <includes>
           <include>**/*.xml</include>
+          <include>**/*.json</include>
           <include>**/*.xsl</include>
           <include>**/*.gif</include>
         </includes>

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/Evaluator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/Evaluator.java b/src/main/java/org/apache/commons/scxml2/Evaluator.java
index ae2e744..0d7cad7 100644
--- a/src/main/java/org/apache/commons/scxml2/Evaluator.java
+++ b/src/main/java/org/apache/commons/scxml2/Evaluator.java
@@ -76,6 +76,12 @@ public interface Evaluator {
     String getSupportedDatamodel();
 
     /**
+     * @param data data to be cloned
+     * @return A deep clone of the data
+     */
+    Object cloneData(Object data);
+
+    /**
      * Evaluate an expression returning a data value
      *
      * @param ctx variable context

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/SCInstance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/SCInstance.java b/src/main/java/org/apache/commons/scxml2/SCInstance.java
index 6b0e5b8..1260fa4 100644
--- a/src/main/java/org/apache/commons/scxml2/SCInstance.java
+++ b/src/main/java/org/apache/commons/scxml2/SCInstance.java
@@ -299,15 +299,14 @@ public class SCInstance implements Serializable {
                 // earlier or externally defined 'initial' value found: do not overwrite
                 continue;
             }
-            Node datumNode = datum.getNode();
-            Node valueNode = null;
-            if (datumNode != null) {
-                valueNode = datumNode.cloneNode(true);
-            }
+            /*
+            TODO: external data.src support (not yet implemented), including late-binding thereof
             // prefer "src" over "expr" over "inline"
             if (datum.getSrc() != null) {
                 ctx.setLocal(datum.getId(), valueNode);
-            } else if (datum.getExpr() != null) {
+            } else
+            */
+            if (datum.getExpr() != null) {
                 Object value;
                 try {
                     ctx.setLocal(Context.NAMESPACES_KEY, datum.getNamespaces());
@@ -345,8 +344,9 @@ public class SCInstance implements Serializable {
                 else {
                     ctx.setLocal(datum.getId(), value);
                 }
-            } else {
-                ctx.setLocal(datum.getId(), valueNode);
+            }
+            else {
+                ctx.setLocal(datum.getId(), evaluator.cloneData(datum.getValue()));
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/XPathBuiltin.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/XPathBuiltin.java b/src/main/java/org/apache/commons/scxml2/XPathBuiltin.java
deleted file mode 100644
index faba709..0000000
--- a/src/main/java/org/apache/commons/scxml2/XPathBuiltin.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.scxml2;
-
-import org.apache.commons.scxml2.env.xpath.XPathEvaluator;
-
-/**
- * Implementation and support of Commons SCXML builtin predicates to support XPath based datamodel operations
- * for non-XPath languages.
- *
- * These static builtin functions delegate to a static {@link }XPathEvaluator} instance.
- */
-public class XPathBuiltin {
-
-    private static XPathEvaluator evaluator = new XPathEvaluator();
-
-    /**
-     * Optional static setter to change and override the default {@link XPathEvaluator}
-     * @param evaluator A custom evaluator to be used
-     */
-    public static void setEvaluator(XPathEvaluator evaluator) {
-        XPathBuiltin.evaluator = evaluator;
-    }
-
-    /**
-     * Evaluate an xpath expression returning a data value
-     *
-     * @param ctx variable context
-     * @param expression xpath expression
-     * @return the result of the evaluation
-     * @throws SCXMLExpressionException A malformed expression exception
-     * @see Evaluator#eval(Context, String)
-     */
-    public static Object eval(Context ctx, String expression) throws SCXMLExpressionException {
-        return evaluator.eval(ctx, expression);
-    }
-
-    /**
-     * Evaluate an xpath location that returns a data assignable reference or list of references.
-     * Manifests as "location" attributes of &lt;assign&gt; element.
-     *
-     * @param ctx variable context
-     * @param expression expression
-     * @return The location result.
-     * @throws SCXMLExpressionException A malformed expression exception
-     * @see Evaluator#evalLocation(Context, String)
-     */
-    public static Object evalLocation(Context ctx, String expression) throws SCXMLExpressionException {
-        return evaluator.evalLocation(ctx, expression);
-    }
-
-    /**
-     * Determine if an {@link Evaluator#evalLocation(Context, String)} returned result represents an XPath location
-     * @param ctx variable context
-     * @param data result data from {@link Evaluator#evalLocation(Context, String)}
-     * @return true if the data represents an XPath location
-     * @see XPathEvaluator#isXPathLocation(Context, Object)
-     */
-    public static boolean isXPathLocation(Context ctx, Object data) {
-        return evaluator.isXPathLocation(ctx, data);
-    }
-
-    /**
-     * Assigns data to a location
-     *
-     * @param ctx variable context
-     * @param location location expression
-     * @param data the data to assign.
-     * @param type the type of assignment to perform, null assumes {@link Evaluator.AssignType#REPLACE_CHILDREN}
-     * @param attr the name of the attribute to add when using type {@link Evaluator.AssignType#ADD_ATTRIBUTE}
-     * @throws SCXMLExpressionException A malformed expression exception
-     * @see Evaluator#evalAssign(Context, String, Object, Evaluator.AssignType, String)
-     * @see XPathEvaluator#assign(Context, Object, Object, Evaluator.AssignType, String)
-     */
-    public static void assign(Context ctx, Object location, Object data, Evaluator.AssignType type, String attr)
-            throws SCXMLExpressionException {
-        evaluator.assign(ctx, location, data, type, attr);
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/AbstractBaseEvaluator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/AbstractBaseEvaluator.java b/src/main/java/org/apache/commons/scxml2/env/AbstractBaseEvaluator.java
new file mode 100644
index 0000000..abd96a4
--- /dev/null
+++ b/src/main/java/org/apache/commons/scxml2/env/AbstractBaseEvaluator.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.scxml2.env;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.scxml2.Evaluator;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Base Evaluator providing common functionality for most Evaluator implementations
+ */
+public abstract class AbstractBaseEvaluator implements Evaluator, Serializable {
+
+    @Override
+    public Object cloneData(final Object data) {
+        if (data != null) {
+            if (data instanceof String || data instanceof Number || data instanceof Boolean) {
+                return data;
+            }
+            if (data instanceof Node) {
+                return ((Node)data).cloneNode(true);
+            }
+            else if (data instanceof NodeList) {
+                NodeList nodeList = (NodeList)data;
+                ArrayList<Node> list = new ArrayList<>();
+                for (int i = 0, size = nodeList.getLength(); i < size; i++) {
+                    list.add(nodeList.item(i).cloneNode(true));
+                }
+                return list;
+            }
+            else if (data instanceof List) {
+                ArrayList<Object> list = new ArrayList<>();
+                for (Object v : (List)data) {
+                    list.add(cloneData(v));
+                }
+                return list;
+            }
+            else if (data instanceof Map) {
+                Map<?,?> dataMap = (Map<?,?>)data;
+                HashMap<Object, Object> map = new LinkedHashMap<>();
+                for (Map.Entry<?,?> entry : dataMap.entrySet()) {
+                    map.put(cloneData(entry.getKey()), cloneData(entry.getValue()));
+                }
+                return map;
+            }
+            else {
+                return cloneUnknownDataType(data);
+            }
+        }
+        return data;
+    }
+
+    /**
+     * Returns cloned value of data of unknown type, to be overridden as desired by specialized Evaluators
+     * @param data data object of unknown type (not of type String, Number, Boolean, Node, NodeList, List or Map)
+     * @return toString() value of data of unknown type
+     */
+    protected Object cloneUnknownDataType(final Object data) {
+        return data.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java b/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java
index f67e7d1..c82d2d7 100644
--- a/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java
+++ b/src/main/java/org/apache/commons/scxml2/env/groovy/GroovyEvaluator.java
@@ -18,7 +18,6 @@ package org.apache.commons.scxml2.env.groovy;
 
 import groovy.lang.Script;
 
-import java.io.Serializable;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -31,7 +30,7 @@ import org.apache.commons.scxml2.Evaluator;
 import org.apache.commons.scxml2.EvaluatorProvider;
 import org.apache.commons.scxml2.SCXMLExpressionException;
 import org.apache.commons.scxml2.SCXMLSystemContext;
-import org.apache.commons.scxml2.XPathBuiltin;
+import org.apache.commons.scxml2.env.AbstractBaseEvaluator;
 import org.apache.commons.scxml2.env.EffectiveContextMap;
 import org.apache.commons.scxml2.model.SCXML;
 
@@ -41,7 +40,7 @@ import org.apache.commons.scxml2.model.SCXML;
  * This implementation itself is thread-safe, so you can keep singleton for efficiency.
  * </P>
  */
-public class GroovyEvaluator implements Evaluator, Serializable {
+public class GroovyEvaluator extends AbstractBaseEvaluator {
 
     /** Serial version UID. */
     private static final long serialVersionUID = 1L;
@@ -256,26 +255,13 @@ public class GroovyEvaluator implements Evaluator, Serializable {
      */
     public void evalAssign(final Context ctx, final String location, final Object data, final AssignType type,
                            final String attr) throws SCXMLExpressionException {
-
-        final Object loc = evalLocation(ctx, location);
-        if (loc != null) {
-
-            if (XPathBuiltin.isXPathLocation(ctx, loc)) {
-                XPathBuiltin.assign(ctx, loc, data, type, attr);
-            }
-            else {
-                final StringBuilder sb = new StringBuilder(location).append("=").append(ASSIGN_VARIABLE_NAME);
-                try {
-                    ctx.getVars().put(ASSIGN_VARIABLE_NAME, data);
-                    eval(ctx, sb.toString());
-                }
-                finally {
-                    ctx.getVars().remove(ASSIGN_VARIABLE_NAME);
-                }
-            }
+        final StringBuilder sb = new StringBuilder(location).append("=").append(ASSIGN_VARIABLE_NAME);
+        try {
+            ctx.getVars().put(ASSIGN_VARIABLE_NAME, data);
+            eval(ctx, sb.toString());
         }
-        else {
-            throw new SCXMLExpressionException("evalAssign - cannot resolve location: '" + location + "'");
+        finally {
+            ctx.getVars().remove(ASSIGN_VARIABLE_NAME);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/groovy/GroovySCXMLScript.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/groovy/GroovySCXMLScript.java b/src/main/java/org/apache/commons/scxml2/env/groovy/GroovySCXMLScript.java
index 29407ef..5980211 100644
--- a/src/main/java/org/apache/commons/scxml2/env/groovy/GroovySCXMLScript.java
+++ b/src/main/java/org/apache/commons/scxml2/env/groovy/GroovySCXMLScript.java
@@ -25,13 +25,10 @@ import java.util.Collection;
 import java.util.Map;
 
 import org.apache.commons.scxml2.Builtin;
-import org.apache.commons.scxml2.SCXMLExpressionException;
-import org.apache.commons.scxml2.XPathBuiltin;
 
 /**
- * Groovy {@link Script} base class for SCXML, providing the standard 'builtin' functions {@link #In(String)},
- * {@link #Data(String)} and {@link #Location(String)}, as well as JEXL like convenience functions
- * {@link #empty(Object)} and {@link #var(String)}.
+ * Groovy {@link Script} base class for SCXML, providing the standard 'builtin' function {@link #In(String)},
+ * as well as JEXL like convenience functions {@link #empty(Object)} and {@link #var(String)}.
  */
 public abstract class GroovySCXMLScript extends Script {
 
@@ -59,26 +56,6 @@ public abstract class GroovySCXMLScript extends Script {
     }
 
     /**
-     * Implements the Data() predicate for SCXML documents.
-     * @param expression the XPath expression
-     * @return the data matching the expression
-     * @throws SCXMLExpressionException A malformed expression exception
-     */
-    public Object Data(final String expression) throws SCXMLExpressionException {
-        return XPathBuiltin.eval(context, expression);
-    }
-
-    /**
-     * Implements the Location() predicate for SCXML documents.
-     * @param location the XPath expression
-     * @return the location list for the location expression
-     * @throws SCXMLExpressionException A malformed expression exception
-     */
-    public Object Location(final String location) throws SCXMLExpressionException {
-        return XPathBuiltin.evalLocation(context, location);
-    }
-
-    /**
      * The var function can be used to check if a variable is defined,
      * <p>
      * In the Groovy language (implementation) you cannot check for an undefined variable directly:

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java b/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java
index 9fee8ea..ca0d8eb 100644
--- a/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java
+++ b/src/main/java/org/apache/commons/scxml2/env/javascript/JSEvaluator.java
@@ -29,23 +29,17 @@ import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.Evaluator;
 import org.apache.commons.scxml2.EvaluatorProvider;
 import org.apache.commons.scxml2.SCXMLExpressionException;
-import org.apache.commons.scxml2.XPathBuiltin;
+import org.apache.commons.scxml2.env.AbstractBaseEvaluator;
 import org.apache.commons.scxml2.env.EffectiveContextMap;
 import org.apache.commons.scxml2.model.SCXML;
 
 /**
  * Embedded JavaScript expression evaluator for SCXML expressions. This
  * implementation is a just a 'thin' wrapper around the Javascript engine in
- * JDK 6 (based on on Mozilla Rhino 1.6.2).
- * <p>
- * Mozilla Rhino 1.6.2 does not support E4X so accessing the SCXML data model
- * is implemented in the same way as the JEXL expression evaluator i.e. using
- * the Data() function, for example,
- * &lt;assign location="Data(hotelbooking,'hotel/rooms')" expr="2" /&gt;
- * </p>
+ * JDK 8.
  */
 
-public class JSEvaluator implements Evaluator {
+public class JSEvaluator extends AbstractBaseEvaluator {
 
     /**
      * Unique context variable name used for temporary reference to assign data (thus must be a valid variable name)
@@ -78,14 +72,10 @@ public class JSEvaluator implements Evaluator {
 
     /** Pattern for recognizing the SCXML In() special predicate. */
     private static final Pattern IN_FN = Pattern.compile("In\\(");
-    /** Pattern for recognizing the Commons SCXML Data() builtin function. */
-    private static final Pattern DATA_FN = Pattern.compile("Data\\(");
-    /** Pattern for recognizing the Commons SCXML Location() builtin function. */
-    private static final Pattern LOCATION_FN = Pattern.compile("Location\\(");
 
     // INSTANCE VARIABLES
 
-    private ScriptEngineManager factory;
+    private transient ScriptEngineManager factory;
 
     // CONSTRUCTORS
 
@@ -98,12 +88,32 @@ public class JSEvaluator implements Evaluator {
 
     // INSTANCE METHODS
 
+    protected ScriptEngineManager getFactory() {
+        if (factory == null) {
+            factory = new ScriptEngineManager();
+        }
+        return factory;
+    }
+
     @Override
     public String getSupportedDatamodel() {
         return SUPPORTED_DATA_MODEL;
     }
 
     /**
+     * @return Returns JavaScript "undefined" for null, otherwise inherited behavior
+     */
+    @Override
+    public Object cloneData(final Object data) {
+        if (data == null) {
+            ScriptEngine engine = getFactory().getEngineByName("JavaScript");
+            Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
+            return bindings.get("undefined");
+        }
+        return super.cloneData(data);
+    }
+
+    /**
      * Creates a child context.
      *
      * @return Returns a new child JSContext.
@@ -117,8 +127,8 @@ public class JSEvaluator implements Evaluator {
     /**
      * Evaluates the expression using a new Javascript engine obtained from
      * factory instantiated in the constructor. The engine is supplied with
-     * a new JSBindings that includes the SCXML Context and
-     * <code>Data()</code> functions are replaced with an equivalent internal
+     * a new JSBindings that includes the SCXML Context and SCXML builtin
+     * <code>In()</code> function is replaced with an equivalent internal
      * Javascript function.
      *
      * @param context    SCXML context.
@@ -142,13 +152,11 @@ public class JSEvaluator implements Evaluator {
             JSContext effectiveContext = getEffectiveContext((JSContext) context);
 
             // ... initialize
-            ScriptEngine engine = factory.getEngineByName("JavaScript");
+            ScriptEngine engine = getFactory().getEngineByName("JavaScript");
             Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
 
             // ... replace built-in functions
             String jsExpression = IN_FN.matcher(expression).replaceAll("_builtin.In(");
-            jsExpression = DATA_FN.matcher(jsExpression).replaceAll("_builtin.Data(");
-            jsExpression = LOCATION_FN.matcher(jsExpression).replaceAll("_builtin.Location(");
 
             // ... evaluate
             JSBindings jsBindings = new JSBindings(effectiveContext, bindings);
@@ -196,8 +204,8 @@ public class JSEvaluator implements Evaluator {
     /**
      * Evaluates a location expression using a new Javascript engine obtained from
      * factory instantiated in the constructor. The engine is supplied with
-     * a new JSBindings that includes the SCXML Context and
-     * <code>Data()</code> functions are replaced with an equivalent internal
+     * a new JSBindings that includes the SCXML Context and SCXML builtin
+     * <code>In()</code> function is replaced with an equivalent internal
      * Javascript function.
      *
      * @param context    FSM context.
@@ -221,32 +229,20 @@ public class JSEvaluator implements Evaluator {
      */
     public void evalAssign(final Context ctx, final String location, final Object data, final AssignType type,
                            final String attr) throws SCXMLExpressionException {
-
-        Object loc = evalLocation(ctx, location);
-
-        if (loc != null) {
-            if (XPathBuiltin.isXPathLocation(ctx, loc)) {
-                XPathBuiltin.assign(ctx, loc, data, type, attr);
-            } else {
-                StringBuilder sb = new StringBuilder(location).append("=").append(ASSIGN_VARIABLE_NAME);
-
-                try {
-                    ctx.getVars().put(ASSIGN_VARIABLE_NAME, data);
-                    eval(ctx, sb.toString());
-                } finally {
-                    ctx.getVars().remove(ASSIGN_VARIABLE_NAME);
-                }
-            }
-        } else {
-            throw new SCXMLExpressionException("evalAssign - cannot resolve location: '" + location + "'");
+        StringBuilder sb = new StringBuilder(location).append("=").append(ASSIGN_VARIABLE_NAME);
+        try {
+            ctx.getVars().put(ASSIGN_VARIABLE_NAME, data);
+            eval(ctx, sb.toString());
+        } finally {
+            ctx.getVars().remove(ASSIGN_VARIABLE_NAME);
         }
     }
 
     /**
      * Executes the script using a new Javascript engine obtained from
      * factory instantiated in the constructor. The engine is supplied with
-     * a new JSBindings that includes the SCXML Context and
-     * <code>Data()</code> functions are replaced with an equivalent internal
+     * a new JSBindings that includes the SCXML Context and SCXML builtin
+     * <code>In()</code> function is replaced with an equivalent internal
      * Javascript function.
      *
      * @param ctx    SCXML context.

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/javascript/JSFunctions.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/javascript/JSFunctions.java b/src/main/java/org/apache/commons/scxml2/env/javascript/JSFunctions.java
index bf99ee7..45771a0 100644
--- a/src/main/java/org/apache/commons/scxml2/env/javascript/JSFunctions.java
+++ b/src/main/java/org/apache/commons/scxml2/env/javascript/JSFunctions.java
@@ -20,12 +20,9 @@ import java.io.Serializable;
 
 import org.apache.commons.scxml2.Builtin;
 import org.apache.commons.scxml2.Context;
-import org.apache.commons.scxml2.SCXMLExpressionException;
-import org.apache.commons.scxml2.XPathBuiltin;
 
 /**
- * Custom Javascript engine function providing the SCXML In() predicate and the Commons SCXML extensions
- * for Data() and Location() to support XPath datamodel access.
+ * Custom Javascript engine function providing the SCXML In() predicate .
  */
 public class JSFunctions implements Serializable {
 
@@ -50,24 +47,4 @@ public class JSFunctions implements Serializable {
     public boolean In(final String state) {
         return Builtin.isMember(ctx, state);
     }
-
-    /**
-     * Provides the Commons SCXML Data() predicate extension for SCXML documents.
-     * @param expression the XPath expression
-     * @return the data matching the expression
-     * @throws SCXMLExpressionException A malformed expression exception
-     */
-    public Object Data(String expression) throws SCXMLExpressionException {
-        return XPathBuiltin.eval(ctx, expression);
-    }
-
-    /**
-     * Provides the Commons SCXML Location() predicate extension for SCXML documents.
-     * @param expression the XPath expression
-     * @return the location matching the expression
-     * @throws SCXMLExpressionException A malformed expression exception
-     */
-    public Object Location(String expression) throws SCXMLExpressionException {
-        return XPathBuiltin.evalLocation(ctx, expression);
-    }
 }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java b/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java
index b1ece86..cddd0f5 100644
--- a/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java
+++ b/src/main/java/org/apache/commons/scxml2/env/jexl/JexlBuiltin.java
@@ -17,12 +17,9 @@
 package org.apache.commons.scxml2.env.jexl;
 
 import org.apache.commons.scxml2.Builtin;
-import org.apache.commons.scxml2.SCXMLExpressionException;
-import org.apache.commons.scxml2.XPathBuiltin;
 
 /**
- * Global JEXL namespace functor, providing the standard SCXML In() operator and the Commons SCXML extensions
- * for Data() and Location() to support XPath datamodel access.
+ * Global JEXL namespace functor, providing the standard SCXML In() predicate.
  */
 public final class JexlBuiltin {
     /**
@@ -46,24 +43,4 @@ public final class JexlBuiltin {
     public boolean In(final String state) {
         return Builtin.isMember(context, state);
     }
-
-    /**
-     * Provides the Commons SCXML Data() predicate extension for SCXML documents.
-     * @param expression the XPath expression
-     * @return the data matching the expression
-     * @throws SCXMLExpressionException A malformed expression exception
-     */
-    public Object Data(final String expression) throws SCXMLExpressionException {
-        return XPathBuiltin.eval(context, expression);
-    }
-
-    /**
-     * Provides the Commons SCXML Location() predicate extension for SCXML documents.
-     * @param expression the XPath expression
-     * @return the location matching the expression
-     * @throws SCXMLExpressionException A malformed expression exception
-     */
-    public Object Location(final String expression) throws SCXMLExpressionException {
-        return XPathBuiltin.evalLocation(context, expression);
-    }
 }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java b/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java
index 3dd0088..d08946c 100644
--- a/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java
+++ b/src/main/java/org/apache/commons/scxml2/env/jexl/JexlEvaluator.java
@@ -16,7 +16,6 @@
  */
 package org.apache.commons.scxml2.env.jexl;
 
-import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
@@ -28,7 +27,7 @@ import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.Evaluator;
 import org.apache.commons.scxml2.EvaluatorProvider;
 import org.apache.commons.scxml2.SCXMLExpressionException;
-import org.apache.commons.scxml2.XPathBuiltin;
+import org.apache.commons.scxml2.env.AbstractBaseEvaluator;
 import org.apache.commons.scxml2.env.EffectiveContextMap;
 import org.apache.commons.scxml2.model.SCXML;
 
@@ -40,7 +39,7 @@ import org.apache.commons.scxml2.model.SCXML;
  * for efficiency of the internal <code>JexlEngine</code> member.
  * </P>
  */
-public class JexlEvaluator implements Evaluator, Serializable {
+public class JexlEvaluator extends AbstractBaseEvaluator {
 
     /** Serial version UID. */
     private static final long serialVersionUID = 1L;
@@ -222,26 +221,13 @@ public class JexlEvaluator implements Evaluator, Serializable {
      */
     public void evalAssign(final Context ctx, final String location, final Object data, final AssignType type,
                            final String attr) throws SCXMLExpressionException {
-
-        Object loc = evalLocation(ctx, location);
-        if (loc != null) {
-
-            if (XPathBuiltin.isXPathLocation(ctx, loc)) {
-                XPathBuiltin.assign(ctx, loc, data, type, attr);
-            }
-            else {
-                StringBuilder sb = new StringBuilder(location).append("=").append(ASSIGN_VARIABLE_NAME);
-                try {
-                    ctx.getVars().put(ASSIGN_VARIABLE_NAME, data);
-                    eval(ctx, sb.toString());
-                }
-                finally {
-                    ctx.getVars().remove(ASSIGN_VARIABLE_NAME);
-                }
-            }
+        StringBuilder sb = new StringBuilder(location).append("=").append(ASSIGN_VARIABLE_NAME);
+        try {
+            ctx.getVars().put(ASSIGN_VARIABLE_NAME, data);
+            eval(ctx, sb.toString());
         }
-        else {
-            throw new SCXMLExpressionException("evalAssign - cannot resolve location: '" + location + "'");
+        finally {
+            ctx.getVars().remove(ASSIGN_VARIABLE_NAME);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/minimal/MinimalEvaluator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/minimal/MinimalEvaluator.java b/src/main/java/org/apache/commons/scxml2/env/minimal/MinimalEvaluator.java
index 401df4e..66c18e5 100644
--- a/src/main/java/org/apache/commons/scxml2/env/minimal/MinimalEvaluator.java
+++ b/src/main/java/org/apache/commons/scxml2/env/minimal/MinimalEvaluator.java
@@ -62,6 +62,11 @@ public class MinimalEvaluator implements Evaluator, Serializable {
     }
 
     @Override
+    public Object cloneData(final Object data) {
+        return data;
+    }
+
+    @Override
     public Object eval(final Context ctx, final String expr) throws SCXMLExpressionException {
         return expr;
     }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/env/xpath/XPathEvaluator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/env/xpath/XPathEvaluator.java b/src/main/java/org/apache/commons/scxml2/env/xpath/XPathEvaluator.java
index 763f090..0da7103 100644
--- a/src/main/java/org/apache/commons/scxml2/env/xpath/XPathEvaluator.java
+++ b/src/main/java/org/apache/commons/scxml2/env/xpath/XPathEvaluator.java
@@ -16,7 +16,6 @@
  */
 package org.apache.commons.scxml2.env.xpath;
 
-import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -34,6 +33,7 @@ import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.Evaluator;
 import org.apache.commons.scxml2.EvaluatorProvider;
 import org.apache.commons.scxml2.SCXMLExpressionException;
+import org.apache.commons.scxml2.env.AbstractBaseEvaluator;
 import org.apache.commons.scxml2.env.EffectiveContextMap;
 import org.apache.commons.scxml2.model.SCXML;
 import org.w3c.dom.Attr;
@@ -48,7 +48,7 @@ import org.w3c.dom.NodeList;
  * <p>Does not support the &lt;script&gt; module, throws
  * {@link UnsupportedOperationException} if attempted.</p>
  */
-public class XPathEvaluator implements Evaluator, Serializable {
+public class XPathEvaluator extends AbstractBaseEvaluator {
 
     /** Serial version UID. */
     private static final long serialVersionUID = -3578920670869493294L;

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/io/ContentParser.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/io/ContentParser.java b/src/main/java/org/apache/commons/scxml2/io/ContentParser.java
new file mode 100644
index 0000000..eb044eb
--- /dev/null
+++ b/src/main/java/org/apache/commons/scxml2/io/ContentParser.java
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.scxml2.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.apache.commons.io.IOUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
+
+/**
+ * The ContentParser provides utility methods for cleaning content strings and parsing them into "raw" content model Objects
+ */
+public class ContentParser {
+
+    public static final ContentParser DEFAULT_PARSER = new ContentParser();
+
+    /**
+     * Jackson JSON ObjectMapper
+     */
+    private ObjectMapper jsonObjectMapper;
+
+    /**
+     * Default constructor initializing a Jackson ObjectMapper allowing embedded comments, including YAML style
+     */
+    public ContentParser() {
+        this.jsonObjectMapper = new ObjectMapper();
+        jsonObjectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
+        jsonObjectMapper.configure(JsonParser.Feature.ALLOW_YAML_COMMENTS, true);
+    }
+
+    /**
+     * Constructor with a custom configured Jackson ObjectMapper
+     * @param jsonObjectMapper custom configured Jackson ObjectMapper
+     */
+    public ContentParser(final ObjectMapper jsonObjectMapper) {
+        this.jsonObjectMapper = jsonObjectMapper;
+    }
+
+    /**
+     * Trim pre/post-fixed whitespace from content string
+     * @param content content to trim
+     * @return trimmed content
+     */
+    public static String trimContent(final String content) {
+        if (content != null) {
+            int start = 0;
+            int length = content.length();
+            while (start < length && isWhiteSpace(content.charAt(start))) {
+                start++;
+            }
+            while (length > start && isWhiteSpace(content.charAt(length - 1))) {
+                length--;
+            }
+            if (start == length) {
+                return "";
+            }
+            return content.substring(start, length);
+        }
+        return null;
+    }
+
+    /**
+     * Space normalize content string, trimming pre/post-fixed whitespace and collapsing embedded whitespaces to
+     * single space.
+     * @param content content to space-normalize
+     * @return space-normalized content
+     */
+    public static String spaceNormalizeContent(final String content) {
+        if (content != null) {
+            int index = 0;
+            int length = content.length();
+            StringBuilder buffer = new StringBuilder(length);
+            boolean whiteSpace = false;
+            while (index < length) {
+                if (isWhiteSpace(content.charAt(index))) {
+                    if (!whiteSpace && buffer.length() > 0) {
+                        buffer.append(' ');
+                        whiteSpace = true;
+                    }
+                }
+                else {
+                    buffer.append(content.charAt(index));
+                    whiteSpace = false;
+                }
+                index++;
+            }
+            if (whiteSpace) {
+                buffer.setLength(buffer.length()-1);
+            }
+            return buffer.toString();
+        }
+        return null;
+    }
+
+    /**
+     * Check if a character is whitespace (space, tab, newline, cr) or not
+     * @param c character to check
+     * @return true if character is whitespace
+     */
+    public static boolean isWhiteSpace(final char c) {
+        return c==' ' || c=='\n' || c=='\t' || c=='\r';
+    }
+
+    /**
+     * Check if content starts with JSON object '{' or array '[' marker
+     * @param content text to check
+     * @return true if content start with '{' or '[' character
+     */
+    public static boolean hasJsonSignature(final String content) {
+        final char c = content.length() > 0 ? content.charAt(0) : 0;
+        return c == '{' || c == '[';
+    }
+
+    /**
+     * Check if content indicates its an XML document
+     * @param content content to check
+     * @return true if content indicates its an XML document
+     */
+    public static boolean hasXmlSignature(final String content) {
+        return content != null && content.startsWith("<?xml ");
+    }
+
+    /**
+     * Parse and map JSON string to 'raw' Java Objects: object -> LinkedHashMap, array -> ArrayList
+     * @param jsonString JSON string to parse
+     * @return 'raw' mapped Java Object for JSON string
+     * @throws IOException In case of parsing exceptions
+     */
+    public Object parseJson(final String jsonString) throws IOException {
+        return jsonObjectMapper.readValue(jsonString, Object.class);
+    }
+
+    /**
+     * Parse an XML String and return the document element
+     * @param xmlString XML String to parse
+     * @return document element
+     * @throws IOException
+     */
+    public Node parseXml(final String xmlString) throws IOException {
+        Document doc = null;
+        try {
+            doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlString);
+        } catch (SAXException e) {
+            throw new IOException(e);
+        } catch (ParserConfigurationException e) {
+            throw new IOException(e);
+        }
+        return doc != null ? doc.getDocumentElement() : null;
+    }
+
+    /**
+     * Parse a string into a content object, following the SCXML rules as specified for the ECMAscript (section B.2.1) Data Model
+     * <ul>
+     *   <li>if the content can be interpreted as JSON, it will be parsed as JSON into an 'raw' object model</li>
+     *   <li>if the content can be interpreted as XML, it will be parsed into a XML DOM element</li>
+     *   <li>otherwise the content will be treated (cleaned) as a space-normalized string literal</li>
+     * </ul>
+     * @param content the content to parse
+     * @return the parsed content object
+     * @throws IOException In case of parsing exceptions
+     */
+    public Object parseContent(final String content) throws IOException {
+        if (content != null) {
+            String src = trimContent(content);
+            if (hasJsonSignature(src)) {
+                return parseJson(src);
+            }
+            else if (hasXmlSignature(src)) {
+                return parseXml(src);
+            }
+            return spaceNormalizeContent(src);
+        }
+        return null;
+    }
+
+    /**
+     * Load a resource (URL) as an UTF-8 encoded content string to be parsed into a content object through {@link #parseContent(String)}
+     * @param resourceURL Resource URL to load content from
+     * @return the parsed content object
+     * @throws IOException In case of loading or parsing exceptions
+     */
+    public Object parseResource(final String resourceURL) throws IOException {
+        InputStream in = null;
+        try {
+            in = new URL(resourceURL).openStream();
+            String content = IOUtils.toString(in, "UTF-8");
+            return parseContent(content);
+        }
+        finally {
+            IOUtils.closeQuietly(in);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java b/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java
index d4d2715..2bb0a0e 100644
--- a/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java
+++ b/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java
@@ -1096,7 +1096,27 @@ public final class SCXMLReader {
         datum.setId(readRequiredAV(reader, ELEM_DATA, ATTR_ID));
         datum.setExpr(readAV(reader, ATTR_EXPR));
         readNamespaces(configuration, datum);
-        datum.setNode(readNode(reader, configuration, XMLNS_SCXML, ELEM_DATA, new String[]{"id"}));
+        Node node = readNode(reader, configuration, XMLNS_SCXML, ELEM_DATA, new String[]{"id"});
+        datum.setNode(node);
+        if (node.hasChildNodes()) {
+            NodeList children = node.getChildNodes();
+            if (children.getLength() == 1 && children.item(0).getNodeType() == Node.TEXT_NODE) {
+                String text = configuration.contentParser.trimContent(children.item(0).getNodeValue());
+                if (configuration.contentParser.hasJsonSignature(text)) {
+                    try {
+                        datum.setValue(configuration.contentParser.parseJson(text));
+                    } catch (IOException e) {
+                        throw new ModelException(e);
+                    }
+                }
+                else {
+                    datum.setValue(configuration.contentParser.spaceNormalizeContent(text));
+                }
+            }
+        }
+        if (datum.getValue() == null) {
+            datum.setValue(node);
+        }
         dm.addData(datum);
     }
 
@@ -2700,6 +2720,8 @@ public final class SCXMLReader {
          */
         boolean strict;
 
+        ContentParser contentParser;
+
         /*
          * Public constructors
          */
@@ -2872,6 +2894,7 @@ public final class SCXMLReader {
             this.namespaces = new HashMap<String, Stack<String>>();
             this.silent = silent;
             this.strict = strict;
+            this.contentParser = new ContentParser();
         }
 
         /*

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/model/Assign.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/model/Assign.java b/src/main/java/org/apache/commons/scxml2/model/Assign.java
index 172aa85..6d07b3e 100644
--- a/src/main/java/org/apache/commons/scxml2/model/Assign.java
+++ b/src/main/java/org/apache/commons/scxml2/model/Assign.java
@@ -17,19 +17,13 @@
 package org.apache.commons.scxml2.model;
 
 import java.io.IOException;
-
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.FactoryConfigurationError;
-import javax.xml.parsers.ParserConfigurationException;
-
 import org.apache.commons.logging.LogFactory;
 import org.apache.commons.scxml2.ActionExecutionContext;
 import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.Evaluator;
 import org.apache.commons.scxml2.PathResolver;
 import org.apache.commons.scxml2.SCXMLExpressionException;
-import org.w3c.dom.*;
-import org.xml.sax.SAXException;
+import org.apache.commons.scxml2.io.ContentParser;
 
 /**
  * The class in this SCXML object model that corresponds to the
@@ -180,7 +174,7 @@ public class Assign extends Action implements PathResolverHolder {
         ctx.setLocal(getNamespacesKey(), getNamespaces());
         Object data;
         if (src != null && src.trim().length() > 0) {
-            data = getSrcNode();
+            data = getSrcData();
         } else {
             data = evaluator.eval(ctx, expr);
         }
@@ -192,41 +186,28 @@ public class Assign extends Action implements PathResolverHolder {
         // TODO: introduce a optional 'trace.change' setting or something alike to enable .change events,
        //        but don't do this by default as it can interfere with transitions not expecting such events
         /*
-        if ((Evaluator.XPATH_DATA_MODEL.equals(evaluator.getSupportedDatamodel()) && location.startsWith("$") && ctx.has(location.substring(1))
-                || ctx.has(location))) {
             TriggerEvent ev = new TriggerEvent(location + ".change", TriggerEvent.CHANGE_EVENT);
             exctx.getInternalIOProcessor().addEvent(ev);
-        }
         */
         ctx.setLocal(getNamespacesKey(), null);
     }
 
     /**
-     * Get the {@link Node} the "src" attribute points to.
+     * Get the data the "src" attribute points to.
      *
-     * @return The node the "src" attribute points to.
+     * @return The data the "src" attribute points to.
      */
-    private Node getSrcNode() {
+    private Object getSrcData() {
         String resolvedSrc = src;
         if (pathResolver != null) {
             resolvedSrc = pathResolver.resolvePath(src);
         }
-        Document doc = null;
         try {
-            doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(resolvedSrc);
-        } catch (FactoryConfigurationError t) {
-            logError(t);
-        } catch (SAXException e) {
-            logError(e);
+            return ContentParser.DEFAULT_PARSER.parseResource(resolvedSrc);
         } catch (IOException e) {
             logError(e);
-        } catch (ParserConfigurationException e) {
-            logError(e);
-        }
-        if (doc == null) {
             return null;
         }
-        return doc.getDocumentElement();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/main/java/org/apache/commons/scxml2/model/Data.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/model/Data.java b/src/main/java/org/apache/commons/scxml2/model/Data.java
index be5efd0..0771bf5 100644
--- a/src/main/java/org/apache/commons/scxml2/model/Data.java
+++ b/src/main/java/org/apache/commons/scxml2/model/Data.java
@@ -40,7 +40,7 @@ public class Data implements NamespacePrefixesHolder, Serializable {
     private String id;
 
     /**
-     * The URL to get the XML data tree from.
+     * The URL to get the data from.
      */
     private String src;
 
@@ -50,12 +50,17 @@ public class Data implements NamespacePrefixesHolder, Serializable {
     private String expr;
 
     /**
-     * The child XML data tree, parsed as a Node, cloned per execution
+     * The child XML data tree, parsed as a Node
      * instance.
      */
     private Node node;
 
     /**
+     * The parsed value for the child XML data tree or the external src (with early-binding), to be cloned before usage
+     */
+    private Object value;
+
+    /**
      * The current XML namespaces in the SCXML document for this action node,
      * preserved for deferred XPath evaluation. Easier than to scrape node
      * above, given the Builtin API.
@@ -63,16 +68,6 @@ public class Data implements NamespacePrefixesHolder, Serializable {
     private Map<String, String> namespaces;
 
     /**
-     * Constructor.
-     */
-    public Data() {
-        this.id = null;
-        this.src = null;
-        this.expr = null;
-        this.node = null;
-    }
-
-    /**
      * Get the id.
      *
      * @return String An identifier.
@@ -91,7 +86,7 @@ public class Data implements NamespacePrefixesHolder, Serializable {
     }
 
     /**
-     * Get the URL where the XML data tree resides.
+     * Get the URL for external data.
      *
      * @return String The URL.
      */
@@ -100,7 +95,7 @@ public class Data implements NamespacePrefixesHolder, Serializable {
     }
 
     /**
-     * Set the URL where the XML data tree resides.
+     * Set the URL for external data.
      *
      * @param src The source URL.
      */
@@ -127,24 +122,46 @@ public class Data implements NamespacePrefixesHolder, Serializable {
     }
 
     /**
-     * Get the XML data tree.
+     * Get the child XML data tree.
      *
-     * @return Node The XML data tree, parsed as a <code>Node</code>.
+     * @return Node The child XML data tree, parsed as a standalone DocumentFragment <code>Node</code>.
      */
     public final Node getNode() {
         return node;
     }
 
     /**
-     * Set the XML data tree.
+     * Set the child XML data tree.
      *
-     * @param node The XML data tree, parsed as a <code>Node</code>.
+     * @param node The child XML data tree, parsed as a standalone DocumentFragment <code>Node</code>.
      */
     public final void setNode(final Node node) {
         this.node = node;
     }
 
     /**
+     * Get the parsed value for the child XML data tree or the external src (with early-binding), to be cloned before usage.
+     * @see #setValue(Object)
+     * @return The parsed Data value
+     */
+    public final Object getValue() {
+        return value;
+    }
+
+    /**
+     * Sets the parsed value for the child XML data tree or the external src (with early-binding), to be cloned before usage.
+     * @param value a serializable object:
+     * <ul>
+     *   <li>"Raw" JSON mapped object tree (array->ArrayList, object->LinkedHashMap based)</li>
+     *   <li>XML Node (equals {@link #getNode()})</li>
+     *   <li>space-normalized String</li>
+     * </ul>
+     */
+    public final void setValue(final Object value) {
+        this.value = value;
+    }
+
+    /**
      * Get the XML namespaces at this action node in the SCXML document.
      *
      * @return Returns the map of namespaces.

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/NamespacePrefixedXPathsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/NamespacePrefixedXPathsTest.java b/src/test/java/org/apache/commons/scxml2/NamespacePrefixedXPathsTest.java
deleted file mode 100644
index c0164b4..0000000
--- a/src/test/java/org/apache/commons/scxml2/NamespacePrefixedXPathsTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.scxml2;
-
-import java.util.Set;
-
-import org.apache.commons.scxml2.model.EnterableState;
-import org.junit.Assert;
-import org.junit.Test;
-
-/**
- * Unit tests for namespace prefixes in XPaths pointing bits in a &lt;data&gt;.
- */
-public class NamespacePrefixedXPathsTest {
-
-    /**
-     * Test the XPath evaluation
-     */
-    // JEXL
-    @Test
-    public void testNamespacePrefixedXPathsJexl() throws Exception {
-        SCXMLExecutor exec = SCXMLTestHelper.getExecutor("org/apache/commons/scxml2/env/jexl/datamodel-03.xml");
-        exec.go();
-        runtest(exec);
-    }
-
-    // Same test, since same documents (different expression languages)
-    private void runtest(SCXMLExecutor exec) throws Exception {
-        // must be in state "ten" at the onset
-        Set<EnterableState> currentStates = exec.getStatus().getStates();
-        Assert.assertEquals(1, currentStates.size());
-        Assert.assertEquals("ten", currentStates.iterator().next().getId());
-
-        // should move to "twenty"
-        currentStates = SCXMLTestHelper.fireEvent(exec, "done.state.ten");
-        Assert.assertEquals(1, currentStates.size());
-        Assert.assertEquals("twenty", currentStates.iterator().next().getId());
-
-        // This is set while exiting "ten"
-        Double retval = (Double) exec.getGlobalContext().get("retval");
-        Assert.assertEquals(Double.valueOf("11"), retval);
-
-        // On to "thirty"
-        currentStates = SCXMLTestHelper.fireEvent(exec, "done.state.twenty");
-        Assert.assertEquals(1, currentStates.size());
-        Assert.assertEquals("thirty", currentStates.iterator().next().getId());
-        exec = SCXMLTestHelper.testInstanceSerializability(exec);
-
-        // Tests XPath on SCXML actions, set while exiting "twenty"
-        String retvalstr = (String) exec.getGlobalContext().get("retval");
-        Assert.assertEquals("Equal to 20", retvalstr);
-
-        // and so on ...
-        currentStates = SCXMLTestHelper.fireEvent(exec, "done.state.thirty");
-        Assert.assertEquals(1, currentStates.size());
-        Assert.assertEquals("forty", currentStates.iterator().next().getId());
-
-        currentStates = SCXMLTestHelper.fireEvent(exec, "done.state.forty");
-        Assert.assertEquals(1, currentStates.size());
-        Assert.assertEquals("fifty", currentStates.iterator().next().getId());
-
-        currentStates = SCXMLTestHelper.fireEvent(exec, "done.state.fifty");
-        Assert.assertEquals(1, currentStates.size());
-        Assert.assertEquals("sixty", (currentStates.iterator().
-            next()).getId());
-
-        currentStates = SCXMLTestHelper.fireEvent(exec, "done.state.sixty");
-        Assert.assertEquals(1, currentStates.size());
-        Assert.assertEquals("seventy", currentStates.iterator().next().getId());
-
-        // done
-        Assert.assertTrue(exec.getStatus().isFinal());
-    }
-}
-

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/groovy/datamodel-01.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/env/groovy/datamodel-01.xml b/src/test/java/org/apache/commons/scxml2/env/groovy/datamodel-01.xml
new file mode 100644
index 0000000..4edc4df
--- /dev/null
+++ b/src/test/java/org/apache/commons/scxml2/env/groovy/datamodel-01.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- A fictitious state machine used by test cases.
+     Meant to illustrate the usage of SCXML <datamodel> element -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+       version="1.0"
+       datamodel="groovy"
+       initial="main">
+
+    <!-- Root or document datamodel -->
+    <datamodel>
+        <data id="docdata">{ "root" : { "foo" : { "bar" : "alpha" } } }</data>
+    </datamodel>
+
+    <state id="main">
+
+        <initial>
+            <transition target="ten"/>
+        </initial>
+
+        <!-- datamodel scoped to state "main" -->
+        <datamodel>
+            <!-- Degenerate usage, similar to the <var> element -->
+            <data id="mainvar" expr="0" />
+            <!-- Usage where the value is an JSON model -->
+            <data id="maindata">{ "root" : { "a" : { "b" : { "c" : "beta", "d" : 123, "e" : 456.789 } } } }</data>
+        </datamodel>
+
+        <state id="ten">
+            <onentry>
+                <assign location="mainvar" expr="10" />
+            </onentry>
+            <transition event="done.state.ten"
+             cond="mainvar eq 10 and maindata.root.a.b.c eq 'beta'"
+             target="twenty" />
+            <onexit>
+                <assign location="maindata.root.a.b.c" expr="'gamma'" />
+            </onexit>
+        </state>
+
+        <state id="twenty">
+            <onentry>
+                <assign location="mainvar" expr="20" />
+            </onentry>
+            <transition event="done.state.twenty"
+             cond="maindata.root.a.b.c eq 'gamma' and mainvar eq 20"
+             target="thirty" />
+            <onexit>
+                <assign location="docdata.root.foo"
+                        expr="maindata.root" />
+            </onexit>
+        </state>
+
+        <state id="thirty">
+            <!-- Arithmetic operations.
+                 Note that data "docdata"
+                 did not have data at 'root.foo.a.b.d' to begin with,
+                 the data model was manipulated by the <assign> above -->
+            <transition event="done.state.thirty"
+             cond="docdata.root.foo.a.b.d + docdata.root.foo.a.b.e eq 579.789"
+             target="forty" />
+        </state>
+
+        <final id="forty"/>
+
+    </state>
+
+</scxml>
+

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/groovy/datamodel-05.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/env/groovy/datamodel-05.xml b/src/test/java/org/apache/commons/scxml2/env/groovy/datamodel-05.xml
new file mode 100644
index 0000000..55f5b9e
--- /dev/null
+++ b/src/test/java/org/apache/commons/scxml2/env/groovy/datamodel-05.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- A fictitious state machine used by test cases. -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+       version="1.0"
+       datamodel="groovy"
+       initial="start">
+
+    <datamodel>
+
+      <data id="airline">
+        {
+          "flight" :
+          {
+            "origin" : null,
+            "destination" : null,
+            "trip" : "round",
+            "class" : "economy",
+            "meal" : null,
+            "dates" :
+            [
+              {
+                "startdate" : "01/01/2009",
+                "enddate" : "01/05/2009"
+              },
+              {
+                "startdate" : "01/26/2009",
+                "enddate" : "01/31/2009"
+              }
+            ]
+          }
+        }
+      </data>
+
+      <data id="hotel">
+        {
+          "hotel" :
+          {
+            "stay" :
+            {
+              "delete" : "foo"
+            },
+            "adults" : 1,
+            "children" : 0,
+            "rooms" : 1,
+            "rate" : null
+          }
+        }
+      </data>
+
+    </datamodel>
+
+    <state id="start">
+        <onentry>
+            <log label="subtree copy - delete (should be foo)" expr="hotel.hotel.stay['delete']"/>
+            <assign location="hotel.hotel.stay" expr="airline.flight.dates[1]"/>
+            <log label="subtree copy - delete (should be null)" expr="hotel.hotel.stay['delete']"/>
+        </onentry>
+        <transition cond="hotel.hotel.stay.startdate eq '01/26/2009'" target="end" />
+    </state>
+
+    <final id="end"/>
+
+</scxml>
+

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/javascript/JSEvaluatorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/env/javascript/JSEvaluatorTest.java b/src/test/java/org/apache/commons/scxml2/env/javascript/JSEvaluatorTest.java
index 28d923e..2f8b403 100644
--- a/src/test/java/org/apache/commons/scxml2/env/javascript/JSEvaluatorTest.java
+++ b/src/test/java/org/apache/commons/scxml2/env/javascript/JSEvaluatorTest.java
@@ -18,6 +18,7 @@
 package org.apache.commons.scxml2.env.javascript;
 
 import java.io.StringReader;
+import java.util.Map;
 
 import javax.xml.xpath.XPath;
 import javax.xml.xpath.XPathConstants;
@@ -52,25 +53,25 @@ public class JSEvaluatorTest {
 
     private static final String BAD_EXPRESSION = ">";
     private static final String SCRIPT         = "<?xml version='1.0'?>" +
-                                                 "<scxml xmlns        = 'http://www.w3.org/2005/07/scxml' " +
-                                                        "xmlns:scxml  = 'http://commons.apache.org/scxml' " +
-                                                        "datamodel = 'ecmascript' " +
-                                                        "initial = 'start' "  +
-                                                        "version      = '1.0'>" +
-                                                  "<datamodel>"           +
-                                                  "<data id='forest'>"  +
-                                                   "<tree xmlns=''>"      +
-                                                   "<branch>"             +
-                                                   "<twig>leaf</twig>"    +
-                                                   "</branch>"            +
-                                                   "</tree>"              +
-                                                  "</data>"               +
-                                                  "</datamodel>"          +
-                                                  "<state id='start'>"              +
-                                                  "<transition target='end' />"     +
-                                                  "</state>"                        +
-                                                  "<state id='end' final='true' />" +
-                                                  "</scxml>";
+                                                 "<scxml xmlns = 'http://www.w3.org/2005/07/scxml'" +
+                                                 "       xmlns:scxml = 'http://commons.apache.org/scxml'" +
+                                                 "       datamodel = 'ecmascript'" +
+                                                 "       initial = 'start'"  +
+                                                 "       version = '1.0'>" +
+                                                 "  <datamodel>" +
+                                                 "    <data id='forest'>" +
+                                                 "      { \"tree\" :" +
+                                                 "        { \"branch\" :" +
+                                                 "          { \"twig\" : \"leaf\" }" +
+                                                 "        }" +
+                                                 "      }" +
+                                                 "    </data>" +
+                                                 "  </datamodel>" +
+                                                 "  <state id='start'>" +
+                                                 "    <transition target='end'/>" +
+                                                 "  </state>" +
+                                                 "  <state id='end' final='true'/>" +
+                                                 "</scxml>";
 
     private static final TestItem[] SIMPLE_EXPRESSIONS = {
             new TestItem("'FIB: ' + (1 + 1 + 2 + 3 + 5)",new String("FIB: 12")),
@@ -241,9 +242,9 @@ public class JSEvaluatorTest {
      */    
     @Test
     public void testDataModelExpressions() throws Exception {
-        Assert.assertEquals("Invalid result: " + "Data('string($forest/tree/branch/twig)')",
+        Assert.assertEquals("Invalid result: " + "forest.tree.branch.twig",
                      "leaf",
-                     evaluator.eval(context,"Data('string($forest/tree/branch/twig)')"));
+                     evaluator.eval(context,"forest.tree.branch.twig"));
     }
 
     /**
@@ -255,8 +256,8 @@ public class JSEvaluatorTest {
         Assert.assertNull(context.get("forestx"));
 
         try {
-            evaluator.eval(context,"Data(forestx,'string($forestx/tree/branch/twig)')");
-            Assert.fail          ("Evaluated invalid Data() expression: " + "Data('string($forestx/tree/branch/twig)')");
+            evaluator.eval(context,"forestx.tree.branch.twig");
+            Assert.fail          ("Evaluated invalid DataModel expression: " + "forestx.tree.branch.twig");
 
         } catch (SCXMLExpressionException x) {
             // expected, ignore
@@ -269,17 +270,11 @@ public class JSEvaluatorTest {
      */    
     @Test
     public void testDataModelLocations() throws Exception {
-            Assert.assertNotNull(context.get("forest"));
-            XPath  xpath = XPathFactory.newInstance().newXPath();
-            Node   node  = (Node)   context.get("forest");
-            Node   twig  = (Node)   xpath.evaluate("tree/branch/twig", node, XPathConstants.NODE);
-
-            Assert.assertTrue  ("Invalid result: " + "Data(forest,'$forest/tree/branch/twig')",
-                          evaluator.eval(context,"Data('$forest/tree/branch/twig')") instanceof Element);
+        Assert.assertTrue("Invalid result: forest instanceof Map",
+                evaluator.eval(context, "forest") instanceof Map);
 
-            Assert.assertSame ("Incorrect node returned: " + "Data('$forest/tree/branch/twig')",
-                         twig,
-                         evaluator.eval(context,"Data('$forest/tree/branch/twig')"));
+        Assert.assertTrue("Invalid result: forest.tree.branch.twig instanceof String",
+                evaluator.eval(context, "forest.tree.branch.twig") instanceof String);
     }
 
     /**
@@ -289,8 +284,8 @@ public class JSEvaluatorTest {
     @Test
     public void testInvalidDataModelLocations() throws Exception {
             Assert.assertNotNull(context.get("forest"));
-            Assert.assertNull("Invalid result: " + "Data('$forest/tree/branch/twigx')",
-                       evaluator.eval(context,"Data('$forest/tree/branch/twigx')"));
+            Assert.assertNull("Invalid result: " + "forest.tree.branch.twigx",
+                       evaluator.eval(context,"forest.tree.branch.twigx"));
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/javascript/datamodel-01.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/env/javascript/datamodel-01.xml b/src/test/java/org/apache/commons/scxml2/env/javascript/datamodel-01.xml
new file mode 100644
index 0000000..3234099
--- /dev/null
+++ b/src/test/java/org/apache/commons/scxml2/env/javascript/datamodel-01.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- A fictitious state machine used by test cases.
+     Meant to illustrate the usage of SCXML <datamodel> element -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+       version="1.0"
+       datamodel="ecmascript"
+       initial="main">
+
+    <!-- Root or document datamodel -->
+    <datamodel>
+        <data id="docdata">{ "root" : { "foo" : { "bar" : "alpha" } } }</data>
+    </datamodel>
+
+    <state id="main">
+
+        <initial>
+            <transition target="ten"/>
+        </initial>
+
+        <!-- datamodel scoped to state "main" -->
+        <datamodel>
+            <!-- Degenerate usage, similar to the <var> element -->
+            <data id="mainvar" expr="0" />
+            <!-- Usage where the value is an JSON model -->
+            <data id="maindata">{ "root" : { "a" : { "b" : { "c" : "beta", "d" : 123, "e" : 456.789 } } } }</data>
+        </datamodel>
+
+        <state id="ten">
+            <onentry>
+                <assign location="mainvar" expr="10" />
+            </onentry>
+            <transition event="done.state.ten"
+             cond="mainvar == 10 &amp;&amp; maindata.root.a.b.c == 'beta'"
+             target="twenty" />
+            <onexit>
+                <assign location="maindata.root.a.b.c" expr="'gamma'" />
+            </onexit>
+        </state>
+
+        <state id="twenty">
+            <onentry>
+                <assign location="mainvar" expr="20" />
+            </onentry>
+            <transition event="done.state.twenty"
+             cond="maindata.root.a.b.c == 'gamma' &amp;&amp; mainvar == 20"
+             target="thirty" />
+            <onexit>
+                <assign location="docdata.root.foo"
+                        expr="maindata.root" />
+            </onexit>
+        </state>
+
+        <state id="thirty">
+            <!-- Arithmetic operations.
+                 Note that data "docdata"
+                 did not have data at 'root.foo.a.b.d' to begin with,
+                 the data model was manipulated by the <assign> above -->
+            <transition event="done.state.thirty"
+             cond="docdata.root.foo.a.b.d + docdata.root.foo.a.b.e == 579.789"
+             target="forty" />
+        </state>
+
+        <final id="forty"/>
+
+    </state>
+
+</scxml>
+

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/javascript/datamodel-05.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/env/javascript/datamodel-05.xml b/src/test/java/org/apache/commons/scxml2/env/javascript/datamodel-05.xml
new file mode 100644
index 0000000..75817f0
--- /dev/null
+++ b/src/test/java/org/apache/commons/scxml2/env/javascript/datamodel-05.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<!-- A fictitious state machine used by test cases. -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+       version="1.0"
+       datamodel="ecmascript"
+       initial="start">
+
+    <datamodel>
+
+      <data id="airline">
+        {
+          "flight" :
+          {
+            "origin" : null,
+            "destination" : null,
+            "trip" : "round",
+            "class" : "economy",
+            "meal" : null,
+            "dates" :
+            [
+              {
+                "startdate" : "01/01/2009",
+                "enddate" : "01/05/2009"
+              },
+              {
+                "startdate" : "01/26/2009",
+                "enddate" : "01/31/2009"
+              }
+            ]
+          }
+        }
+      </data>
+
+      <data id="hotel">
+        {
+          "hotel" :
+          {
+            "stay" :
+            {
+              "delete" : "foo"
+            },
+            "adults" : 1,
+            "children" : 0,
+            "rooms" : 1,
+            "rate" : null
+          }
+        }
+      </data>
+
+    </datamodel>
+
+    <state id="start">
+        <onentry>
+            <log label="subtree copy - delete (should be foo)" expr="hotel.hotel.stay['delete']"/>
+            <assign location="hotel.hotel.stay" expr="airline.flight.dates[1]"/>
+            <log label="subtree copy - delete (should be null)" expr="hotel.hotel.stay['delete']"/>
+        </onentry>
+        <transition cond="hotel.hotel.stay.startdate == '01/26/2009'" target="end" />
+    </state>
+
+    <final id="end"/>
+
+</scxml>
+

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/javascript/example-01.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/env/javascript/example-01.xml b/src/test/java/org/apache/commons/scxml2/env/javascript/example-01.xml
index 5fbd7a7..72898d5 100644
--- a/src/test/java/org/apache/commons/scxml2/env/javascript/example-01.xml
+++ b/src/test/java/org/apache/commons/scxml2/env/javascript/example-01.xml
@@ -27,16 +27,21 @@
 
   <datamodel>
     <data id='jungle'>
-      <animals xmlns=''>
-        <lion>
-          <name>Simba</name>
-          <age>12</age>
-        </lion>
-        <tiger>
-          <name>Sher Khan</name>
-          <age>13</age>
-        </tiger>
-      </animals>
+      {
+        "animals" :
+        {
+          "lion" :
+          {
+            "name" : "Simba",
+            "age" : 12
+          },
+          "tiger" :
+          {
+            "name" : "Sher Khan",
+            "age" : 13
+          }
+        }
+      }
     </data>
   </datamodel>
 
@@ -88,11 +93,11 @@
 
     <state id='javascript.datamodel'>
       <onentry>
-        <log expr='"Lion : " + Data("string(jungle/animals/lion/name)")  + "," + Data("string(jungle/animals/lion/age)")'  />
-        <log expr='"Tiger: " + Data("string(jungle/animals/tiger/name)") + "," + Data("string(jungle/animals/tiger/age)")' />
-        <assign location='Location("jungle/animals/lion/age")' expr='Data("jungle/animals/tiger/age")' type="replace"/>
-        <log expr='"Lion : " + Data("string(jungle/animals/lion/name)")  + "," + Data("string(jungle/animals/lion/age)")'  />
-        <log expr='"Tiger: " + Data("string(jungle/animals/tiger/name)") + "," + Data("string(jungle/animals/tiger/age)")' />
+        <log expr='"Lion : " + jungle.animals.lion.name  + "," + jungle.animals.lion.age'  />
+        <log expr='"Tiger: " + jungle.animals.tiger.name  + "," + jungle.animals.tiger.age'  />
+        <assign location='jungle.animals.lion.age' expr='jungle.animals.tiger.age'/>
+        <log expr='"Lion : " + jungle.animals.lion.name  + "," + jungle.animals.lion.age'  />
+        <log expr='"Tiger: " + jungle.animals.tiger.name  + "," + jungle.animals.tiger.age'  />
       </onentry>
       <transition target='javascript.functions.inline' />
     </state>
@@ -128,11 +133,11 @@
     <state id='javascript.functions.print'>
       <onentry>
         <log expr='function debug(msg)
-                        { println("** " + msg + " **");
+                        { print("** " + msg + " **");
                           return "ok"
                         }
 
-               debug("This is the Javascript println() function")' />
+               debug("This is the Javascript print() function")' />
       </onentry>
       <transition target='javascript.eventdatamap.example' />
     </state>

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/6af929eb/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-01.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-01.xml b/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-01.xml
index d6b4e7c..5e87087 100644
--- a/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-01.xml
+++ b/src/test/java/org/apache/commons/scxml2/env/jexl/datamodel-01.xml
@@ -16,8 +16,7 @@
  * limitations under the License.
 -->
 <!-- A fictitious state machine used by test cases.
-     Meant to illustrate the usage of SCXML <datamodel> element
-     and the Commons SCXML Data() function -->
+     Meant to illustrate the usage of SCXML <datamodel> element -->
 <scxml xmlns="http://www.w3.org/2005/07/scxml"
        version="1.0"
        datamodel="jexl"
@@ -25,13 +24,7 @@
 
     <!-- Root or document datamodel -->
     <datamodel>
-        <data id="docdata">
-            <root xmlns="">
-                <foo>
-                    <bar>alpha</bar>
-                </foo>
-            </root>
-        </data>
+        <data id="docdata">{ "root" : { "foo" : { "bar" : "alpha" } } }</data>
     </datamodel>
 
     <state id="main">
@@ -44,37 +37,19 @@
         <datamodel>
             <!-- Degenerate usage, similar to the <var> element -->
             <data id="mainvar" expr="0" />
-            <!-- Usage where the value is an XML data tree -->
-            <data id="maindata">
-                <root xmlns="">
-                    <a>
-                        <b>
-                            <c>beta</c>
-                            <d>123</d>
-                            <e>456.789</e>
-                        </b>
-                    </a>
-                </root>
-            </data>
+            <!-- Usage where the value is an JSON model -->
+            <data id="maindata">{ "root" : { "a" : { "b" : { "c" : "beta", "d" : 123, "e" : 456.789 } } } }</data>
         </datamodel>
 
         <state id="ten">
             <onentry>
-                <!-- Assign Usage 1: location is previously defined
-                      <var> or degenerate <data> (as in this case) -->
                 <assign location="mainvar" expr="10" />
             </onentry>
-            <!-- Commons SCXML defines a Data() function to use in conjunction
-                 with the Commons JEXL expression language. The
-                 argument is the XPath expression to a node whose value is to be
-                 examined  -->
             <transition event="done.state.ten"
-             cond="mainvar eq 10 and Data('string($maindata/root/a/b/c)') eq 'beta'"
+             cond="mainvar eq 10 and maindata.root.a.b.c eq 'beta'"
              target="twenty" />
             <onexit>
-                <!-- Assign Usage 2: location must point to an existing
-                      node  -->
-                <assign location="Location('$maindata/root/a/b/c')" expr="'gamma'" />
+                <assign location="maindata.root.a.b.c" expr="'gamma'" />
             </onexit>
         </state>
 
@@ -83,24 +58,21 @@
                 <assign location="mainvar" expr="20" />
             </onentry>
             <transition event="done.state.twenty"
-             cond="Data('string(maindata/root/a/b/c)') eq 'gamma' and mainvar eq 20"
+             cond="maindata.root.a.b.c eq 'gamma' and mainvar eq 20"
              target="thirty" />
             <onexit>
-                <!-- Assign Usage 3: location points to an existing
-                      node, and expr points to an existing node.
-                      In this case, location adopts expr's child nodes.  -->
-                <assign location="Location('$docdata/root/foo')"
-                        expr="Data('$maindata/root/*')" />
+                <assign location="docdata.root.foo"
+                        expr="maindata.root" />
             </onexit>
         </state>
 
         <state id="thirty">
-            <!-- Arithmetic operations are possible with results from
-                 the Data() function. Note that data "docdata"
-                 did not have a node at 'root/foo/a/b/d' to begin with,
-                 the XML tree was manipulated by the <assign> above -->
+            <!-- Arithmetic operations.
+                 Note that data "docdata"
+                 did not have data at 'root.foo.a.b.d' to begin with,
+                 the data model was manipulated by the <assign> above -->
             <transition event="done.state.thirty"
-             cond="Data('number($docdata/root/foo/a/b/d)') + Data('number($docdata/root/foo/a/b/e)') eq 579.789"
+             cond="docdata.root.foo.a.b.d + docdata.root.foo.a.b.e eq 579.789"
              target="forty" />
         </state>