- From: COUTHURES Alain <alain.couthures@agencexml.com>
- Date: Sat, 11 Dec 2010 15:48:25 +0100
- To: public-forms@w3.org, www-forms@w3.org
- Message-ID: <4D038F39.90209@agencexml.com>
Hello,
Please find below my proposition for an internal storage in XML 1.0 for
JSON objects allowing intuitive XPath expressions.
I'm writing a paper for XML Prague 2011 about implementing this in
XSLTForms. This is the corresponding extract.
Thank you for your feedbacks.
-Alain
------------------------------------------------------------------------
Constraints
Reversibility
JSON objects have to be serialized identically to the original ones when
not modified by controls.
XPath Full Support
New XPath extension functions should be enough to guaranty a full support.
Whenever extra elements are required for internal storage, their number
should be minimal.
Javascript notation to retrieve an item in a array ([/pos/] where /pos/
starts from 0) should be almost preserved ([/pos/] where /pos/ starts
from 1).
XML Schema conformance
XML Schema Recommendation already defines the xsi:type and the xsi:nil
attributes and they are supported in the XForms Recommendation. The
xsd:maxOccurs attribute enables to specify how many occurences there
might be for an element.
Proposed Representation of JSON Objects With XML 1.0
Elements, Attributes and Namespaces
Elements are used for JSON values within the empty namespace.
Meta data are stored in attributes within a specific namespace.
Extra elements are limited and always in a specific namespace.
Extra Document Element
XML 1.0 requires a unique document element so such an element is always
added.
Example:
{ a: "stringA", b: { c: "stringC", d: "stringD" } }
would be serialized as:
<exml:noname xmlns:exml="http://www.agencexml.com/exml" xmlns="">
<a>stringA</a>
<b>
<c>stringC</c>
<d>stringD</d>
</b>
</exml:noname>
and
*
"/*/a" equals 'stringA'
*
"/*/b/c" equals 'stringC'
*
"/*/b/d" equals 'stringD'
JSON Names
JSON names which cannot be used as XML names are replaced by '________'
in the empty namespace.
An extra attribute is used to store the JSON name and the new XPath
functions fullname() and local-fullname() are created to return its value.
Example:
{ "a& b": "A+B", "déjà": "already", "________": "undescores" }
are represented as:
<exml:noname xmlns:exml="http://www.agencexml.com/exml"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:exsi="http://www.agencexml.com/exi" xmlns="">
<________ exml:fullname="a& b">A+B</________>
<________ exml:fullname="déjà">already</________>
<________ exml:fullname="________">underscores</________>
</exml:noname>
and
*
"/*/*[fullname() = 'a & b']" equals 'A+B'
*
"local-fullname(/*/*[1])" equals 'a & b'
*
"/*/*[fullname() = 'déjà']" equals 'already'
*
"local-fullname(/*/*[2])" equals 'déjà'
*
"/*/________[fullname() = '________']" equals 'underscores'
JSON Datatypes
For each Javascript datatype, the most approaching XSD type is
automatically associated. XForms bindings have to be used to adjust more
precisely the effective datatype.
Example:
{ a: "string"+"A", b: 42, c: new Date(2011,3,26), d: true }
would be serialized as:
<exml:noname xmlns:exml="http://www.agencexml.com/exml"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns="">
<a>stringA</a>
<b xsi:type="xsd:double">42</b>
<c xsi:type="xsd:dateTime">2011-03-26T00:00:00Z</c>
<d xsi:type="xsd:boolean">true</d>
</exml:noname>
JSON Named Arrays
Arrays are modeled with an extra attribute. Empty arrays require another
attribute because, if not, there would be an ambiguity for an array with
just the empty string as element.
Extra XPath functions might be helpful:
*
is-array(/node/) which might be defined as
"count(/node/[@exsi:maxOccurs = 'unbounded']) != 0"
*
array-length(/node/) which might be defined as
"count(/node/[@exsi:maxOccurs = 'unbounded' and @xsi:nil != 'true'])"
Example:
{ a: ["stringA", 42], b: [], c: [""] }
would be serialized as:
<exml:noname xmlns:exml="http://www.agencexml.com/exml"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:exsi="http://www.agencexml.com/exi" xmlns="">
<a exsi:maxOccurs="unbounded">stringA</a>
<a exsi:maxOccurs="unbounded" xsi:type="xsd:double">42</a>
<b exsi:maxOccurs="unbounded" xsi:nil="true"/>
<c exsi:maxOccurs="unbounded"/>
</exml:noname>
and
*
"is-array(/*/a)" equals true()
*
"array-length(/*/a)" equals 2
*
"/*/a[1]" equals 'stringA'
*
"/*/a[2]" equals '42'
*
"is-array(/*/b)" equals true()
*
"array-length(/*/b)" equals 0
*
"is-array(/*/c)" equals true()
*
"array-length(/*/c)" equals 1
*
"/*/c[1]" equals ''
JSON Unnamed Arrays
An element with a reserved name in a specific namespace has to be used.
Example:
[ ["stringA", 42], [], [[]], { c: "stringC1", d: "stringD1" }, { c: "stringC2", d: "stringD2" } ]
would be serialized as:
<exml:noname xmlns:exml="http://www.agencexml.com/exml"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:exsi="http://www.agencexml.com/exi" xmlns="">
<exml:noname exsi:maxOccurs="unbounded">
<exml:noname exsi:maxOccurs="unbounded">stringA</exml:noname>
<exml:noname exsi:maxOccurs="unbounded" xsi:type="xsd:double">42</exml:noname>
</exml:noname>
<exml:noname exsi:maxOccurs="unbounded">
<exml:noname exsi:maxOccurs="unbounded" xsi:nil="true"/>
</exml:noname>
<exml:noname exsi:maxOccurs="unbounded">
<exml:noname exsi:maxOccurs="unbounded">
<exml:noname exsi:maxOccurs="unbounded" xsi:nil="true"/>
</exml:noname>
</exml:noname>
<exml:noname exsi:maxOccurs="unbounded">
<c>stringC1</c>
<d>stringD1</d>
</exml:noname>
<exml:noname exsi:maxOccurs="unbounded">
<c>stringC2</c>
<d>stringD2</d>
</exml:noname>
</exml:noname>
and
*
"/*/*[1]/*[1]" equals 'stringA'
*
"/*/*[1]/*[2]" equals '42'
*
"is-array(/*/*[2])" equals true()
*
"is-array(/*/*[3]/*[1])" equals true()
*
"/*/*/c[../d = 'stringD1']" equals 'stringC1'
*
"/*/*[c = 'stringC2']/d" equals 'stringD2'
XPath Engine Proposed Enhancements
When possible, XPath engine modifications can simplify expressions for
JSON objects:
*
non-XML names in expressions could be quoted with character `
(reverse quote) to avoid predicates with fullname() calls
*
name() and local-name() functions could be extended to support
fullname() and local-fullname() functions and return '________'
just when true
*
name() and local-name() functions could be modified to return ''
(empty string) instead of, respectively, 'exml:noname' and 'noname'
*
"/*/" used for "/exml:noname/" could be simplified as just "/"'
*
"*" used for "exml:noname" could be written ``
*
"*" used for "exml:noname" before a predicate could even be omitted
Received on Saturday, 11 December 2010 14:47:36 UTC