← Back to team overview

zorba-coders team mailing list archive

[Merge] lp:~zorba-coders/zorba/feature-json_parser into lp:zorba

 

Paul J. Lucas has proposed merging lp:~zorba-coders/zorba/feature-json_parser into lp:zorba.

Requested reviews:
  Paul J. Lucas (paul-lucas)
  William Candillon (wcandillon)
  Sorin Marian Nasoi (sorin.marian.nasoi)

For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/feature-json_parser/+merge/89616

New JSON parser and module.
Fixed the missing quote in the documentation.
Added checking of stream state for manipulators.
-- 
https://code.launchpad.net/~zorba-coders/zorba/feature-json_parser/+merge/89616
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'include/zorba/diagnostic.h'
--- include/zorba/diagnostic.h	2011-07-01 16:07:54 +0000
+++ include/zorba/diagnostic.h	2012-01-23 00:53:27 +0000
@@ -239,7 +239,10 @@
   ZORBA_DEBUGGER,                       // Zorba Debugger
   ZORBA_OS,                             // Operating System
   ZORBA_SERIALIZATION,
-  ZORBA_STORE
+  ZORBA_STORE,
+
+  JSON_PARSER,
+  JSON_SERIALIZATION
 };
 
 /**

=== modified file 'include/zorba/pregenerated/diagnostic_list.h'
--- include/zorba/pregenerated/diagnostic_list.h	2011-12-21 14:40:33 +0000
+++ include/zorba/pregenerated/diagnostic_list.h	2012-01-23 00:53:27 +0000
@@ -746,6 +746,38 @@
 
 extern ZORBA_DLL_PUBLIC ZorbaErrorCode XSST0010;
 
+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0001_ILLEGAL_CHARACTER;
+
+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0002_ILLEGAL_CODEPOINT;
+
+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0003_ILLEGAL_ESCAPE;
+
+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0004_ILLEGAL_LITERAL;
+
+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0005_ILLEGAL_NUMBER;
+
+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0006_UNEXPECTED_TOKEN;
+
+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0007_UNTERMINATED_STRING;
+
+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0008_ILLEGAL_QNAME;
+
+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJSE0001_NOT_DOCUMENT_OR_ELEMENT_NODE;
+
+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJSE0002_ELEMENT_MISSING_ATTRIBUTE;
+
+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJSE0003_BAD_ATTRIBUTE_VALUE;
+
+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJSE0004_BAD_ELEMENT;
+
+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJSE0005_BAD_CHILD_ELEMENT;
+
+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJSE0006_NO_ELEMENT_CHILD;
+
+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJSE0007_NO_TEXT_CHILD;
+
+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJSE0008_BAD_VALUE;
+
 } // namespace zerr
 
 namespace zwarn {

=== modified file 'modules/com/zorba-xquery/www/modules/CMakeLists.txt'
--- modules/com/zorba-xquery/www/modules/CMakeLists.txt	2012-01-11 17:30:25 +0000
+++ modules/com/zorba-xquery/www/modules/CMakeLists.txt	2012-01-23 00:53:27 +0000
@@ -68,6 +68,10 @@
 # Subdirectories
 DECLARE_ZORBA_MODULE(FILE converters/base64.xq VERSION 2.0
   URI "http://www.zorba-xquery.com/modules/converters/base64";)
+DECLARE_ZORBA_MODULE(FILE converters/json.xq VERSION 2.0
+  URI "http://www.zorba-xquery.com/modules/converters/json";)
+DECLARE_ZORBA_SCHEMA(FILE converters/json-options.xsd
+  URI "http://www.zorba-xquery.com/modules/converters/json-options";)
 DECLARE_ZORBA_MODULE(FILE introspection/sctx.xq VERSION 2.0
   URI "http://www.zorba-xquery.com/modules/introspection/sctx";)
 DECLARE_ZORBA_MODULE(FILE xqdoc2xhtml/error.xq VERSION 2.0

=== added file 'modules/com/zorba-xquery/www/modules/converters/json-options.xsd'
--- modules/com/zorba-xquery/www/modules/converters/json-options.xsd	1970-01-01 00:00:00 +0000
+++ modules/com/zorba-xquery/www/modules/converters/json-options.xsd	2012-01-23 00:53:27 +0000
@@ -0,0 +1,60 @@
+<!--
+ ! Copyright 2006-2008 The FLWOR Foundation.
+ !
+ ! Licensed 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.
+-->
+
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema";
+  xmlns:json="http://www.zorba-xquery.com/modules/converters/json-options";
+  targetNamespace="http://www.zorba-xquery.com/modules/converters/json-options";
+  elementFormDefault="qualified"
+  attributeFormDefault="unqualified">
+
+  <xs:element name="options">
+    <xs:complexType>
+      <xs:all>
+
+        <xs:element name="json-format" minOccurs="1" maxOccurs="1">
+          <xs:complexType>
+            <xs:attribute name="value" use="required">
+              <xs:simpleType>
+                <xs:restriction base="xs:string">
+                  <xs:enumeration value="Snelson"/>
+                  <xs:enumeration value="JsonML-array"/>
+                  <xs:enumeration value="JsonML-object"/>
+                </xs:restriction>
+              </xs:simpleType>
+            </xs:attribute>
+          </xs:complexType>
+        </xs:element>
+
+        <xs:element name="whitespace" minOccurs="0" maxOccurs="1">
+          <xs:complexType>
+            <xs:attribute name="value" use="required">
+              <xs:simpleType>
+                <xs:restriction base="xs:string">
+                  <xs:enumeration value="none"/>
+                  <xs:enumeration value="some"/>
+                  <xs:enumeration value="indent"/>
+                </xs:restriction>
+              </xs:simpleType>
+            </xs:attribute>
+          </xs:complexType>
+        </xs:element>
+
+      </xs:all>
+    </xs:complexType>
+  </xs:element>
+</xs:schema>
+
+<!-- vim:set et sw=2 ts=2: -->

=== added file 'modules/com/zorba-xquery/www/modules/converters/json.xq'
--- modules/com/zorba-xquery/www/modules/converters/json.xq	1970-01-01 00:00:00 +0000
+++ modules/com/zorba-xquery/www/modules/converters/json.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,175 @@
+(:
+ : Copyright 2006-2009 The FLWOR Foundation.
+ :
+ : Licensed 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.
+ :)
+
+xquery version "3.0";
+
+ (:~
+  : Using this module, you can parse JSON data into XML, manipulate it like any
+  : other XML data using XQuery, and serialize the result back as JSON.
+  :
+  : There are many ways to represent JSON data in XML, some loss-less ("round
+  : tripable") and some lossy ("one way").  Loss-less representations preserve
+  : the JSON data types <i>boolean</i>, <i>number</i>, and <i>null</i>; lossy
+  : representations convert all data to strings.
+  :
+  : For a loss-less representation, Zorba implements that proposed by
+  : <a href="http://john.snelson.org.uk/parsing-json-into-xquery";>John Snelson</a>;
+  : for a lossy representation, Zorba implements
+  : <a href="http://jsonml.org/";>JsonML</a> (the array form).
+  :)
+
+module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+import module namespace schema = "http://www.zorba-xquery.com/modules/schema";;
+
+import schema namespace json-options =
+  "http://www.zorba-xquery.com/modules/converters/json-options";;
+
+declare namespace err = "http://www.w3.org/2005/xqt-errors";;
+
+declare namespace ver = "http://www.zorba-xquery.com/options/versioning";;
+declare option ver:module-version "2.0";
+
+(:~
+ : Parses JSON data from a string and returns an XDM instance using one of the
+ : representations described above.
+ :
+ : @param $json The JSON data to parse.
+ : @param $options The parsing options.
+ : @return said XDM instance.
+ : @error err:XQDY0027 if $options can not be validated against the
+ : json-options schema.
+ : @error ZJPE0001 if $json contains an illegal JSON character.
+ : @error ZJPE0002 if $json contains an illegal Unicode code-point.
+ : @error ZJPE0003 if $json contains an illegal JSON character escape.
+ : @error ZJPE0004 if $json contains an illegal JSON literal.
+ : @error ZJPE0005 if $json contains an illegal JSON number.
+ : @error ZJPE0007 if $json contains an unterminated string.
+ : @error ZJPE0008 if $json contains an illegal QName.
+ :)
+declare function json:parse(
+  $json as xs:string?,
+  $options as element(json-options:options)
+) as element(*,xs:untyped)*
+{
+  let $validated-options := if ( schema:is-validated( $options ) ) then
+                              $options
+                            else
+                              validate { $options }
+  return json:parse-internal( $json, $validated-options )
+};
+
+(:~
+ : Parses JSON data from a string and returns an XDM instance using the Snelson
+ : representation described above.
+ :
+ : @param $json The JSON data to parse.
+ : @return said XDM instance.
+ : @error ZJPE0001 if $json contains an illegal JSON character.
+ : @error ZJPE0002 if $json contains an illegal Unicode code-point.
+ : @error ZJPE0003 if $json contains an illegal JSON character escape.
+ : @error ZJPE0004 if $json contains an illegal JSON literal.
+ : @error ZJPE0005 if $json contains an illegal JSON number.
+ : @error ZJPE0007 if $json contains an unterminated string.
+ : @error ZJPE0008 if $json contains an illegal QName.
+ :)
+declare function json:parse(
+  $json as xs:string?
+) as element(*,xs:untyped)*
+{
+  json:parse-internal(
+    $json,
+    validate {
+      <options xmlns="http://www.zorba-xquery.com/modules/converters/json-options"; >
+        <json-format value="Snelson"/>
+      </options>
+    }
+  )
+};
+
+(:~
+ : Serializes an XDM into JSON using one of the representations described
+ : above.
+ :
+ : @param $xml The XDM to serialize.
+ : @param $options The serializing options.
+ : @return a JSON string.
+ : @error err:XQDY0027 if $options can not be validated against the
+ : json-options schema.
+ : @error ZJSE0001 if $xml is not a document or element node.
+ : @error ZJSE0002 if $xml contains an element that is missing a required
+ : attribute.
+ : @error ZJSE0003 if $xml contains an attribute having an illegal value.
+ : @error ZJSE0004 if $xml contains an illegal element.
+ : @error ZJSE0005 if $xml contains an illegal child element for a JSON type.
+ : @error ZJSE0006 if $xml contains an illegal child element.
+ : @error ZJSE0007 if $xml contains an illegal text node.
+ : @error ZJSE0008 if $xml contains an illegal value for a JSON type.
+ :)
+declare function json:serialize(
+  $xml as item()*,
+  $options as element(json-options:options)
+) as xs:string
+{
+  let $validated-options := if ( schema:is-validated( $options ) ) then
+                              $options
+                            else
+                              validate { $options }
+  return json:serialize-internal( $xml, $validated-options )
+};
+
+(:~
+ : Serializes an XDM into JSON using one of the representations described
+ : above.
+ :
+ : @param $xml The XDM to serialize.
+ : @return a JSON string.
+ : @error ZJSE0001 if $xml is not a document or element node.
+ : @error ZJSE0002 if $xml contains an element that is missing a required
+ : attribute.
+ : @error ZJSE0003 if $xml contains an attribute having an illegal value.
+ : @error ZJSE0004 if $xml contains an illegal element.
+ : @error ZJSE0005 if $xml contains an illegal child element for a JSON type.
+ : @error ZJSE0006 if $xml contains an illegal child element.
+ : @error ZJSE0007 if $xml contains an illegal text node.
+ : @error ZJSE0008 if $xml contains an illegal value for a JSON type.
+ :)
+declare function json:serialize(
+  $xml as item()*
+) as xs:string
+{
+  json:serialize-internal($xml,
+    validate {
+      <options xmlns="http://www.zorba-xquery.com/modules/converters/json-options"; >
+        <json-format value="Snelson"/>
+      </options>
+   }
+ )
+};
+
+(:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::)
+
+declare %private function json:parse-internal(
+  $json as xs:string,
+  $options as item()?
+) as element()* external;
+
+declare %private function json:serialize-internal(
+  $xml as item()*,
+  $options as item()?
+) as xs:string external;
+
+(: vim:set et sw=2 ts=2: :)

=== modified file 'modules/com/zorba-xquery/www/modules/pregenerated/errors.xq'
--- modules/com/zorba-xquery/www/modules/pregenerated/errors.xq	2011-12-21 14:40:33 +0000
+++ modules/com/zorba-xquery/www/modules/pregenerated/errors.xq	2012-01-23 00:53:27 +0000
@@ -784,4 +784,68 @@
 
 (:~
 :)
-declare variable $zerr:XSST0010 as xs:QName := fn:QName($zerr:NS, "zerr:XSST0010");
\ No newline at end of file
+declare variable $zerr:XSST0010 as xs:QName := fn:QName($zerr:NS, "zerr:XSST0010");
+
+(:~
+:)
+declare variable $zerr:ZJPE0001 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0001");
+
+(:~
+:)
+declare variable $zerr:ZJPE0002 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0002");
+
+(:~
+:)
+declare variable $zerr:ZJPE0003 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0003");
+
+(:~
+:)
+declare variable $zerr:ZJPE0004 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0004");
+
+(:~
+:)
+declare variable $zerr:ZJPE0005 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0005");
+
+(:~
+:)
+declare variable $zerr:ZJPE0006 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0006");
+
+(:~
+:)
+declare variable $zerr:ZJPE0007 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0007");
+
+(:~
+:)
+declare variable $zerr:ZJPE0008 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0008");
+
+(:~
+:)
+declare variable $zerr:ZJSE0001 as xs:QName := fn:QName($zerr:NS, "zerr:ZJSE0001");
+
+(:~
+:)
+declare variable $zerr:ZJSE0002 as xs:QName := fn:QName($zerr:NS, "zerr:ZJSE0002");
+
+(:~
+:)
+declare variable $zerr:ZJSE0003 as xs:QName := fn:QName($zerr:NS, "zerr:ZJSE0003");
+
+(:~
+:)
+declare variable $zerr:ZJSE0004 as xs:QName := fn:QName($zerr:NS, "zerr:ZJSE0004");
+
+(:~
+:)
+declare variable $zerr:ZJSE0005 as xs:QName := fn:QName($zerr:NS, "zerr:ZJSE0005");
+
+(:~
+:)
+declare variable $zerr:ZJSE0006 as xs:QName := fn:QName($zerr:NS, "zerr:ZJSE0006");
+
+(:~
+:)
+declare variable $zerr:ZJSE0007 as xs:QName := fn:QName($zerr:NS, "zerr:ZJSE0007");
+
+(:~
+:)
+declare variable $zerr:ZJSE0008 as xs:QName := fn:QName($zerr:NS, "zerr:ZJSE0008");
\ No newline at end of file

=== modified file 'src/context/static_context.cpp'
--- src/context/static_context.cpp	2012-01-11 17:30:25 +0000
+++ src/context/static_context.cpp	2012-01-23 00:53:27 +0000
@@ -349,6 +349,9 @@
 static_context::ZORBA_STRING_FN_NS = NS_PRE + "modules/string";
 
 const zstring
+static_context::ZORBA_JSON_FN_NS = NS_PRE + "modules/converters/json";
+
+const zstring
 static_context::ZORBA_FETCH_FN_NS = NS_PRE + "modules/fetch";
 
 const zstring
@@ -414,6 +417,7 @@
             ns == ZORBA_REFLECTION_FN_NS ||
             ns == ZORBA_SCRIPTING_FN_NS ||
             ns == ZORBA_STRING_FN_NS ||
+            ns == ZORBA_JSON_FN_NS ||
             ns == ZORBA_FETCH_FN_NS ||
             ns == ZORBA_NODE_FN_NS ||
             ns == ZORBA_XML_FN_NS);
@@ -460,6 +464,7 @@
   {
     return (ns == ZORBA_MATH_FN_NS ||
             ns == ZORBA_INTROSP_SCTX_FN_NS ||
+            ns == ZORBA_JSON_FN_NS ||
             ns == ZORBA_RANDOM_FN_NS);
   }
 

=== modified file 'src/context/static_context.h'
--- src/context/static_context.h	2012-01-11 17:30:25 +0000
+++ src/context/static_context.h	2012-01-23 00:53:27 +0000
@@ -464,6 +464,7 @@
   static const zstring ZORBA_INTROSP_SCTX_FN_NS;
   static const zstring ZORBA_REFLECTION_FN_NS;
   static const zstring ZORBA_STRING_FN_NS;
+  static const zstring ZORBA_JSON_FN_NS;
   static const zstring ZORBA_FETCH_FN_NS;
   static const zstring ZORBA_NODE_FN_NS;
   static const zstring ZORBA_XML_FN_NS;

=== modified file 'src/diagnostics/diagnostic.cpp'
--- src/diagnostics/diagnostic.cpp	2011-07-11 21:01:20 +0000
+++ src/diagnostics/diagnostic.cpp	2012-01-23 00:53:27 +0000
@@ -134,6 +134,9 @@
     case ZORBA_STORE         : o << "Zorba store"           ; break;
     case ZORBA_XQP           : o << "Zorba"                 ; break;
 
+    case JSON_PARSER         : o << "JSON parser"           ; break;
+    case JSON_SERIALIZATION  : o << "JSON serialization"    ; break;
+
     default                  : /* suppresses warning */       break;
   }
   return o;

=== modified file 'src/diagnostics/diagnostic_en.xml'
--- src/diagnostics/diagnostic_en.xml	2011-12-21 14:40:33 +0000
+++ src/diagnostics/diagnostic_en.xml	2012-01-23 00:53:27 +0000
@@ -2307,6 +2307,60 @@
       <value>"continue loop" statement not inside while statement</value>
     </diagnostic>
 
+   <!--////////// JSON Parse Errors ////////////////////////////////////////-->
+
+    <diagnostic code="ZJPE0001" name="ILLEGAL_CHARACTER">
+      <value>'$1': illegal JSON character</value>
+    </diagnostic>
+    <diagnostic code="ZJPE0002" name="ILLEGAL_CODEPOINT">
+      <value>"$1": illegal Unicode code-point</value>
+    </diagnostic>
+    <diagnostic code="ZJPE0003" name="ILLEGAL_ESCAPE">
+      <value>'\\$1': illegal JSON character escape</value>
+    </diagnostic>
+    <diagnostic code="ZJPE0004" name="ILLEGAL_LITERAL">
+      <value>illegal JSON literal</value>
+    </diagnostic>
+    <diagnostic code="ZJPE0005" name="ILLEGAL_NUMBER">
+      <value>illegal JSON number</value>
+    </diagnostic>
+    <diagnostic code="ZJPE0006" name="UNEXPECTED_TOKEN">
+      <value>"$1": unexpected JSON token</value>
+    </diagnostic>
+    <diagnostic code="ZJPE0007" name="UNTERMINATED_STRING">
+      <value>unterminated JSON string</value>
+    </diagnostic>
+    <diagnostic code="ZJPE0008" name="ILLEGAL_QNAME">
+      <value>"$1": illegal QName</value>
+    </diagnostic>
+
+   <!--////////// JSON Serialization Errors ////////////////////////////////-->
+
+    <diagnostic code="ZJSE0001" name="NOT_DOCUMENT_OR_ELEMENT_NODE">
+      <value>JSON serialization requires document or element node</value>
+    </diagnostic>
+    <diagnostic code="ZJSE0002" name="ELEMENT_MISSING_ATTRIBUTE">
+      <value>"$1" element missing required "$2" attribute</value>
+    </diagnostic>
+    <diagnostic code="ZJSE0003" name="BAD_ATTRIBUTE_VALUE">
+      <value>"$1": illegal value for attribute "$2"</value>
+    </diagnostic>
+    <diagnostic code="ZJSE0004" name="BAD_ELEMENT">
+      <value>"$1": illegal element${; must be "2"}${ or "3"}</value>
+    </diagnostic>
+    <diagnostic code="ZJSE0005" name="BAD_CHILD_ELEMENT">
+      <value>"$1": illegal child element of "$2" type; must be "$3"</value>
+    </diagnostic>
+    <diagnostic code="ZJSE0006" name="NO_ELEMENT_CHILD">
+      <value>JSON type "$1" can not have a child element node</value>
+    </diagnostic>
+    <diagnostic code="ZJSE0007" name="NO_TEXT_CHILD">
+      <value>JSON type "$1" can not have a child text node</value>
+    </diagnostic>
+    <diagnostic code="ZJSE0008" name="BAD_VALUE">
+      <value>"$1": illegal value for JSON type "$2"</value>
+    </diagnostic>
+
   </namespace>
 
   <!--////////// Zorba Warnings ////////////////////////////////////////////-->
@@ -3264,6 +3318,14 @@
       <value>Zorba warning</value>
     </entry>
 
+    <entry key="JSON parser error">
+      <value>JSON parser error</value>
+    </entry>
+
+    <entry key="JSON serialization error">
+      <value>JSON serialization error</value>
+    </entry>
+
     <entry key="dynamic error">
       <value>dynamic error</value>
     </entry>

=== modified file 'src/diagnostics/pregenerated/diagnostic_list.cpp'
--- src/diagnostics/pregenerated/diagnostic_list.cpp	2011-12-21 14:40:33 +0000
+++ src/diagnostics/pregenerated/diagnostic_list.cpp	2012-01-23 00:53:27 +0000
@@ -1097,6 +1097,54 @@
 ZorbaErrorCode XSST0010( "XSST0010" );
 
 
+ZorbaErrorCode ZJPE0001_ILLEGAL_CHARACTER( "ZJPE0001" );
+
+
+ZorbaErrorCode ZJPE0002_ILLEGAL_CODEPOINT( "ZJPE0002" );
+
+
+ZorbaErrorCode ZJPE0003_ILLEGAL_ESCAPE( "ZJPE0003" );
+
+
+ZorbaErrorCode ZJPE0004_ILLEGAL_LITERAL( "ZJPE0004" );
+
+
+ZorbaErrorCode ZJPE0005_ILLEGAL_NUMBER( "ZJPE0005" );
+
+
+ZorbaErrorCode ZJPE0006_UNEXPECTED_TOKEN( "ZJPE0006" );
+
+
+ZorbaErrorCode ZJPE0007_UNTERMINATED_STRING( "ZJPE0007" );
+
+
+ZorbaErrorCode ZJPE0008_ILLEGAL_QNAME( "ZJPE0008" );
+
+
+ZorbaErrorCode ZJSE0001_NOT_DOCUMENT_OR_ELEMENT_NODE( "ZJSE0001" );
+
+
+ZorbaErrorCode ZJSE0002_ELEMENT_MISSING_ATTRIBUTE( "ZJSE0002" );
+
+
+ZorbaErrorCode ZJSE0003_BAD_ATTRIBUTE_VALUE( "ZJSE0003" );
+
+
+ZorbaErrorCode ZJSE0004_BAD_ELEMENT( "ZJSE0004" );
+
+
+ZorbaErrorCode ZJSE0005_BAD_CHILD_ELEMENT( "ZJSE0005" );
+
+
+ZorbaErrorCode ZJSE0006_NO_ELEMENT_CHILD( "ZJSE0006" );
+
+
+ZorbaErrorCode ZJSE0007_NO_TEXT_CHILD( "ZJSE0007" );
+
+
+ZorbaErrorCode ZJSE0008_BAD_VALUE( "ZJSE0008" );
+
+
 } // namespace zerr
 
 namespace zwarn {

=== modified file 'src/diagnostics/pregenerated/dict_en.cpp'
--- src/diagnostics/pregenerated/dict_en.cpp	2011-12-21 14:40:33 +0000
+++ src/diagnostics/pregenerated/dict_en.cpp	2012-01-23 00:53:27 +0000
@@ -332,6 +332,22 @@
 #if defined(ZORBA_WITH_DEBUGGER)
   { "ZGDB0001", "" },
 #endif
+  { "ZJPE0001", "'$1': illegal JSON character" },
+  { "ZJPE0002", "\"$1\": illegal Unicode code-point" },
+  { "ZJPE0003", "'\\$1': illegal JSON character escape" },
+  { "ZJPE0004", "illegal JSON literal" },
+  { "ZJPE0005", "illegal JSON number" },
+  { "ZJPE0006", "\"$1\": unexpected JSON token" },
+  { "ZJPE0007", "unterminated JSON string" },
+  { "ZJPE0008", "\"$1\": illegal QName" },
+  { "ZJSE0001", "JSON serialization requires document or element node" },
+  { "ZJSE0002", "\"$1\" element missing required \"$2\" attribute" },
+  { "ZJSE0003", "\"$1\": illegal value for attribute \"$2\"" },
+  { "ZJSE0004", "\"$1\": illegal element${; must be \"2\"}${ or \"3\"}" },
+  { "ZJSE0005", "\"$1\": illegal child element of \"$2\" type; must be \"$3\"" },
+  { "ZJSE0006", "JSON type \"$1\" can not have a child element node" },
+  { "ZJSE0007", "JSON type \"$1\" can not have a child text node" },
+  { "ZJSE0008", "\"$1\": illegal value for JSON type \"$2\"" },
   { "ZOSE0001", "\"$1\": file not found" },
   { "ZOSE0002", "\"$1\": not plain file" },
   { "ZOSE0003", "stream read failure" },
@@ -494,6 +510,8 @@
   { "~HexBinaryMustBeEven", "HexBinary value must contain an even number of characters" },
   { "~IncompleteKeyInIndexBuild", "incomplete key during index build" },
   { "~IncompleteKeyInIndexRefresh", "incomplete key during index refresh" },
+  { "~JSON parser error", "JSON parser error" },
+  { "~JSON serialization error", "JSON serialization error" },
   { "~LibModVersionMismatch_3", "XQuery library version can not be imported by a $3 version module" },
   { "~ModuleDeclNotInMain", "module declaration must not be in main module" },
   { "~ModuleNotFound", "module not found" },

=== modified file 'src/diagnostics/qname.cpp'
--- src/diagnostics/qname.cpp	2011-07-01 16:07:54 +0000
+++ src/diagnostics/qname.cpp	2012-01-23 00:53:27 +0000
@@ -79,9 +79,15 @@
     case 'C': return ZORBA_SERIALIZATION;
     case 'D': return ZORBA_DDF;
     case 'G': return ZORBA_DEBUGGER;
+    case 'J': switch ( name[2] ) {
+                case 'P': return JSON_PARSER;
+                case 'S': return JSON_SERIALIZATION;
+                default : ZORBA_ASSERT( false );
+              }
     case 'O': return ZORBA_OS;
     case 'S': return ZORBA_STORE;
     case 'X': return ZORBA_XQP;
+
     default : ZORBA_ASSERT( false );
   }
 }

=== modified file 'src/functions/library.cpp'
--- src/functions/library.cpp	2011-10-14 07:35:51 +0000
+++ src/functions/library.cpp	2012-01-23 00:53:27 +0000
@@ -57,6 +57,7 @@
 #include "functions/func_sequences.h"
 #include "functions/func_sequences_impl.h"
 #include "functions/func_strings.h"
+#include "functions/func_json.h"
 #include "functions/func_var_decl.h"
 #include "functions/func_xqdoc.h"
 #include "functions/func_documents.h"
@@ -107,6 +108,7 @@
   populate_context_fnput(sctx);
   populate_context_index_ddl(sctx);
   populate_context_ic_ddl(sctx);
+  populate_context_json(sctx);
   populate_context_maths(sctx);
   populate_context_nodes(sctx);
   populate_context_node_position(sctx);

=== added file 'src/functions/pregenerated/func_json.cpp'
--- src/functions/pregenerated/func_json.cpp	1970-01-01 00:00:00 +0000
+++ src/functions/pregenerated/func_json.cpp	2012-01-23 00:53:27 +0000
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed 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.
+ */
+ 
+// ******************************************
+// *                                        *
+// * THIS IS A GENERATED FILE. DO NOT EDIT! *
+// * SEE .xml FILE WITH SAME NAME           *
+// *                                        *
+// ******************************************
+
+
+#include "stdafx.h"
+#include "runtime/json/json.h"
+#include "functions/func_json.h"
+
+
+namespace zorba{
+
+
+
+PlanIter_t fn_zorba_json_parse_internal::codegen(
+  CompilerCB*,
+  static_context* sctx,
+  const QueryLoc& loc,
+  std::vector<PlanIter_t>& argv,
+  AnnotationHolder& ann) const
+{
+  return new JSONParseInternal(sctx, loc, argv);
+}
+
+PlanIter_t fn_zorba_json_serialize_internal::codegen(
+  CompilerCB*,
+  static_context* sctx,
+  const QueryLoc& loc,
+  std::vector<PlanIter_t>& argv,
+  AnnotationHolder& ann) const
+{
+  return new JSONSerializeInternal(sctx, loc, argv);
+}
+
+void populate_context_json(static_context* sctx)
+{
+  {
+    
+
+    DECL_WITH_KIND(sctx, fn_zorba_json_parse_internal,
+        (createQName("http://www.zorba-xquery.com/modules/converters/json","","parse-internal";), 
+        GENV_TYPESYSTEM.STRING_TYPE_ONE, 
+        GENV_TYPESYSTEM.ITEM_TYPE_QUESTION, 
+        GENV_TYPESYSTEM.ELEMENT_TYPE_STAR),
+        FunctionConsts::FN_ZORBA_JSON_PARSE_INTERNAL_2);
+
+  }
+
+
+  {
+    
+
+    DECL_WITH_KIND(sctx, fn_zorba_json_serialize_internal,
+        (createQName("http://www.zorba-xquery.com/modules/converters/json","","serialize-internal";), 
+        GENV_TYPESYSTEM.ITEM_TYPE_STAR, 
+        GENV_TYPESYSTEM.ITEM_TYPE_QUESTION, 
+        GENV_TYPESYSTEM.STRING_TYPE_ONE),
+        FunctionConsts::FN_ZORBA_JSON_SERIALIZE_INTERNAL_2);
+
+  }
+
+}
+
+
+}
+
+
+

=== added file 'src/functions/pregenerated/func_json.h'
--- src/functions/pregenerated/func_json.h	1970-01-01 00:00:00 +0000
+++ src/functions/pregenerated/func_json.h	2012-01-23 00:53:27 +0000
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed 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.
+ */
+ 
+// ******************************************
+// *                                        *
+// * THIS IS A GENERATED FILE. DO NOT EDIT! *
+// * SEE .xml FILE WITH SAME NAME           *
+// *                                        *
+// ******************************************
+
+
+#ifndef ZORBA_FUNCTIONS_JSON_H
+#define ZORBA_FUNCTIONS_JSON_H
+
+
+#include "common/shared_types.h"
+#include "functions/function_impl.h"
+
+
+namespace zorba {
+
+
+void populate_context_json(static_context* sctx);
+
+
+
+
+//fn-zorba-json:parse-internal
+class fn_zorba_json_parse_internal : public function
+{
+public:
+  fn_zorba_json_parse_internal(const signature& sig, FunctionConsts::FunctionKind kind)
+    : 
+    function(sig, kind)
+  {
+
+  }
+
+  CODEGEN_DECL();
+};
+
+
+//fn-zorba-json:serialize-internal
+class fn_zorba_json_serialize_internal : public function
+{
+public:
+  fn_zorba_json_serialize_internal(const signature& sig, FunctionConsts::FunctionKind kind)
+    : 
+    function(sig, kind)
+  {
+
+  }
+
+  CODEGEN_DECL();
+};
+
+
+} //namespace zorba
+
+
+#endif
+/*
+ * Local variables:
+ * mode: c++
+ * End:
+ */ 

=== modified file 'src/functions/pregenerated/function_enum.h'
--- src/functions/pregenerated/function_enum.h	2012-01-11 17:30:25 +0000
+++ src/functions/pregenerated/function_enum.h	2012-01-23 00:53:27 +0000
@@ -166,6 +166,8 @@
   FN_ZORBA_INTROSPECT_SCTX_IN_SCOPE_ATTRIBUTE_GROUPS_0,
   FN_ZORBA_INTROSPECT_SCTX_OPTION_1,
   FN_ZORBA_INTROSPECT_SCTX_FUNCTION_ANNOTATIONS_2,
+  FN_ZORBA_JSON_PARSE_INTERNAL_2,
+  FN_ZORBA_JSON_SERIALIZE_INTERNAL_2,
   MATH_SQRT_1,
   MATH_EXP_1,
   MATH_EXP10_1,

=== modified file 'src/runtime/CMakeLists.txt'
--- src/runtime/CMakeLists.txt	2011-06-01 13:16:28 +0000
+++ src/runtime/CMakeLists.txt	2012-01-23 00:53:27 +0000
@@ -115,6 +115,9 @@
   durations_dates_times/DurationsDatesTimesImpl.cpp
   indexing/doc_indexer.cpp
   indexing/index_ddl.cpp
+  json/common.cpp
+  json/jsonml_array.cpp
+  json/snelson.cpp
   numerics/NumericsImpl.cpp
   numerics/format_integer_impl.cpp
   sequences/SequencesImpl.cpp

=== modified file 'src/runtime/full_text/ft_match.cpp'
--- src/runtime/full_text/ft_match.cpp	2011-06-14 17:26:33 +0000
+++ src/runtime/full_text/ft_match.cpp	2012-01-23 00:53:27 +0000
@@ -31,7 +31,7 @@
   return o << "0x" << hex << reinterpret_cast<unsigned long>( obj ) << dec;
 }
 
-DEF_OMANIP1( print_addr, void const*, obj )
+DEF_OMANIP1( print_addr, void const* )
 
 ostream& operator<<( ostream &o, ft_string_match const &sm ) {
   return  o << "{SM: "
@@ -52,8 +52,7 @@
   return o;
 }
 
-DEF_OMANIP2( print_string_matches, char const*, label,
-             ft_string_matches const&, sms )
+DEF_OMANIP2( print_string_matches, char const*, ft_string_matches const& )
 
 ostream& operator<<( ostream &o, ft_match const &m ) {
   return  o << indent << "ft_match @ " << print_addr( &m ) << '\n'

=== added directory 'src/runtime/json'
=== added file 'src/runtime/json/common.cpp'
--- src/runtime/json/common.cpp	1970-01-01 00:00:00 +0000
+++ src/runtime/json/common.cpp	2012-01-23 00:53:27 +0000
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2006-2011 The FLWOR Foundation.
+ * 
+ * Licensed 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.
+ */
+#include "stdafx.h"
+
+#include "store/api/iterator.h"
+
+#include "common.h"
+
+using namespace std;
+
+namespace zorba {
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool get_attribute_value( store::Item_t const &element, char const *att_name,
+                          zstring *att_value ) {
+  store::Iterator_t i( element->getAttributes() );
+  bool found = false;
+  i->open();
+  store::Item_t att_item;
+  while ( i->next( att_item ) ) {
+    if ( att_item->getNodeName()->getStringValue() == att_name ) {
+      att_item->getStringValue2( *att_value );
+      found = true;
+      break;
+    }
+  }
+  i->close();
+  return found;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#if ZORBA_DEBUG_JSON
+
+ostream& operator<<( ostream &o, parse_state s ) {
+  static char const *const string_of[] = {
+    "in_array",
+    "in_object"
+  };
+  return o << string_of[ s ];
+}
+
+#endif /* ZORBA_DEBUG_JSON */
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace zorba
+/* vim:set et sw=2 ts=2: */

=== added file 'src/runtime/json/common.h'
--- src/runtime/json/common.h	1970-01-01 00:00:00 +0000
+++ src/runtime/json/common.h	2012-01-23 00:53:27 +0000
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2006-2011 The FLWOR Foundation.
+ * 
+ * Licensed 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.
+ */
+
+#ifndef ZORBA_RUNTIME_JSON_COMMON_H
+#define ZORBA_RUNTIME_JSON_COMMON_H
+
+#include <iostream>
+#include <stack>
+
+#include "store/api/item.h"
+#include "store/api/item_factory.h"
+#include "util/indent.h"
+#include "util/omanip.h"
+#include "zorbatypes/zstring.h"
+
+#define ZORBA_DEBUG_JSON 0
+
+namespace zorba {
+
+///////////////////////////////////////////////////////////////////////////////
+
+typedef std::stack<store::Item*> item_stack_type;
+
+enum parse_state {
+  in_array,
+  in_object
+};
+
+typedef std::stack<int> state_stack_type;
+
+namespace whitespace {
+  enum type {
+    none,
+    some,
+    indent
+  };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool get_attribute_value( store::Item_t const &element, char const *att_name,
+                          zstring *att_value );
+
+typedef std::ostream& (*std_omanip_type)(std::ostream&);
+
+inline std::ostream& if_do( std::ostream &o, bool expr, std_omanip_type fn ) {
+  if ( expr )
+    o << fn;
+  return o;
+}
+DEF_OMANIP2( if_do, bool, std_omanip_type )
+
+#define if_indent(WS,FN) if_do( (WS) == whitespace::indent, FN )
+
+inline std::ostream& if_emit( std::ostream &o, bool expr, char c ) {
+  if ( expr )
+    o << c;
+  return o;
+}
+DEF_OMANIP2( if_emit, bool, char )
+
+///////////////////////////////////////////////////////////////////////////////
+
+#if ZORBA_DEBUG_JSON
+
+std::ostream& operator<<( std::ostream &o, parse_state s );
+
+# define PUSH_ITEM(I)                                                     \
+    do {                                                                  \
+      cout << __LINE__ << ":PUSH_ITEM( " << (I)->show() << " )" << endl;  \
+      item_stack.push( (I).getp() );                                      \
+    } while (0)
+
+# define POP_ITEM()                               \
+    do {                                          \
+      cout << __LINE__ << ":POP_ITEM()" << endl;  \
+      cur_item = ztd::pop_stack( item_stack );    \
+    } while (0)
+
+# define PUSH_STATE(S) \
+    do {                                                          \
+      cout << __LINE__ << ":PUSH_STATE( " << (S) << " )" << endl; \
+      state_stack.push( S );                                      \
+    } while (0)
+
+# define POP_STATE()                              \
+    do {                                          \
+      cout << __LINE__ << ":POP_STATE()" << endl; \
+      state_stack.pop();                          \
+    } while (0)                                   \
+
+#else
+
+# define PUSH_ITEM(I)   item_stack.push( (I).getp() )
+# define POP_ITEM()     cur_item = ztd::pop_stack( item_stack )
+# define PUSH_STATE(S)  state_stack.push( S )
+# define POP_STATE()    state_stack.pop()
+
+#endif /* ZORBA_DEBUG_JSON */
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace zorba
+#endif /* ZORBA_RUNTIME_JSON_COMMON_H */
+/* vim:set et sw=2 ts=2: */

=== added file 'src/runtime/json/json_impl.cpp'
--- src/runtime/json/json_impl.cpp	1970-01-01 00:00:00 +0000
+++ src/runtime/json/json_impl.cpp	2012-01-23 00:53:27 +0000
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2006-2011 The FLWOR Foundation.
+ * 
+ * Licensed 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.
+ */
+#include "stdafx.h"
+
+#include <map>
+#include <sstream>
+
+#include <zorba/diagnostic_list.h>
+
+#include "runtime/json/json.h"
+#include "store/api/item_factory.h"
+#include "system/globalenv.h"
+#include "util/mem_streambuf.h"
+
+#include "jsonml_array.h"
+#include "snelson.h"
+
+using namespace std;
+
+namespace zorba {
+
+///////////////////////////////////////////////////////////////////////////////
+
+typedef map<zstring,zstring> options_type;
+
+static void get_options( store::Item_t const &options_element,
+                         options_type *options ) {
+  ZORBA_ASSERT( options_element->getNodeKind() ==
+    store::StoreConsts::elementNode );
+  store::Iterator_t i = options_element->getChildren();
+  i->open();
+  store::Item_t option_item;
+  while ( i->next( option_item ) ) {
+    if ( option_item->getNodeKind() == store::StoreConsts::elementNode ) {
+      zstring const name( option_item->getNodeName()->getStringValue() );
+      zstring value;
+      get_attribute_value( option_item, "value", &value );
+      (*options)[ name ] = value;
+    }
+  }
+  i->close();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool JSONParseInternal::nextImpl( store::Item_t& result,
+                                  PlanState &planState ) const {
+  store::Item_t cur_item;
+  options_type options;
+  istringstream iss;
+  mem_streambuf buf;
+
+  PlanIteratorState *state;
+  DEFAULT_STACK_INIT( PlanIteratorState, state, planState );
+
+  ZORBA_ASSERT( theChildren.size() == 2 );
+  ZORBA_ASSERT( consumeNext( cur_item, theChildren[1], planState ) );
+  get_options( cur_item, &options );
+
+  if ( consumeNext( cur_item, theChildren[0], planState ) ) {
+    istream *is;
+    if ( cur_item->isStreamable() ) {
+      is = &cur_item->getStream();
+    } else {
+      zstring s;
+      cur_item->getStringValue2( s );
+      // Doing it this way uses the string data in-place with no copy.
+      buf.set( s.data(), s.size() );
+      iss.ios::rdbuf( &buf );
+      is = &iss;
+    }
+
+    try {
+      json::parser p( *is );
+      p.set_loc(
+        loc.getFilename().c_str(), loc.getLineBegin(), loc.getColumnBegin()
+      );
+
+      options_type::mapped_type const &format = options[ "json-format" ];
+      ZORBA_ASSERT( !format.empty() );
+      if ( format == "Snelson" )
+        snelson::parse( p, &result );
+      else if ( format == "JsonML-array" )
+        jsonml_array::parse( p, &result );
+      else
+        ZORBA_ASSERT( false );
+    }
+    catch ( json::illegal_character const &e ) {
+      throw XQUERY_EXCEPTION(
+        zerr::ZJPE0001_ILLEGAL_CHARACTER,
+        ERROR_PARAMS( e.get_char() ),
+        ERROR_LOC( e.get_loc() )
+      );
+    }
+    catch ( json::illegal_codepoint const &e ) {
+      throw XQUERY_EXCEPTION(
+        zerr::ZJPE0002_ILLEGAL_CODEPOINT,
+        ERROR_PARAMS( e.get_codepoint() ),
+        ERROR_LOC( e.get_loc() )
+      );
+    }
+    catch ( json::illegal_escape const &e ) {
+      throw XQUERY_EXCEPTION(
+        zerr::ZJPE0003_ILLEGAL_ESCAPE,
+        ERROR_PARAMS( e.get_escape() ),
+        ERROR_LOC( e.get_loc() )
+      );
+    }
+    catch ( json::illegal_literal const &e ) {
+      throw XQUERY_EXCEPTION(
+        zerr::ZJPE0004_ILLEGAL_LITERAL,
+        ERROR_LOC( e.get_loc() )
+      );
+    }
+    catch ( json::illegal_number const &e ) {
+      throw XQUERY_EXCEPTION(
+        zerr::ZJPE0005_ILLEGAL_NUMBER,
+        ERROR_LOC( e.get_loc() )
+      );
+    }
+    catch ( json::unexpected_token const &e ) {
+      throw XQUERY_EXCEPTION(
+        zerr::ZJPE0006_UNEXPECTED_TOKEN,
+        ERROR_PARAMS( e.get_token() ),
+        ERROR_LOC( e.get_loc() )
+      );
+    }
+    catch ( json::unterminated_string const &e ) {
+      throw XQUERY_EXCEPTION(
+        zerr::ZJPE0007_UNTERMINATED_STRING,
+        ERROR_LOC( e.get_loc() )
+      );
+    }
+
+    STACK_PUSH( !!result, state );
+  } // if ( consumeNext( ...
+  STACK_END( state );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool JSONSerializeInternal::nextImpl( store::Item_t& result,
+                                      PlanState &planState ) const {
+  store::Item_t cur_item;
+  options_type options;
+
+  PlanIteratorState *state;
+  DEFAULT_STACK_INIT( PlanIteratorState, state, planState );
+
+  ZORBA_ASSERT( theChildren.size() == 2 );
+  ZORBA_ASSERT( consumeNext( cur_item, theChildren[1], planState ) );
+  get_options( cur_item, &options );
+
+  if ( consumeNext( cur_item, theChildren[0], planState ) ) {
+    try {
+      options_type::mapped_type const &format_opt = options[ "json-format" ];
+      ZORBA_ASSERT( !format_opt.empty() );
+
+      whitespace::type ws;
+      options_type::mapped_type const &whitespace_opt = options[ "whitespace" ];
+      if ( whitespace_opt.empty() || whitespace_opt == "none" )
+        ws = whitespace::none;
+      else if ( whitespace_opt == "some" )
+        ws = whitespace::some;
+      else if ( whitespace_opt == "indent" )
+        ws = whitespace::indent;
+      else
+        ZORBA_ASSERT( false );
+
+      ostringstream oss;
+      switch ( cur_item->getNodeKind() ) {
+        case store::StoreConsts::documentNode:
+        case store::StoreConsts::elementNode:
+          if ( format_opt == "Snelson" )
+            snelson::serialize( oss, cur_item, ws );
+          else if ( format_opt == "JsonML-array" )
+            jsonml_array::serialize( oss, cur_item, ws );
+          else
+            ZORBA_ASSERT( false );
+          break;
+        default:
+          throw XQUERY_EXCEPTION(
+            zerr::ZJSE0001_NOT_DOCUMENT_OR_ELEMENT_NODE,
+            ERROR_LOC( loc )
+          );
+      }
+      // This string copying is inefficient, but I can't see another way.
+      zstring temp( oss.str() );
+      GENV_ITEMFACTORY->createString( result, temp );
+    }
+    catch ( ZorbaException &e ) {
+      set_source( e, loc );
+      throw;
+    }
+  } // if ( consumeNext( ...
+  STACK_PUSH( !!result, state );
+  STACK_END( state );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace zorba
+/* vim:set et sw=2 ts=2: */

=== added file 'src/runtime/json/jsonml_array.cpp'
--- src/runtime/json/jsonml_array.cpp	1970-01-01 00:00:00 +0000
+++ src/runtime/json/jsonml_array.cpp	2012-01-23 00:53:27 +0000
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2006-2011 The FLWOR Foundation.
+ * 
+ * Licensed 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.
+ */
+#include "stdafx.h"
+
+#include <sstream>
+
+#include <zorba/diagnostic_list.h>
+
+#include "runtime/json/json.h"
+#include "store/api/item_factory.h"
+#include "system/globalenv.h"
+#include "types/root_typemanager.h"
+#include "util/ascii_util.h"
+#include "util/cxx_util.h"
+#include "util/json_parser.h"
+#include "util/mem_streambuf.h"
+#include "util/omanip.h"
+#include "util/oseparator.h"
+#include "util/stl_util.h"
+
+#include "jsonml_array.h"
+
+using namespace std;
+
+namespace zorba {
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void split_name( zstring const &name, zstring *prefix, zstring *local ) {
+  zstring::size_type const colon = name.find( ':' );
+  if ( colon != zstring::npos ) {
+    *prefix = name.substr( 0, colon );
+    *local = name.substr( colon + 1 );
+    if ( prefix->empty() || local->empty() )
+      throw XQUERY_EXCEPTION(
+        zerr::ZJPE0008_ILLEGAL_QNAME,
+        ERROR_PARAMS( name )
+      );
+  } else {
+    prefix->clear();
+    *local = name;
+  }
+}
+
+namespace expect {
+  enum type {
+    none,
+    element_name,
+    attribute_name,
+    attribute_value
+  };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace jsonml_array {
+
+void parse( json::parser &p, store::Item_t *result ) {
+  ZORBA_ASSERT( result );
+
+  state_stack_type state_stack;
+
+  store::Item_t cur_item, junk_item, value_item;
+  store::Item_t att_name, element_name, type_name;
+
+  zstring base_uri;
+  item_stack_type item_stack;
+  expect::type expect_what = expect::none;
+  store::NsBindings ns_bindings;
+  zstring value;
+
+  json::token token;
+  while ( p.next( &token ) ) {
+    switch ( token.get_type() ) {
+
+      case '[':
+        PUSH_STATE( in_array );
+        expect_what = expect::element_name;
+        break;
+
+      case '{':
+        PUSH_STATE( in_object );
+        expect_what = expect::attribute_name;
+        break;
+
+      case ']':
+        POP_ITEM();
+        // no break;
+      case '}':
+        POP_STATE();
+        expect_what = expect::none;
+        break;
+
+      case ',':
+        expect_what = state_stack.top() == in_object ?
+          expect::attribute_name : expect::none;
+        break;
+
+      case ':':
+        expect_what = expect::attribute_value;
+        break;
+
+      case json::token::number:
+      case 'F':
+      case 'T':
+      case json::token::json_null:
+      case json::token::string: {
+        value = token.get_value();
+        zstring prefix, local;
+        switch ( expect_what ) {
+          case expect::element_name:
+            split_name( value, &prefix, &local );
+            GENV_ITEMFACTORY->createQName( element_name, "", prefix, local );
+            type_name = GENV_TYPESYSTEM.XS_UNTYPED_QNAME;
+            GENV_ITEMFACTORY->createElementNode(
+              cur_item,
+              item_stack.empty() ? nullptr : item_stack.top(),
+              element_name, type_name, false, false, ns_bindings, base_uri
+            );
+            PUSH_ITEM( cur_item );
+            if ( !*result )
+              *result = cur_item;
+            break;
+          case expect::attribute_name:
+            split_name( value, &prefix, &local );
+            GENV_ITEMFACTORY->createQName( att_name, "", prefix, local );
+            break;
+          case expect::attribute_value:
+            type_name = GENV_TYPESYSTEM.XS_UNTYPED_QNAME;
+            GENV_ITEMFACTORY->createString( value_item, value );
+            GENV_ITEMFACTORY->createAttributeNode(
+              junk_item, cur_item, att_name, type_name, value_item
+            );
+            break;
+          case expect::none:
+            GENV_ITEMFACTORY->createTextNode( junk_item, cur_item, value );
+            break;
+        }
+        break;
+      }
+
+      case json::token::none:
+        break;
+
+      default:
+        assert( false );
+    } // switch
+  } // while
+}
+
+} // namespace jsonml_array
+
+///////////////////////////////////////////////////////////////////////////////
+
+static ostream& serialize_attributes( ostream &o, store::Item_t const &element,
+                                      oseparator &sep, whitespace::type ws ) {
+  bool emitted_attributes = false;
+  oseparator att_sep;
+  switch ( ws ) {
+    case whitespace::none  : att_sep.sep( ","   ); break;
+    case whitespace::some  : att_sep.sep( ", "  ); break;
+    case whitespace::indent: att_sep.sep( ",\n" ); break;
+  }
+
+  store::Iterator_t i( element->getAttributes() );
+  i->open();
+  store::Item_t att_item;
+  while ( i->next( att_item ) ) {
+    zstring const att_name( att_item->getNodeName()->getStringValue() );
+    if ( att_name == "xmlns" )
+      continue;
+    if ( !emitted_attributes ) {
+      o << sep
+        << if_emit( ws == whitespace::indent, '\n' )
+        << if_indent( ws, indent ) << '{'
+        << if_indent( ws, inc_indent );
+      emitted_attributes = true;
+    }
+    bool const was_printing = att_sep.printing();
+    o << att_sep;
+    if ( was_printing )
+      o << if_indent( ws, indent );
+    else
+      o << if_emit( ws, ' ' );
+    
+    o << '"' << att_name << '"'
+      << if_emit( ws, ' ' ) << ':' << if_emit( ws, ' ' )
+      << '"' << att_item->getStringValue() << '"';
+  }
+  i->close();
+  if ( emitted_attributes )
+    o << if_emit( ws, ' ' ) << '}' << if_indent( ws, dec_indent );
+  return o;
+}
+DEF_OMANIP3( serialize_attributes, store::Item_t const&, oseparator&,
+             whitespace::type )
+
+static ostream& serialize_children( ostream&, store::Item_t const &parent,
+                                    oseparator&, whitespace::type );
+DEF_OMANIP3( serialize_children, store::Item_t const&, oseparator&,
+             whitespace::type )
+
+static ostream& serialize_element( ostream &o, store::Item_t const &element,
+                                   oseparator &sep, whitespace::type ws ) {
+  if ( sep.printing() )
+    o << if_emit( ws == whitespace::indent, '\n' );
+  sep.printing( true );
+  o << if_indent( ws, indent ) << '[' << if_emit( ws, ' ' )
+    << '"' << element->getNodeName()->getStringValue() << '"'
+    << if_indent( ws, inc_indent )
+    << serialize_attributes( element, sep, ws )
+    << serialize_children( element, sep, ws )
+    << if_emit( ws, ' ' ) << ']'
+    << if_indent( ws, dec_indent );
+  return o;
+}
+DEF_OMANIP3( serialize_element, store::Item_t const&, oseparator&,
+             whitespace::type )
+
+static ostream& serialize_children( ostream &o, store::Item_t const &parent,
+                                    oseparator &sep, whitespace::type ws ) {
+  store::Iterator_t i( parent->getChildren() );
+  i->open();
+  store::Item_t child;
+  while ( i->next( child ) ) {
+    switch ( child->getNodeKind() ) {
+      case store::StoreConsts::elementNode:
+        o << sep << serialize_element( child, sep, ws );
+        break;
+      case store::StoreConsts::textNode:
+        o << sep << '"' << child->getStringValue() << '"';
+        break;
+      default:
+        break;
+    }
+  }
+  i->close();
+  return o;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace jsonml_array {
+
+void serialize( ostream &o, store::Item_t const &item, whitespace::type ws ) {
+  oseparator sep;
+  if ( ws )
+    sep.sep( ", " );
+  else
+    sep.sep( "," );
+  switch ( item->getNodeKind() ) {
+    case store::StoreConsts::documentNode:
+      o << serialize_children( item, sep, ws );
+      break;
+    case store::StoreConsts::elementNode:
+      o << serialize_element( item, sep, ws );
+      break;
+    default:
+      throw XQUERY_EXCEPTION( zerr::ZJSE0001_NOT_DOCUMENT_OR_ELEMENT_NODE );
+  }
+}
+
+} // namespace jsonml_array
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace zorba
+/* vim:set et sw=2 ts=2: */

=== added file 'src/runtime/json/jsonml_array.h'
--- src/runtime/json/jsonml_array.h	1970-01-01 00:00:00 +0000
+++ src/runtime/json/jsonml_array.h	2012-01-23 00:53:27 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2006-2011 The FLWOR Foundation.
+ * 
+ * Licensed 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.
+ */
+#include "stdafx.h"
+
+#ifndef ZORBA_RUNTIME_JSON_JSONML_ARRAY_H
+#define ZORBA_RUNTIME_JSON_JSONML_ARRAY_H
+
+#include <iostream>
+
+#include "store/api/item.h"
+#include "util/json_parser.h"
+
+#include "common.h"
+
+namespace zorba {
+namespace jsonml_array {
+
+///////////////////////////////////////////////////////////////////////////////
+
+void parse( json::parser &p, store::Item_t *result );
+void serialize( std::ostream&, store::Item_t const &item, whitespace::type );
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace jsonml_array
+} // namespace zorba
+#endif /* ZORBA_RUNTIME_JSON_JSONML_ARRAY_H */
+/* vim:set et sw=2 ts=2: */

=== added directory 'src/runtime/json/pregenerated'
=== added file 'src/runtime/json/pregenerated/json.cpp'
--- src/runtime/json/pregenerated/json.cpp	1970-01-01 00:00:00 +0000
+++ src/runtime/json/pregenerated/json.cpp	2012-01-23 00:53:27 +0000
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed 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.
+ */
+ 
+// ******************************************
+// *                                        *
+// * THIS IS A GENERATED FILE. DO NOT EDIT! *
+// * SEE .xml FILE WITH SAME NAME           *
+// *                                        *
+// ******************************************
+
+#include "stdafx.h"
+#include "zorbatypes/rchandle.h"
+#include "zorbatypes/zstring.h"
+#include "runtime/visitors/planiter_visitor.h"
+#include "runtime/json/json.h"
+#include "system/globalenv.h"
+
+
+
+namespace zorba {
+
+// <JSONParseInternal>
+const char* JSONParseInternal::class_name_str = "JSONParseInternal";
+JSONParseInternal::class_factory<JSONParseInternal>
+JSONParseInternal::g_class_factory;
+
+const serialization::ClassVersion 
+JSONParseInternal::class_versions[] ={{ 1, 0x000905, false}};
+
+const int JSONParseInternal::class_versions_count =
+sizeof(JSONParseInternal::class_versions)/sizeof(struct serialization::ClassVersion);
+
+void JSONParseInternal::accept(PlanIterVisitor& v) const {
+  v.beginVisit(*this);
+
+  std::vector<PlanIter_t>::const_iterator lIter = theChildren.begin();
+  std::vector<PlanIter_t>::const_iterator lEnd = theChildren.end();
+  for ( ; lIter != lEnd; ++lIter ){
+    (*lIter)->accept(v);
+  }
+
+  v.endVisit(*this);
+}
+
+JSONParseInternal::~JSONParseInternal() {}
+
+// </JSONParseInternal>
+
+
+// <JSONSerializeInternal>
+const char* JSONSerializeInternal::class_name_str = "JSONSerializeInternal";
+JSONSerializeInternal::class_factory<JSONSerializeInternal>
+JSONSerializeInternal::g_class_factory;
+
+const serialization::ClassVersion 
+JSONSerializeInternal::class_versions[] ={{ 1, 0x000905, false}};
+
+const int JSONSerializeInternal::class_versions_count =
+sizeof(JSONSerializeInternal::class_versions)/sizeof(struct serialization::ClassVersion);
+
+void JSONSerializeInternal::accept(PlanIterVisitor& v) const {
+  v.beginVisit(*this);
+
+  std::vector<PlanIter_t>::const_iterator lIter = theChildren.begin();
+  std::vector<PlanIter_t>::const_iterator lEnd = theChildren.end();
+  for ( ; lIter != lEnd; ++lIter ){
+    (*lIter)->accept(v);
+  }
+
+  v.endVisit(*this);
+}
+
+JSONSerializeInternal::~JSONSerializeInternal() {}
+
+// </JSONSerializeInternal>
+
+
+
+}
+
+

=== added file 'src/runtime/json/pregenerated/json.h'
--- src/runtime/json/pregenerated/json.h	1970-01-01 00:00:00 +0000
+++ src/runtime/json/pregenerated/json.h	2012-01-23 00:53:27 +0000
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed 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.
+ */
+ 
+// ******************************************
+// *                                        *
+// * THIS IS A GENERATED FILE. DO NOT EDIT! *
+// * SEE .xml FILE WITH SAME NAME           *
+// *                                        *
+// ******************************************
+#ifndef ZORBA_RUNTIME_JSON_JSON_H
+#define ZORBA_RUNTIME_JSON_JSON_H
+
+
+#include "common/shared_types.h"
+
+
+
+#include "runtime/base/narybase.h"
+
+
+namespace zorba {
+
+/**
+ * 
+ *    function for parsing strings into json-xdm
+ *  
+ * Author: Zorba Team
+ */
+class JSONParseInternal : public NaryBaseIterator<JSONParseInternal, PlanIteratorState>
+{ 
+public:
+  SERIALIZABLE_CLASS(JSONParseInternal);
+
+  SERIALIZABLE_CLASS_CONSTRUCTOR2T(JSONParseInternal,
+    NaryBaseIterator<JSONParseInternal, PlanIteratorState>);
+
+  void serialize( ::zorba::serialization::Archiver& ar)
+  {
+    serialize_baseclass(ar,
+    (NaryBaseIterator<JSONParseInternal, PlanIteratorState>*)this);
+  }
+
+  JSONParseInternal(
+    static_context* sctx,
+    const QueryLoc& loc,
+    std::vector<PlanIter_t>& children)
+    : 
+    NaryBaseIterator<JSONParseInternal, PlanIteratorState>(sctx, loc, children)
+  {}
+
+  virtual ~JSONParseInternal();
+
+  void accept(PlanIterVisitor& v) const;
+
+  bool nextImpl(store::Item_t& result, PlanState& aPlanState) const;
+};
+
+
+/**
+ * 
+ *    Function to serialize json/jsonml xdm to string
+ *  
+ * Author: Zorba Team
+ */
+class JSONSerializeInternal : public NaryBaseIterator<JSONSerializeInternal, PlanIteratorState>
+{ 
+public:
+  SERIALIZABLE_CLASS(JSONSerializeInternal);
+
+  SERIALIZABLE_CLASS_CONSTRUCTOR2T(JSONSerializeInternal,
+    NaryBaseIterator<JSONSerializeInternal, PlanIteratorState>);
+
+  void serialize( ::zorba::serialization::Archiver& ar)
+  {
+    serialize_baseclass(ar,
+    (NaryBaseIterator<JSONSerializeInternal, PlanIteratorState>*)this);
+  }
+
+  JSONSerializeInternal(
+    static_context* sctx,
+    const QueryLoc& loc,
+    std::vector<PlanIter_t>& children)
+    : 
+    NaryBaseIterator<JSONSerializeInternal, PlanIteratorState>(sctx, loc, children)
+  {}
+
+  virtual ~JSONSerializeInternal();
+
+  void accept(PlanIterVisitor& v) const;
+
+  bool nextImpl(store::Item_t& result, PlanState& aPlanState) const;
+};
+
+
+}
+#endif
+/*
+ * Local variables:
+ * mode: c++
+ * End:
+ */ 

=== added file 'src/runtime/json/snelson.cpp'
--- src/runtime/json/snelson.cpp	1970-01-01 00:00:00 +0000
+++ src/runtime/json/snelson.cpp	2012-01-23 00:53:27 +0000
@@ -0,0 +1,498 @@
+/*
+ * Copyright 2006-2011 The FLWOR Foundation.
+ * 
+ * Licensed 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.
+ */
+#include "stdafx.h"
+
+#include <sstream>
+
+#include <zorba/diagnostic_list.h>
+
+#include "runtime/json/json.h"
+#include "store/api/item_factory.h"
+#include "system/globalenv.h"
+#include "types/root_typemanager.h"
+#include "util/ascii_util.h"
+#include "util/cxx_util.h"
+#include "util/indent.h"
+#include "util/json_parser.h"
+#include "util/mem_streambuf.h"
+#include "util/omanip.h"
+#include "util/oseparator.h"
+#include "util/stl_util.h"
+
+#include "snelson.h"
+
+#define SNELSON_NS "http://john.snelson.org.uk/parsing-json-into-xquery";
+
+using namespace std;
+
+namespace zorba {
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void add_type_attribute( store::Item *parent, char const *value ) {
+  store::Item_t junk_item, att_name, type_name, value_item;
+  GENV_ITEMFACTORY->createQName( att_name, "", "", "type" );
+  type_name = GENV_TYPESYSTEM.XS_UNTYPED_QNAME;
+  zstring value_string( value );
+  GENV_ITEMFACTORY->createString( value_item, value_string );
+  GENV_ITEMFACTORY->createAttributeNode(
+    junk_item, parent, att_name, type_name, value_item
+  );
+}
+
+#define ADD_TYPE_ATTRIBUTE(T)             \
+  do {                                    \
+    if ( needs_type_attribute ) {         \
+      add_type_attribute( cur_item, T );  \
+      needs_type_attribute = false;       \
+    }                                     \
+  } while (0)
+
+static void add_item_element( item_stack_type &item_stack,
+                              state_stack_type &state_stack,
+                              store::Item_t &cur_item,
+                              char const *type ) {
+  if ( !state_stack.empty() && state_stack.top() == in_array ) {
+    store::Item_t element_name, type_name;
+    zstring base_uri;
+    store::NsBindings ns_bindings;
+    GENV_ITEMFACTORY->createQName( element_name, SNELSON_NS, "", "item" );
+    type_name = GENV_TYPESYSTEM.XS_UNTYPED_QNAME;
+    GENV_ITEMFACTORY->createElementNode(
+      cur_item, item_stack.top(),
+      element_name, type_name, false, false, ns_bindings, base_uri
+    );
+    add_type_attribute( cur_item.getp(), type );
+  }
+}
+
+#define ADD_ITEM_ELEMENT(T) \
+  add_item_element( item_stack, state_stack, cur_item, T );
+
+static void escape_json_chars( zstring *s ) {
+  ascii::replace_all( *s, "\"", 1, "\\\"", 2 );
+  ascii::replace_all( *s, "\\", 1, "\\\\", 2 );
+  ascii::replace_all( *s, "\b", 1, "\\b", 2 );
+  ascii::replace_all( *s, "\f", 1, "\\f", 2 );
+  ascii::replace_all( *s, "\n", 1, "\\n", 2 );
+  ascii::replace_all( *s, "\r", 1, "\\r", 2 );
+  ascii::replace_all( *s, "\t", 1, "\\t", 2 );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace snelson {
+
+void parse( json::parser &p, store::Item_t *result ) {
+  ZORBA_ASSERT( result );
+
+  state_stack_type state_stack;
+
+  store::Item_t cur_item, junk_item, value_item;
+  store::Item_t att_name, element_name, type_name;
+
+  zstring base_uri;
+  item_stack_type item_stack;
+  bool needs_type_attribute = false;
+  bool next_string_is_key = false;
+  store::NsBindings ns_bindings;
+  zstring value;
+
+  json::token token;
+  while ( p.next( &token ) ) {
+    if ( !*result ) {
+      GENV_ITEMFACTORY->createQName( element_name, SNELSON_NS, "", "json" );
+      type_name = GENV_TYPESYSTEM.XS_UNTYPED_QNAME;
+      GENV_ITEMFACTORY->createElementNode(
+        cur_item, nullptr,
+        element_name, type_name, false, false, ns_bindings, base_uri
+      );
+      *result = cur_item;
+      needs_type_attribute = true;
+    }
+
+    switch ( token.get_type() ) {
+
+      case '[':
+        PUSH_ITEM( cur_item );
+        ADD_TYPE_ATTRIBUTE( "array" );
+        ADD_ITEM_ELEMENT( "array" );
+        PUSH_STATE( in_array );
+        break;
+
+      case '{':
+        PUSH_ITEM( cur_item );
+        ADD_TYPE_ATTRIBUTE( "object" );
+        ADD_ITEM_ELEMENT( "object" );
+        PUSH_STATE( in_object );
+        next_string_is_key = true;
+        break;
+
+      case ']':
+      case '}':
+        POP_ITEM();
+        POP_STATE();
+        break;
+
+      case ',':
+        next_string_is_key = (state_stack.top() == in_object);
+        break;
+
+      case json::token::number:
+        ADD_TYPE_ATTRIBUTE( "number" );
+        ADD_ITEM_ELEMENT( "number" );
+        value = token.get_value();
+        GENV_ITEMFACTORY->createTextNode( junk_item, cur_item, value );
+        break;
+
+      case json::token::string:
+        ADD_TYPE_ATTRIBUTE( "string" );
+        value = token.get_value();
+#if 0
+        escape_json_chars( &value );
+#endif
+
+        if ( next_string_is_key ) {
+          // <pair name="..." ...>
+          GENV_ITEMFACTORY->createQName( element_name, SNELSON_NS, "", "pair" );
+          type_name = GENV_TYPESYSTEM.XS_UNTYPED_QNAME;
+          GENV_ITEMFACTORY->createElementNode(
+            cur_item, item_stack.top(),
+            element_name, type_name, false, false, ns_bindings, base_uri
+          );
+
+          GENV_ITEMFACTORY->createQName( att_name, "", "", "name" );
+          type_name = GENV_TYPESYSTEM.XS_UNTYPED_QNAME;
+          GENV_ITEMFACTORY->createString( value_item, value );
+          GENV_ITEMFACTORY->createAttributeNode(
+            junk_item, cur_item, att_name, type_name, value_item
+          );
+
+          needs_type_attribute = true;
+          next_string_is_key = false;
+        } else {
+          ADD_ITEM_ELEMENT( "string" );
+          GENV_ITEMFACTORY->createTextNode( junk_item, cur_item, value );
+        }
+        break;
+
+      case 'F':
+      case 'T':
+        ADD_TYPE_ATTRIBUTE( "boolean" );
+        ADD_ITEM_ELEMENT( "boolean" );
+        value = token.get_type() == 'F' ? "false" : "true";
+        GENV_ITEMFACTORY->createTextNode( junk_item, cur_item, value );
+        break;
+
+      case json::token::json_null:
+        ADD_TYPE_ATTRIBUTE( "null" );
+        ADD_ITEM_ELEMENT( "null" );
+        break;
+
+      case ':':
+      case json::token::none:
+        break;
+
+      default:
+        assert( false );
+    } // switch
+  } // while
+}
+
+} // namespace snelson
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void assert_json_type( json::type t, zstring const &s ) {
+  // Doing it this way uses the string data in-place with no copy.
+  mem_streambuf::char_type *const p =
+    const_cast<mem_streambuf::char_type*>( s.data() );
+  mem_streambuf buf( p, s.size() );
+  istringstream iss;
+  iss.ios::rdbuf( &buf );
+
+  json::lexer lex( iss );
+  json::token token;
+  try {
+    if ( lex.next( &token ) && json::map_type( token.get_type() ) == t )
+      return;
+  }
+  catch ( json::exception const& ) {
+    // do nothing
+  }
+  throw XQUERY_EXCEPTION(
+    zerr::ZJSE0008_BAD_VALUE,
+    ERROR_PARAMS( s, t )
+  );
+}
+
+static void require_attribute_value( store::Item_t const &element,
+                                     char const *att_name,
+                                     zstring *att_value ) {
+  if ( !get_attribute_value( element, att_name, att_value ) )
+    throw XQUERY_EXCEPTION(
+      zerr::ZJSE0002_ELEMENT_MISSING_ATTRIBUTE,
+      ERROR_PARAMS( element->getNodeName()->getStringValue(), att_name )
+    );
+}
+
+static json::type get_json_type( store::Item_t const &element,
+                                 bool allow_all_types = true ) {
+  zstring att_value;
+  require_attribute_value( element, "type", &att_value );
+  if ( att_value == "array" )
+    return json::array;
+  if ( att_value == "object" )
+    return json::object;
+  if ( allow_all_types ) {
+    if ( att_value == "boolean" )
+      return json::boolean;
+    if ( att_value == "null" )
+      return json::null;
+    if ( att_value == "number" )
+      return json::number;
+    if ( att_value == "string" )
+      return json::string;
+  }
+  throw XQUERY_EXCEPTION(
+    zerr::ZJSE0003_BAD_ATTRIBUTE_VALUE,
+    ERROR_PARAMS( att_value, "type" )
+  );
+}
+
+inline std::ostream& if_space_or_newline( std::ostream &o,
+                                          whitespace::type ws ) {
+  if ( ws == whitespace::some )
+    o << ' ';
+  else
+    o << if_emit( ws == whitespace::indent, '\n' );
+  return o;
+}
+DEF_OMANIP1( if_space_or_newline, whitespace::type )
+
+static ostream& serialize_begin( ostream &o, json::type t,
+                                 whitespace::type ws ) {
+  switch ( t ) {
+    case json::array :
+      o << '[' << if_emit( ws, ' ' );
+      break;
+    case json::object:
+      o << '{' << if_space_or_newline( ws ) << if_indent( ws, inc_indent );
+      break;
+    default:
+      /* suppress warning */;
+  }
+  return o;
+}
+DEF_OMANIP2( serialize_begin, json::type, whitespace::type )
+
+static ostream& serialize_end( ostream &o, json::type t, whitespace::type ws ) {
+  switch ( t ) {
+    case json::array:
+      o << if_emit( ws, ' ' ) << ']';
+      break;
+    case json::object:
+      o << if_space_or_newline( ws ) << if_indent( ws, dec_indent )
+        << if_indent( ws, indent ) << '}';
+      break;
+    default:
+      /* suppress warning */;
+  }
+  return o;
+}
+DEF_OMANIP2( serialize_end, json::type, whitespace::type )
+
+static ostream& serialize_boolean( ostream &o, zstring const &s ) {
+  assert_json_type( json::boolean, s );
+  return o << s;
+}
+DEF_OMANIP1( serialize_boolean, zstring const& )
+
+static ostream& serialize_number( ostream &o, zstring const &s ) {
+  assert_json_type( json::number, s );
+  return o << s;
+}
+DEF_OMANIP1( serialize_number, zstring const& )
+
+static ostream& serialize_string( ostream &o, zstring const &s ) {
+  zstring temp( s );
+  escape_json_chars( &temp );
+  temp.insert( (zstring::size_type)0, 1, '"' );
+  temp.append( 1, '"' );
+  assert_json_type( json::string, temp );
+  return o << temp;
+}
+DEF_OMANIP1( serialize_string, zstring const& )
+
+static ostream& serialize_children( ostream&, store::Item_t const&, json::type,
+                                    whitespace::type );
+DEF_OMANIP3( serialize_children, store::Item_t const&, json::type,
+             whitespace::type )
+
+static ostream& serialize_json_element( ostream &o,
+                                        store::Item_t const &element,
+                                        whitespace::type ws ) {
+  zstring const element_name( element->getNodeName()->getStringValue() );
+  if ( element_name != "json" )
+    throw XQUERY_EXCEPTION(
+      zerr::ZJSE0004_BAD_ELEMENT,
+      ERROR_PARAMS( element_name, "json" )
+    );
+
+  json::type const t = get_json_type( element, false );
+
+  return o
+    << serialize_begin( t, ws )
+    << serialize_children( element, t, ws )
+    << serialize_end( t, ws );
+}
+DEF_OMANIP2( serialize_json_element, store::Item_t const&, whitespace::type )
+
+static ostream& serialize_item_element( ostream &o,
+                                        store::Item_t const &element,
+                                        whitespace::type ws ) {
+  zstring const element_name( element->getNodeName()->getStringValue() );
+  if ( element_name != "item" )
+    throw XQUERY_EXCEPTION(
+      zerr::ZJSE0005_BAD_CHILD_ELEMENT,
+      ERROR_PARAMS( element_name, "array", "item" )
+    );
+
+  json::type const t = get_json_type( element );
+
+  return o
+    << serialize_begin( t, ws )
+    << serialize_children( element, t, ws )
+    << serialize_end( t, ws );
+}
+DEF_OMANIP2( serialize_item_element, store::Item_t const&, whitespace::type )
+
+static ostream& serialize_pair_element( ostream &o,
+                                        store::Item_t const &element,
+                                        whitespace::type ws ) {
+  zstring const element_name( element->getNodeName()->getStringValue() );
+  if ( element_name != "pair" )
+    throw XQUERY_EXCEPTION(
+      zerr::ZJSE0005_BAD_CHILD_ELEMENT,
+      ERROR_PARAMS( element_name, "object", "pair" )
+    );
+
+  zstring name_att_value;
+  require_attribute_value( element, "name", &name_att_value );
+  json::type const t = get_json_type( element );
+
+  return o
+    << if_indent( ws, indent ) << serialize_string( name_att_value )
+    << if_emit( ws, ' ' ) << ':' << if_emit( ws, ' ' )
+    << serialize_begin( t, ws )
+    << serialize_children( element, t, ws )
+    << serialize_end( t, ws );
+}
+DEF_OMANIP2( serialize_pair_element, store::Item_t const&, whitespace::type )
+
+static ostream& serialize_children( ostream &o, store::Item_t const &parent,
+                                    json::type parent_type,
+                                    whitespace::type ws ) {
+  if ( parent_type == json::null )
+    o << "null";
+  else {
+    oseparator sep;
+    if ( ws == whitespace::none )
+      sep.sep( "," );
+    else if ( ws == whitespace::some || parent_type == json::array )
+      sep.sep( ", " );
+    else
+      sep.sep( ",\n" );
+
+    store::Iterator_t i = parent->getChildren();
+    i->open();
+    store::Item_t child;
+    while ( i->next( child ) ) {
+      o << sep;
+
+      switch ( child->getNodeKind() ) {
+
+        case store::StoreConsts::elementNode:
+          switch ( parent_type ) {
+            case json::none:
+              o << serialize_json_element( child, ws );
+              break;
+            case json::array:
+              o << serialize_item_element( child, ws );
+              break;
+            case json::object:
+              o << serialize_pair_element( child, ws );
+              break;
+            default:
+              throw XQUERY_EXCEPTION(
+                zerr::ZJSE0006_NO_ELEMENT_CHILD,
+                ERROR_PARAMS( json::type_string_of[ parent_type ] )
+              );
+          }
+          break;
+
+        case store::StoreConsts::textNode:
+          switch ( parent_type ) {
+            case json::boolean:
+              o << serialize_boolean( child->getStringValue() );
+              break;
+            case json::number:
+              o << serialize_number( child->getStringValue() );
+              break;
+            case json::string:
+              o << serialize_string( child->getStringValue() );
+              break;
+            default:
+              throw XQUERY_EXCEPTION(
+                zerr::ZJSE0007_NO_TEXT_CHILD,
+                ERROR_PARAMS( json::type_string_of[ parent_type ] )
+              );
+          }
+          break;
+
+        default:
+          // do nothing
+          break;
+      } // switch
+    } // while
+    i->close();
+  }
+  return o;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace snelson {
+
+void serialize( ostream &o, store::Item_t const &item, whitespace::type ws ) {
+  switch ( item->getNodeKind() ) {
+    case store::StoreConsts::documentNode:
+      o << serialize_children( item, json::none, ws );
+      break;
+    case store::StoreConsts::elementNode:
+      o << serialize_json_element( item, ws );
+      break;
+    default:
+      throw XQUERY_EXCEPTION( zerr::ZJSE0001_NOT_DOCUMENT_OR_ELEMENT_NODE );
+  }
+}
+
+} // namespace snelson
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace zorba
+/* vim:set et sw=2 ts=2: */

=== added file 'src/runtime/json/snelson.h'
--- src/runtime/json/snelson.h	1970-01-01 00:00:00 +0000
+++ src/runtime/json/snelson.h	2012-01-23 00:53:27 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2006-2011 The FLWOR Foundation.
+ * 
+ * Licensed 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.
+ */
+#include "stdafx.h"
+
+#ifndef ZORBA_RUNTIME_JSON_SNELSON_H
+#define ZORBA_RUNTIME_JSON_SNELSON_H
+
+#include <iostream>
+
+#include "store/api/item.h"
+#include "util/json_parser.h"
+
+#include "common.h"
+
+namespace zorba {
+namespace snelson {
+
+///////////////////////////////////////////////////////////////////////////////
+
+void parse( json::parser &p, store::Item_t *result );
+void serialize( std::ostream&, store::Item_t const &item, whitespace::type );
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace snelson
+} // namespace zorba
+#endif /* ZORBA_RUNTIME_JSON_SNELSON_H */
+/* vim:set et sw=2 ts=2: */

=== added directory 'src/runtime/spec/json'
=== added file 'src/runtime/spec/json/json.xml'
--- src/runtime/spec/json/json.xml	1970-01-01 00:00:00 +0000
+++ src/runtime/spec/json/json.xml	2012-01-23 00:53:27 +0000
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+-->
+<zorba:iterators
+  xmlns:zorba="http://www.zorba-xquery.com";
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+  xsi:schemaLocation="http://www.zorba-xquery.com ../runtime.xsd">
+
+<!--
+/*******************************************************************************
+*******************************************************************************/
+-->
+<zorba:iterator name="JSONParseInternal" arity="nary">
+
+  <zorba:description author="Zorba Team">
+    function for parsing strings into json-xdm
+  </zorba:description>
+
+  <zorba:function isDeterministic="true">
+    <zorba:signature localname="parse-internal" prefix="fn-zorba-json">
+      <zorba:param>xs:string</zorba:param>
+      <zorba:param>item()?</zorba:param>
+      <zorba:output>element()*</zorba:output>
+    </zorba:signature>
+  </zorba:function>
+
+</zorba:iterator>
+
+<!--
+/*******************************************************************************
+*******************************************************************************/
+-->
+<zorba:iterator name="JSONSerializeInternal" arity="nary">
+
+  <zorba:description author="Zorba Team">
+    Function to serialize json/jsonml xdm to string
+  </zorba:description>
+
+  <zorba:function isDeterministic="true">
+    <zorba:signature localname="serialize-internal" prefix="fn-zorba-json">
+      <zorba:param>item()*</zorba:param>
+      <zorba:param>item()?</zorba:param>
+      <zorba:output>xs:string</zorba:output>
+    </zorba:signature>
+  </zorba:function>
+
+</zorba:iterator>
+
+</zorba:iterators>

=== modified file 'src/runtime/spec/mappings.xml'
--- src/runtime/spec/mappings.xml	2011-10-14 07:35:51 +0000
+++ src/runtime/spec/mappings.xml	2012-01-23 00:53:27 +0000
@@ -106,6 +106,10 @@
                      define="ZORBA_STRING_FN_NS" 
                      prefix="fn-zorba-string"/>
 
+    <zorba:namespace uri="http://www.zorba-xquery.com/modules/converters/json";
+                     define="ZORBA_JSON_FN_NS" 
+                     prefix="fn-zorba-json"/>
+
 		<zorba:namespace uri="http://www.zorba-xquery.com/modules/fetch";
                      define="ZORBA_FETCH_FN_NS" 
                      prefix="fn-zorba-fetch"/>

=== modified file 'src/runtime/visitors/pregenerated/planiter_visitor.h'
--- src/runtime/visitors/pregenerated/planiter_visitor.h	2012-01-11 17:30:25 +0000
+++ src/runtime/visitors/pregenerated/planiter_visitor.h	2012-01-23 00:53:27 +0000
@@ -251,6 +251,10 @@
 
     class FunctionAnnotationsIterator;
 
+    class JSONParseInternal;
+
+    class JSONSerializeInternal;
+
     class SqrtIterator;
 
     class ExpIterator;
@@ -929,6 +933,12 @@
     virtual void beginVisit ( const FunctionAnnotationsIterator& ) = 0;
     virtual void endVisit   ( const FunctionAnnotationsIterator& ) = 0;
 
+    virtual void beginVisit ( const JSONParseInternal& ) = 0;
+    virtual void endVisit   ( const JSONParseInternal& ) = 0;
+
+    virtual void beginVisit ( const JSONSerializeInternal& ) = 0;
+    virtual void endVisit   ( const JSONSerializeInternal& ) = 0;
+
     virtual void beginVisit ( const SqrtIterator& ) = 0;
     virtual void endVisit   ( const SqrtIterator& ) = 0;
 

=== modified file 'src/runtime/visitors/pregenerated/printer_visitor.cpp'
--- src/runtime/visitors/pregenerated/printer_visitor.cpp	2012-01-11 17:30:25 +0000
+++ src/runtime/visitors/pregenerated/printer_visitor.cpp	2012-01-23 00:53:27 +0000
@@ -50,6 +50,7 @@
 #include "runtime/function_item/function_item_iter.h"
 #include "runtime/indexing/ic_ddl.h"
 #include "runtime/introspection/sctx.h"
+#include "runtime/json/json.h"
 #include "runtime/maths/maths.h"
 #include "runtime/nodes/node_position.h"
 #include "runtime/nodes/nodes.h"
@@ -1650,6 +1651,34 @@
 // </FunctionAnnotationsIterator>
 
 
+// <JSONParseInternal>
+void PrinterVisitor::beginVisit ( const JSONParseInternal& a) {
+  thePrinter.startBeginVisit("JSONParseInternal", ++theId);
+  printCommons( &a, theId );
+  thePrinter.endBeginVisit( theId );
+}
+
+void PrinterVisitor::endVisit ( const JSONParseInternal& ) {
+  thePrinter.startEndVisit();
+  thePrinter.endEndVisit();
+}
+// </JSONParseInternal>
+
+
+// <JSONSerializeInternal>
+void PrinterVisitor::beginVisit ( const JSONSerializeInternal& a) {
+  thePrinter.startBeginVisit("JSONSerializeInternal", ++theId);
+  printCommons( &a, theId );
+  thePrinter.endBeginVisit( theId );
+}
+
+void PrinterVisitor::endVisit ( const JSONSerializeInternal& ) {
+  thePrinter.startEndVisit();
+  thePrinter.endEndVisit();
+}
+// </JSONSerializeInternal>
+
+
 // <SqrtIterator>
 void PrinterVisitor::beginVisit ( const SqrtIterator& a) {
   thePrinter.startBeginVisit("SqrtIterator", ++theId);

=== modified file 'src/runtime/visitors/pregenerated/printer_visitor.h'
--- src/runtime/visitors/pregenerated/printer_visitor.h	2012-01-11 17:30:25 +0000
+++ src/runtime/visitors/pregenerated/printer_visitor.h	2012-01-23 00:53:27 +0000
@@ -379,6 +379,12 @@
     void beginVisit( const FunctionAnnotationsIterator& );
     void endVisit  ( const FunctionAnnotationsIterator& );
 
+    void beginVisit( const JSONParseInternal& );
+    void endVisit  ( const JSONParseInternal& );
+
+    void beginVisit( const JSONSerializeInternal& );
+    void endVisit  ( const JSONSerializeInternal& );
+
     void beginVisit( const SqrtIterator& );
     void endVisit  ( const SqrtIterator& );
 

=== modified file 'src/unit_tests/CMakeLists.txt'
--- src/unit_tests/CMakeLists.txt	2011-12-21 14:40:33 +0000
+++ src/unit_tests/CMakeLists.txt	2012-01-23 00:53:27 +0000
@@ -16,4 +16,5 @@
 SET(UNIT_TEST_SRCS
   unit_tests.cpp
   test_uri.cpp
+  json_parser.cpp
 )

=== added file 'src/unit_tests/json_parser.cpp'
--- src/unit_tests/json_parser.cpp	1970-01-01 00:00:00 +0000
+++ src/unit_tests/json_parser.cpp	2012-01-23 00:53:27 +0000
@@ -0,0 +1,636 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ * 
+ * Licensed 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.
+ */
+
+#include <sstream>
+
+#include "util/json_parser.h"
+
+using namespace std;
+using namespace zorba;
+using namespace zorba::json;
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int failures;
+
+static bool assert_true( char const *expr, int line, bool result ) {
+  if ( !result ) {
+    cout << "FAILED, line " << line << ": " << expr << endl;
+    ++failures;
+  }
+  return result;
+}
+
+static void print_exception( char const *expr, int line,
+                             std::exception const &e ) {
+  assert_true( expr, line, false );
+  cout << "+ exception: ";
+  if ( json::exception const *j = dynamic_cast<json::exception const*>( &e ) ) {
+    json::location const &loc = j->get_loc();
+    if ( loc.file() && *loc.file() )
+      cout << '"' << loc.file() << "\": ";
+    cout << loc.line();
+    if ( loc.column() )
+      cout << ',' << loc.column();
+    cout << ": ";
+  }
+  cout << e.what() << endl;
+}
+
+#define ASSERT_TRUE( EXPR ) assert_true( #EXPR, __LINE__, !!(EXPR) )
+
+#define ASSERT_EXCEPTION( EXPR, EXCEPTION ) \
+  try { EXPR; assert_true( #EXPR, __LINE__, false ); } \
+  catch ( EXCEPTION const& ) { }
+
+#define ASSERT_NO_EXCEPTION( EXPR ) \
+  try { EXPR; } \
+  catch ( std::exception const &e ) { print_exception( #EXPR, __LINE__, e ); } \
+  catch ( ... ) { assert_true( #EXPR, __LINE__, false ); }
+
+#define ASSERT_TRUE_AND_NO_EXCEPTION( EXPR ) \
+  try { ASSERT_TRUE( EXPR ); } \
+  catch ( std::exception const &e ) { print_exception( #EXPR, __LINE__, e ); } \
+  catch ( ... ) { assert_true( #EXPR, __LINE__, false ); }
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void test_empty_stream() {
+  char const source[] = "";
+  istringstream iss( source );
+  parser p( iss );
+  token t;
+  ASSERT_NO_EXCEPTION( p.next( &t ) );
+}
+
+static void test_illegal_character() {
+  char const source[] = " x ";
+  istringstream iss( source );
+  lexer lex( iss );
+  token t;
+  ASSERT_EXCEPTION( lex.next( &t ), illegal_character );
+}
+
+static void test_illegal_codepoint() {
+  static char const *const sources[] = {
+    " \" \\u  \" ",
+    " \" \\u0  \" ",
+    " \" \\u00  \" ",
+    " \" \\u000  \" ",
+    " \" \\uG  \" ",
+    " \" \\u\" ",
+    0
+  };
+
+  for ( char const *const *s = sources; *s; ++s ) {
+    istringstream iss( *s );
+    lexer lex( iss );
+    token t;
+    ASSERT_EXCEPTION( lex.next( &t ), illegal_codepoint );
+  }
+}
+
+static void test_illegal_escape() {
+  char const source[] = "  \"  \\x  \"  ";
+  istringstream iss( source );
+  lexer lex( iss );
+  token t;
+  ASSERT_EXCEPTION( lex.next( &t ), illegal_escape );
+}
+
+static void test_illegal_literal() {
+  static char const *const sources[] = {
+    " f ",
+    " fa ",
+    " fal ",
+    " fals ",
+    " falsee ",
+    " t ",
+    " tr ",
+    " tru ",
+    " truee ",
+    " n ",
+    " nu ",
+    " nul ",
+    " nulll ",
+    0
+  };
+
+  for ( char const *const *s = sources; *s; ++s ) {
+    istringstream iss( *s );
+    lexer lex( iss );
+    token t;
+    ASSERT_EXCEPTION( lex.next( &t ), illegal_literal );
+  }
+}
+
+static void test_illegal_number() {
+}
+
+static void test_json_org_example() {
+  char const source[] =
+/*  1 */ "{" "\n"
+/*  2 */ "  \"glossary\": {" "\n"
+/*  3 */ "    \"title\": \"example glossary\"," "\n"
+/*  4 */ "    \"GlossDiv\": {" "\n"
+/*  5 */ "      \"title\": \"S\"," "\n"
+/*  6 */ "      \"GlossList\": {" "\n"
+/*  7 */ "        \"GlossEntry\": {" "\n"
+/*  8 */ "          \"ID\": \"SGML\"," "\n"
+/*  9 */ "          \"SortAs\": \"SGML\"," "\n"
+/* 10 */ "          \"GlossTerm\": \"Standard Generalized Markup Language\"," "\n"
+/* 11 */ "          \"Acronym\": \"SGML\"," "\n"
+/* 12 */ "          \"Abbrev\": \"ISO 8879:1986\"," "\n"
+/* 13 */ "          \"GlossDef\": {" "\n"
+/* 14 */ "            \"para\": \"A meta-markup language, used to create markup languages such as DocBook.\"," "\n"
+/* 15 */ "            \"GlossSeeAlso\": [\"GML\", \"XML\"]" "\n"
+/* 16 */ "          }," "\n"
+/* 17 */ "          \"GlossSee\": \"markup\"" "\n"
+/* 18 */ "        }" "\n"
+/* 19 */ "      }" "\n"
+/* 20 */ "    }" "\n"
+/* 21 */ "  }" "\n"
+/* 22 */ "}" "\n" ;
+
+  istringstream iss( source );
+  parser p( iss );
+  token t;
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  1: {
+  ASSERT_TRUE( t == token::begin_object );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  2: "glossary"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  2: :
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  2: {
+  ASSERT_TRUE( t == token::begin_object );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  3: "title"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  3: :
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  3: "example glossary"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  3: ,
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  4: "GlossDiv"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  4: :
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  4: {
+  ASSERT_TRUE( t == token::begin_object );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  5: "title"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  5: :
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  5: "S"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  5: ,
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  6: "GlossList"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  6: :
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  6: {
+  ASSERT_TRUE( t == token::begin_object );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  7: "GlossEntry"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  7: :
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  7: {
+  ASSERT_TRUE( t == token::begin_object );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  8: "ID"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  8: :
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  8: "SGML"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  8: ,
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  9: "SortAs"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  9: :
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  9: "SGML"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  //  9: ,
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 10: "GlossTerm"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 10: :
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 10: "Standard ..."
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 10: ,
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 11: "Acronym"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 11: :
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 11: "SGML"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 11: ,
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 12: "Abbrev"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 12: :
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 12: "ISO 8879:1986"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 12: ,
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 13: "GlossDef"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 13: :
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 13: {
+  ASSERT_TRUE( t == token::begin_object );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 14: "para"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 14: :
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 14: "A meta-markup ..."
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 14: ,
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 15: "GlossSeeAlso"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 15: :
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 15: [
+  ASSERT_TRUE( t == token::begin_array );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 15: "GML"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 15: ,
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 15: "XML"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 15: ]
+  ASSERT_TRUE( t == token::end_array );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 16: }
+  ASSERT_TRUE( t == token::end_object );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 16: ,
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 17: "GlossSee"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 17: :
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 17: "markup"
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 18: }
+  ASSERT_TRUE( t == token::end_object );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 19: }
+  ASSERT_TRUE( t == token::end_object );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 20: }
+  ASSERT_TRUE( t == token::end_object );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 21: }
+  ASSERT_TRUE( t == token::end_object );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );  // 22: }
+  ASSERT_TRUE( t == token::end_object );
+
+  ASSERT_TRUE( !p.next( &t ) );
+}
+
+static void test_lexer_array() {
+  char const source[] = "[ 1, \"2\", false, true, null ]";
+  istringstream iss( source );
+  lexer lex( iss );
+  token t;
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::begin_array );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::number );
+  ASSERT_TRUE( t.get_value() == "1" );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::string );
+  ASSERT_TRUE( t.get_value() == "2" );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::json_false );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::json_true );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::json_null );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::end_array );
+
+  ASSERT_TRUE( !lex.next( &t ) );
+}
+
+static void test_lexer_object() {
+  char const source[] = "{ \"a\" : 1, \"b\" : \"2\" }";
+  istringstream iss( source );
+  lexer lex( iss );
+  token t;
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::begin_object );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::number );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE( lex.next( &t ) );
+  ASSERT_TRUE( t == token::end_object );
+
+  ASSERT_TRUE( !lex.next( &t ) );
+}
+
+static void test_parser_array() {
+  char const source[] = "[ 1, \"2\", false, true, null ]";
+  istringstream iss( source );
+  parser p( iss );
+  token t;
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::begin_array );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::number );
+  ASSERT_TRUE( t.get_value() == "1" );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::string );
+  ASSERT_TRUE( t.get_value() == "2" );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::json_false );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::json_true );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::json_null );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::end_array );
+
+  ASSERT_TRUE( !p.next( &t ) );
+}
+
+static void test_parser_object() {
+  char const source[] = "{ \"a\" : 1, \"b\" : \"2\" }";
+  istringstream iss( source );
+  parser p( iss );
+  token t;
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::begin_object );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::number );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::value_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::name_separator );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::string );
+
+  ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+  ASSERT_TRUE( t == token::end_object );
+
+  ASSERT_TRUE( !p.next( &t ) );
+}
+
+static void test_unexpected_token() {
+  token t;
+  {
+    char const source[] = "{ 1 }";
+    istringstream iss( source );
+    parser p( iss );
+
+    ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+    ASSERT_TRUE( t == token::begin_object );
+    ASSERT_EXCEPTION( p.next( &t ), unexpected_token );
+  }
+  {
+    char const source[] = "{ \"a\" : 1, }";
+    istringstream iss( source );
+    parser p( iss );
+
+    ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+    ASSERT_TRUE( t == token::begin_object );
+
+    ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+    ASSERT_TRUE( t == token::string );
+
+    ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+    ASSERT_TRUE( t == token::name_separator );
+
+    ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+    ASSERT_TRUE( t == token::number );
+
+    ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+    ASSERT_TRUE( t == token::value_separator );
+
+    ASSERT_EXCEPTION( p.next( &t ), unexpected_token );
+  }
+  {
+    char const source[] = "{ \"t\" : true \"f\" : false }";
+    istringstream iss( source );
+    parser p( iss );
+
+    ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+    ASSERT_TRUE( t == token::begin_object );
+
+    ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+    ASSERT_TRUE( t == token::string );
+
+    ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+    ASSERT_TRUE( t == token::name_separator );
+
+    ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+    ASSERT_TRUE( t == token::json_true );
+
+    ASSERT_EXCEPTION( p.next( &t ), unexpected_token );
+  }
+  {
+    char const source[] = "[ 1";
+    istringstream iss( source );
+    parser p( iss );
+
+    ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+    ASSERT_TRUE( t == token::begin_array );
+
+    ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
+    ASSERT_TRUE( t == token::number );
+
+    ASSERT_EXCEPTION( p.next( &t ), unexpected_token );
+  }
+}
+
+static void test_unterminated_string() {
+  char const source[] = "  \"hello  ";
+  istringstream iss( source );
+  lexer lex( iss );
+  token t;
+
+  ASSERT_EXCEPTION( lex.next( &t ), unterminated_string );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace zorba {
+namespace UnitTests {
+
+int json_parser( int, char*[] ) {
+
+  // lexer-only tests
+  test_lexer_array();
+  test_lexer_object();
+  test_illegal_character();
+  test_illegal_codepoint();
+  test_illegal_escape();
+  test_illegal_literal();
+  test_illegal_number();
+  test_unterminated_string();
+
+  // parser tests
+  test_empty_stream();
+  test_parser_array();
+  test_parser_object();
+  test_unexpected_token();
+  test_json_org_example();
+
+  cout << failures << " test(s) failed\n";
+  return failures ? 1 : 0;
+}
+
+} // namespace UnitTests
+} // namespace zorba
+/* vim:set et sw=2 ts=2: */

=== modified file 'src/unit_tests/unit_test_list.h'
--- src/unit_tests/unit_test_list.h	2011-06-14 17:26:33 +0000
+++ src/unit_tests/unit_test_list.h	2012-01-23 00:53:27 +0000
@@ -28,6 +28,7 @@
     /**
      * ADD NEW UNIT TESTS HERE
      */
+    int json_parser( int, char*[] );
 
 
     void initializeTestList();

=== modified file 'src/unit_tests/unit_tests.cpp'
--- src/unit_tests/unit_tests.cpp	2011-06-14 17:26:33 +0000
+++ src/unit_tests/unit_tests.cpp	2012-01-23 00:53:27 +0000
@@ -38,6 +38,7 @@
      */
     void initializeTestList() {
       libunittests["uri"] = runUriTest;
+      libunittests["json_parser"] = json_parser;
 #ifdef ZORBA_WITH_DEBUGGER
 //      libunittests["debugger_protocol"] = runDebuggerProtocolTest;
 #endif

=== modified file 'src/util/CMakeLists.txt'
--- src/util/CMakeLists.txt	2011-07-18 14:25:21 +0000
+++ src/util/CMakeLists.txt	2012-01-23 00:53:27 +0000
@@ -20,6 +20,8 @@
   dir.cpp
   fs_util.cpp
   indent.cpp
+  json_parser.cpp
+  mem_streambuf.cpp
   regex.cpp
   string_util.cpp
   unicode_util.cpp

=== added file 'src/util/json_parser.cpp'
--- src/util/json_parser.cpp	1970-01-01 00:00:00 +0000
+++ src/util/json_parser.cpp	2012-01-23 00:53:27 +0000
@@ -0,0 +1,653 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed 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.
+ */
+
+#include "diagnostics/assert.h"
+
+#include "ascii_util.h"
+#include "stl_util.h"
+#include "string_util.h"
+#include "utf8_util.h"
+
+#define DEBUG_JSON_PARSER 0
+
+#if DEBUG_JSON_PARSER
+# include "indent.h"
+#endif /* DEBUG_JSON_PARSER */
+
+#include "json_parser.h"
+
+using namespace std;
+
+namespace zorba {
+namespace json {
+
+///////////////////////////////////////////////////////////////////////////////
+
+char const *const type_string_of[] = {
+  "none",
+  "array",
+  "boolean",
+  "null",
+  "number",
+  "object",
+  "string"
+};
+
+type map_type( token::type tt ) {
+  switch ( tt ) {
+    case token::string:
+      return string;
+    case token::number:
+      return number;
+    case token::json_false:
+    case token::json_true:
+      return boolean;
+    case token::json_null:
+      return null;
+    default:
+      return none;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+exception::exception( location const &loc, std::string const &message ) :
+  loc_( loc ), message_( message )
+{
+}
+
+exception::~exception() throw() {
+  // out-of-line since it's virtual
+}
+
+char const* exception::what() const throw() {
+  return message_.c_str();
+}
+
+illegal_character::illegal_character( location const &loc, char c ) :
+  exception( loc, BUILD_STRING( '\'', c, "': illegal character" ) ),
+  c_( c )
+{
+}
+
+illegal_character::~illegal_character() throw() {
+  // out-of-line since it's virtual
+}
+
+illegal_codepoint::illegal_codepoint( location const &loc,
+                                      token::value_type const &cp ) :
+  exception( loc, BUILD_STRING( '"', cp, "\": illegal codepoint" ) ),
+  codepoint_( cp )
+{
+}
+
+illegal_codepoint::~illegal_codepoint() throw() {
+  // out-of-line since it's virtual
+}
+
+illegal_escape::illegal_escape( location const &loc, char c ) :
+  exception( loc, BUILD_STRING( "\"\\", c, "\": illegal character escape" ) ),
+  esc_( c )
+{
+}
+
+illegal_escape::~illegal_escape() throw() {
+  // out-of-line since it's virtual
+}
+
+illegal_literal::illegal_literal( location const &loc ) :
+  exception( loc, "illegal literal" )
+{
+}
+
+illegal_literal::~illegal_literal() throw() {
+  // out-of-line since it's virtual
+}
+
+illegal_number::illegal_number( location const &loc ) :
+  exception( loc, "illegal number" )
+{
+}
+
+illegal_number::~illegal_number() throw() {
+  // out-of-line since it's virtual
+}
+
+unexpected_token::unexpected_token( token const &t ) :
+  exception( t.get_loc(), BUILD_STRING( '"', t, "\": unexpected token" ) ),
+  token_( t )
+{
+}
+
+unexpected_token::~unexpected_token() throw() {
+  // out-of-line since it's virtual
+}
+
+unterminated_string::unterminated_string( location const &loc ) :
+  exception( loc, "unterminated string" )
+{
+}
+
+unterminated_string::~unterminated_string() throw() {
+  // out-of-line since it's virtual
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+token::token() :
+  type_( none )
+{
+}
+
+ostream& operator<<( ostream &o, token::type tt ) {
+  switch ( tt ) {
+    case token::string    : o << "string"; break;
+    case token::number    : o << "number"; break;
+    case token::json_false: o << "false" ; break;
+    case token::json_null : o << "null"  ; break;
+    case token::json_true : o << "true"  ; break;
+    case token::none      : o << "<none>"; break;
+    default               : o << static_cast<char>( tt );
+  }
+  return o;
+}
+
+ostream& operator<<( ostream &o, token const &t ) {
+  switch ( t.get_type() ) {
+    case token::string: o << '"' << t.get_value() << '"'; break;
+    case token::number: o <<        t.get_value()       ; break;
+    default           : o <<        t.get_type()        ;
+  }
+  return o;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+lexer::lexer( istream &in ) :
+  in_( &in ),
+  line_( 1 ),
+  col_( 1 )
+{
+}
+
+bool lexer::get_char( char *c ) {
+  char const temp = in_->get();
+  if ( in_->good() ) {
+    if ( temp == '\n' )
+      ++line_, col_ = 1;
+    else
+      ++col_;
+    if ( c )
+      *c = temp;
+    return true;
+  }
+  return false;
+}
+
+bool lexer::peek_char( char *c ) {
+  *c = in_->peek();
+  return in_->good();
+}
+
+bool lexer::next( token *t ) {
+  while ( true ) {
+    cur_loc_ = cur_loc();
+    char c;
+    if ( !get_char( &c ) )
+      return false;
+    switch ( c ) {
+      case ' ':
+      case '\n':
+      case '\r':
+      case '\t':
+        continue;
+      case '"':
+        t->type_ = token::string;
+        t->loc_ = cur_loc_;
+        parse_string( &t->value_ );
+        return true;
+      case '-':
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        t->type_ = token::number;
+        t->loc_ = cur_loc_;
+        parse_number( c, &t->value_ );
+        return true;
+      case 'f':
+      case 'n':
+      case 't':
+        t->type_ = parse_literal( c, &t->value_ );
+        t->loc_ = cur_loc_;
+        return true;
+      case '[':
+      case '{':
+      case ']':
+      case '}':
+      case ':':
+      case ',':
+        t->type_ = static_cast<token::type>( c );
+        t->loc_ = cur_loc_;
+        return true;
+      default:
+        throw illegal_character( cur_loc_, c );
+    }
+  } // while
+}
+
+unicode::code_point lexer::parse_codepoint() {
+  static char const hex_digits[] = "0123456789ABCDEF";
+
+  zstring cp_string( "\\u" );           // needed only for error message
+
+  unicode::code_point cp = 0;
+  for ( int i = 1; i <= 4; ++i ) {
+    char c;
+    if ( !get_char( &c ) || !ascii::is_xdigit( c ) )
+      throw illegal_codepoint( cur_loc_, cp_string );
+    cp_string += c;
+    c = ascii::to_upper( c );
+    char const *const p = std::strchr( hex_digits, c );
+    assert( p );
+    cp = (cp << 4) | (p - hex_digits);
+  }
+  return cp;
+}
+
+token::type lexer::parse_literal( char first_c, token::value_type *value ) {
+  static token::value_type const false_value( "false" );
+  static token::value_type const null_value ( "null"  );
+  static token::value_type const true_value ( "true"  );
+
+  token::type tt;
+  switch ( first_c ) {
+    case 'f': *value = false_value; tt = token::json_false; break;
+    case 'n': *value = null_value ; tt = token::json_null ; break;
+    case 't': *value = true_value ; tt = token::json_true ; break;
+    default : assert( false );
+  }
+
+  char c;
+  for ( char const *s = value->c_str(); *++s; ) {
+    if ( !get_char( &c ) || c != *s )
+      throw illegal_literal( cur_loc_ );
+  }
+  if ( peek_char( &c ) && ascii::is_alnum( c ) )
+    throw illegal_literal( cur_loc_ );
+
+  return tt;
+}
+
+void lexer::parse_number( char first_c, token::value_type *value ) {
+  value->clear();
+
+  // <number> ::= [-] <int> [<frac>] [<exp>]
+  char c = first_c;
+  if ( c == '-' ) {
+    *value += c;
+    if ( !get_char( &c ) )
+      throw illegal_number( cur_loc_ );
+  }
+
+  // <int> := '0' | <1-9> <digit>*
+  if ( !ascii::is_digit( c ) )
+    throw illegal_number( cur_loc_ );
+  *value += c;
+  if ( c == '0' ) {
+    if ( !get_char( &c ) )
+      return;
+  } else {
+    while ( true ) {
+      if ( !get_char( &c ) )
+        return;
+      if ( !ascii::is_digit( c ) )
+        break;
+      *value += c;
+    }
+  }
+
+  // <frac> ::= '.' <digit>+
+  if ( c == '.' ) {
+    *value += c;
+    if ( !get_char( &c ) || !ascii::is_digit( c ) )
+      throw illegal_number( cur_loc_ );
+    *value += c;
+    while ( true ) {
+      if ( !get_char( &c ) )
+        return;
+      if ( !ascii::is_digit( c ) )
+        break;
+      *value += c;
+    }
+  }
+
+  // <exp>  ::= <e> [<sign>] <digit>+
+  // <e>    ::= 'e' | 'E'
+  // <sign> ::= '-' | '+'
+  if ( c == 'e' || c == 'E' ) {
+    *value += c;
+    if ( !get_char( &c ) )
+      throw illegal_number( cur_loc_ );
+    if ( c == '+' || c == '-' ) {
+      *value += c;
+      if ( !get_char( &c ) )
+        throw illegal_number( cur_loc_ );
+    }
+    if ( !ascii::is_digit( c ) )
+      throw illegal_number( cur_loc_ );
+    *value += c;
+    while ( true ) {
+      if ( !get_char( &c ) )
+        return;
+      if ( !ascii::is_digit( c ) )
+        break;
+      *value += c;
+    }
+  }
+
+  in_->putback( c );
+}
+
+void lexer::parse_string( token::value_type *value ) {
+  value->clear();
+  bool got_backslash = false;
+  location const start_loc( cur_loc_ );
+
+  while ( true ) {
+    cur_loc_ = cur_loc();
+    char c;
+    if ( !get_char( &c ) )
+      throw unterminated_string( start_loc );
+    if ( got_backslash ) {
+      got_backslash = false;
+      switch ( c ) {
+        case '"':
+        case '/':
+        case '\\':
+          *value += c;
+          break;
+        case 'b':
+          *value += '\b';
+          break;
+        case 'f':
+          *value += '\f';
+          break;
+        case 'n':
+          *value += '\n';
+          break;
+        case 'r':
+          *value += '\r';
+          break;
+        case 't':
+          *value += '\t';
+          break;
+        case 'u':
+          utf8::encode( parse_codepoint(), value );
+          break;
+        default:
+          throw illegal_escape( cur_loc_, c );
+      }
+      continue;
+    }
+
+    switch ( c ) {
+      case '\\':
+        got_backslash = true;
+        break;
+      case '"':
+        return;
+      default:
+        *value += c;
+    }
+  } // while
+}
+
+void lexer::set_loc( char const *file, line_type line, column_type col ) {
+  if ( file )
+    file_ = file;
+  line_ = line;
+  col_ = col;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#if DEBUG_JSON_PARSER
+
+ostream& operator<<( ostream &o, parser::state s ) {
+  static char const *const string_of[] = {
+    "A0", "A1", "A2",
+    "E0", "E1",
+    "J0", "J1",
+    "M0", "M1",
+    "O0", "O1", "O2",
+    "P0", "P1",
+    "V0"
+  };
+  return o << string_of[ s ];
+}
+
+static void throw_unexpected_token( int line, token const &t ) {
+  try {
+    throw unexpected_token( t );
+  }
+  catch ( exception const &e ) {
+    cerr << line << ": " << e.what() << endl;
+    throw;
+  }
+}
+
+bool parser::get_token_debug( int line, token *t ) {
+  bool const got_token = get_token( t );
+  cout << line << ": get_token => " << *t << endl;
+  return got_token;
+}
+
+bool parser::matches_token_debug( int line, token::type tt, token *t ) {
+  bool const matched = matches_token( tt, t );
+  cout << line << ": token " << *t << " matches " << tt << " => " << (matched ? 'T' : 'F') << endl;
+  return matched;
+}
+
+token::type parser::peek_token_debug( int line ) {
+  token::type const tt = peek_token();
+  cout << line << ": peek_token => " << peeked_token_ << endl;
+  return tt;
+}
+
+void parser::require_token_debug( int line, token::type tt, token *t ) {
+  if ( !get_token_debug( line, t ) || t->get_type() != tt )
+    throw_unexpected_token( line, *t );
+}
+
+# define GET_TOKEN(T)               get_token_debug( __LINE__, T )
+# define MATCHES_TOKEN(TT,T)        matches_token_debug( __LINE__, TT, T )
+# define PEEK_TOKEN()               peek_token_debug( __LINE__ )
+# define REQUIRE_TOKEN(TT,T)        require_token_debug( __LINE__, TT, T )
+# define THROW_UNEXPECTED_TOKEN(T)  throw_unexpected_token( __LINE__, T )
+
+# define GOTO_STATE(S)  \
+    if (0) ; else {     \
+      state_ = (S);     \
+      cout << __LINE__ << ':' << indent << "GOTO_STATE( " << state_ << " )" << endl;                    \
+      continue;         \
+    }
+
+# define PUSH_STATE(S)      \
+    if (0) ; else {         \
+      state_stack_.push(S); \
+      cout << __LINE__ << ':' << indent << "PUSH_STATE( " << (S) << " )" << endl << inc_indent;             \
+    }
+
+# define POP_STATE()                            \
+    if (0) ; else {                             \
+      state_ = ztd::pop_stack( state_stack_ );  \
+      cout << __LINE__ << ':' << indent << "POP_STATE() => " << state_ << endl << dec_indent;                                   \
+    }
+
+#else
+
+# define GET_TOKEN(T)               get_token( T )
+# define MATCHES_TOKEN(TT,T)        matches_token( TT, T )
+# define PEEK_TOKEN()               peek_token()
+# define REQUIRE_TOKEN(TT,T)        require_token( TT, T )
+# define THROW_UNEXPECTED_TOKEN(T)  throw unexpected_token( T )
+
+# define GOTO_STATE(S)              { state_ = (S); continue; }
+# define PUSH_STATE(S)              state_stack_.push(S)
+# define POP_STATE()                state_ = ztd::pop_stack( state_stack_ )
+
+#endif /* DEBUG_JSON_PARSER */
+
+///////////////////////////////////////////////////////////////////////////////
+
+parser::parser( istream &in ) : lexer_( in ) {
+#if DEBUG_JSON_PARSER
+  get_indent( cout ) = 0;
+#endif /* DEBUG_JSON_PARSER */
+  PUSH_STATE( J0 );
+}
+
+bool parser::get_token( token *t ) {
+  if ( peeked_token_ ) {
+    *t = peeked_token_;
+    peeked_token_.clear();
+    return true;
+  }
+  t->clear();
+  return lexer_.next( t );
+}
+
+bool parser::matches_token( token::type tt, token *t ) {
+  if ( peek_token() == tt )
+    return get_token( t );
+  *t = peeked_token_;
+  return false;
+}
+
+token::type parser::peek_token() {
+  if ( !peeked_token_ )
+    lexer_.next( &peeked_token_ );
+  return peeked_token_.get_type();
+}
+
+#if ! DEBUG_JSON_PARSER
+void parser::require_token( token::type tt, token *t ) {
+  if ( !get_token( t ) || t->get_type() != tt )
+    THROW_UNEXPECTED_TOKEN( *t );
+}
+#endif /* DEBUG_JSON_PARSER */
+
+bool parser::next( token *t ) {
+  if ( state_stack_.empty() )
+    return false;
+  POP_STATE();
+  while ( true ) {
+    switch ( state_ ) {
+
+      // <JSON> ::= <Array> | <Object>
+      case J0:  PUSH_STATE( J1 );
+                switch ( PEEK_TOKEN() ) {
+                  case token::begin_array : GOTO_STATE( A0 );
+                  case token::begin_object: GOTO_STATE( O0 );
+                  case token::none        : break;
+                  default: THROW_UNEXPECTED_TOKEN( peeked_token_ );
+                }
+      case J1:  return false;
+
+      // <Array> ::= '[' <Element>* ']'
+      case A0:  REQUIRE_TOKEN( token::begin_array, t );
+                PUSH_STATE( A1 );
+                return true;
+      case A1:  if ( MATCHES_TOKEN( token::end_array, t ) )
+                  return true;
+                PUSH_STATE( A2 );
+                GOTO_STATE( E0 );
+      case A2:  REQUIRE_TOKEN( token::end_array, t );
+                return true;
+
+      // <Element> ::= <Value> [ ',' <Element> ]
+      case E0:  PUSH_STATE( E1 );
+                GOTO_STATE( V0 );
+      case E1:  if ( MATCHES_TOKEN( token::value_separator, t ) ) {
+                  PUSH_STATE( E0 );
+                  return true;
+                }
+                POP_STATE();
+                continue;
+
+      // <Object> ::= '{' <Member>* '}'
+      case O0:  REQUIRE_TOKEN( token::begin_object, t );
+                PUSH_STATE( O1 );
+                return true;
+      case O1:  if ( MATCHES_TOKEN( token::end_object, t ) )
+                  return true;
+                PUSH_STATE( O2 );
+                GOTO_STATE( M0 );
+      case O2:  REQUIRE_TOKEN( token::end_object, t );
+                return true;
+
+      // <Member> ::= <Pair> [ ',' <Member> ]
+      case M0:  PUSH_STATE( M1 );
+                GOTO_STATE( P0 );
+      case M1:  if ( MATCHES_TOKEN( token::value_separator, t ) ) {
+                  PUSH_STATE( M0 );
+                  return true;
+                }
+                POP_STATE();
+                continue;
+
+      // <Pair> ::= <String> ':' <Value>
+      case P0:  REQUIRE_TOKEN( token::string, t );
+                PUSH_STATE( P1 );
+                return true;
+      case P1:  REQUIRE_TOKEN( token::name_separator, t );
+                PUSH_STATE( V0 );
+                return true;
+
+      // <Value> ::= <Array> | <Object> | <String> | <Number>
+      //           | false | null | true
+      case V0:  switch ( PEEK_TOKEN() ) {
+                  case token::begin_array:
+                    GOTO_STATE( A0 );
+                  case token::begin_object:
+                    GOTO_STATE( O0 );
+                  case token::string:
+                  case token::number:
+                  case token::json_false:
+                  case token::json_null:
+                  case token::json_true:
+                    GET_TOKEN( t );
+                    return true;
+                  default:
+                    THROW_UNEXPECTED_TOKEN( peeked_token_ );
+                }
+    } // switch ( state_ )
+  } // while
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace json
+} // namespace zorba
+
+/* vim:set et sw=2 ts=2: */

=== added file 'src/util/json_parser.h'
--- src/util/json_parser.h	1970-01-01 00:00:00 +0000
+++ src/util/json_parser.h	2012-01-23 00:53:27 +0000
@@ -0,0 +1,561 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed 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.
+ */
+
+#ifndef ZORBA_JSON_PARSER_H
+#define ZORBA_JSON_PARSER_H
+
+#include <zorba/config.h>
+
+#include <exception>
+#include <iostream>
+#include <stack>
+#include <string>
+
+#include <zorba/internal/diagnostic.h>
+
+#include "zorbatypes/zstring.h"
+
+#include "cxx_util.h"
+#include "unicode_util.h"
+
+namespace zorba {
+namespace json {
+
+///////////////////////////////////////////////////////////////////////////////
+
+typedef internal::diagnostic::location location;
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A JSON %type is the type of JSON data.  This isn't used by the lexer or
+ * parser implementation at all, but it's handy.
+ */
+enum type {
+  none,   // meaning "not set" as opposed to "null"
+  array,
+  boolean,
+  null,
+  number,
+  object,
+  string
+};
+extern char const *const type_string_of[];
+
+inline std::ostream& operator<<( std::ostream &o, type t ) {
+  return o << type_string_of[ t ];
+}
+
+/**
+ * A JSON %token.  Tokens have a type, location at which they were found, and
+ * sometimes a value.
+ *
+ * See: "RFC 4627: The application/json Media Type for JavaScript Object
+ * Notation (JSON)."
+ */
+class token {
+  // see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2333.html
+  struct pointer_conversion { int valid; };
+  typedef int pointer_conversion::*explicit_bool;
+public:
+  typedef zstring value_type;
+
+  /**
+   * The types of tokens in JSON.  The first 6 constants have values that
+   * correspond to the actual structural characters used by JSON; the rest were
+   * assigned non-standard, mnemonic values for convenience.
+   */
+  enum type {
+    none,
+    begin_array     = '[',
+    begin_object    = '{',
+    end_array       = ']',
+    end_object      = '}',
+    name_separator  = ':',
+    value_separator = ',',
+    string          = 'S',
+    number          = 'N',
+    json_false      = 'F',
+    json_null       = '0',
+    json_true       = 'T',
+  };
+
+  /**
+   * Default constructor.
+   */
+  token();
+
+  /**
+   * Clears this %token.
+   */
+  void clear() {
+    type_ = none;
+    value_.clear();
+  }
+
+  /**
+   * Gets the location at which this %token was found.
+   *
+   * @return Returns said location.
+   */
+  location const& get_loc() const {
+    return loc_;
+  }
+
+  /**
+   * Gets the type of this %token.
+   *
+   * @return Returns said type.
+   */
+  type get_type() const {
+    return type_;
+  }
+
+  /**
+   * Gets the value of this %token, if any.  Only %token types string, number,
+   * false, null, and true have a value.
+   *
+   * @return Returns said value or the empty string.
+   */
+  value_type const& get_value() const {
+    return value_;
+  }
+
+  /**
+   * Conversion to \c bool.
+   *
+   * @return Returns \c true only if this token's type is not \c none.
+   */
+  operator explicit_bool() const {
+    return type_ ? &pointer_conversion::valid : nullptr;
+  }
+
+private:
+  location loc_;
+  type type_;
+  value_type value_;
+
+  friend class lexer;
+};
+
+/**
+ * Map a token's type to a JSON type.
+ *
+ * @param tt The token::type to map.
+ * @return Returns the corresponding JSON type or \c none if \a tt doesn't map.
+ */
+type map_type( token::type tt );
+
+/**
+ * Emits the given token type to an ostream.
+ *
+ * @param o The ostream to emit to.
+ * @param tt The token type to emit.
+ * @return Returns \a o.
+ */
+std::ostream& operator<<( std::ostream &o, token::type tt );
+
+/**
+ * Emits the given token to an ostream.
+ *
+ * @param o The ostream to emit to.
+ * @param t The token to emit.
+ * @return Returns \a o.
+ */
+std::ostream& operator<<( std::ostream &o, token const &t );
+
+/**
+ * Compares two tokens for equality.
+ *
+ * @param t1 The first token.
+ * @param t2 The second token.
+ * @return Returns \c true only if the two tokens' types and values are equal.
+ */
+inline bool operator==( token const &t1, token const &t2 ) {
+  return t1.get_type() == t2.get_type() && t1.get_value() == t2.get_value();
+}
+
+/**
+ * Compares a token's type to another type for equality.
+ *
+ * @param t The token whose type to compare.
+ * @param tt The type to compare to.
+ * @return Returns \c true only if the token's type equals \a tt.
+ */
+inline bool operator==( token const &t, token::type tt ) {
+  return t.get_type() == tt;
+}
+
+/**
+ * Compares a token's type to another type for equality.
+ *
+ * @param tt The type to compare.
+ * @param t The token whose type to compare to.
+ * @return Returns \c true only if \a tt equals the token's type.
+ */
+inline bool operator==( token::type tt, token const &t ) {
+  return t == tt;
+}
+
+/**
+ * Compares a token's value to a C string for equality.
+ *
+ * @param t The token whose value to compare.
+ * @param value The value to compare to.
+ * @return Returns \c true only if the token's value equals \a value.
+ */
+inline bool operator==( token const &t, char const *value ) {
+  return t.get_value() == value;
+}
+
+/**
+ * Compares a C string to a token's value for equality.
+ *
+ * @param value The value to compare.
+ * @param t The token whose value to compare to.
+ * @return Returns \c true only if \a value equals the token's value.
+ */
+inline bool operator==( char const *value, token const &t ) {
+  return t == value;
+}
+
+/**
+ * Compares two tokens for inequality.
+ *
+ * @param t1 The first token.
+ * @param t2 The second token.
+ * @return Returns \c true if either the two tokens' types or values are not
+ * equal.
+ */
+inline bool operator!=( token const &t1, token const &t2 ) {
+  return !(t1 == t2);
+}
+
+/**
+ * Compares a token's type to another type for inequality.
+ *
+ * @param t The token whose type to compare.
+ * @param tt The type to compare to.
+ * @return Returns \c true only if the token's type is not equal to \a tt.
+ */
+inline bool operator!=( token const &t, token::type tt ) {
+  return !(t == tt);
+}
+
+/**
+ * Compares a token's type to another type for inequality.
+ *
+ * @param tt The type to compare.
+ * @param t The token whose type to compare to.
+ * @return Returns \c true only if \a tt is not equal to the token's type.
+ */
+inline bool operator!=( token::type tt, token const &t ) {
+  return !(tt == t);
+}
+
+/**
+ * Compares a token's value to a C string for inequality.
+ *
+ * @param t The token whose value to compare.
+ * @param value The value to compare to.
+ * @return Returns \c true only if the token's value is not equal to \a value.
+ */
+inline bool operator!=( token const &t, char const *value ) {
+  return !(t == value);
+}
+
+/**
+ * Compares a token's value to a C string for inequality.
+ *
+ * @param value The value to compare.
+ * @param t The token whose value to compare to.
+ * @return Returns \c true only if \a value is not equal to the token's value.
+ */
+inline bool operator!=( char const *value, token const &t ) {
+  return !(value == t);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * An %exception is the root of the JSON %exception hierarchy.
+ */
+class exception : public std::exception {
+public:
+  ~exception() throw();
+
+  /**
+   * Gets the location in the JSON source whence this exception was thrown.
+   */
+  location const& get_loc() const {
+    return loc_;
+  }
+
+  // inherited
+  char const* what() const throw();
+
+protected:
+  exception( location const &loc, std::string const &message );
+
+private:
+  location loc_;
+  std::string message_;
+};
+
+/**
+ * This exception is thrown when an illegal character is encountered in a JSON
+ * data stream.
+ */
+class illegal_character : public exception {
+public:
+  illegal_character( location const &loc, char c );
+  ~illegal_character() throw();
+
+  /**
+   * Gets the illegal character.
+   *
+   * @return Returns said character.
+   */
+  char get_char() const {
+    return c_;
+  }
+
+private:
+  char c_;
+};
+
+/**
+ * This exception is thrown when an illegal Unicode code-point escape sequence
+ * (\uHHHH) is encountered.
+ */
+class illegal_codepoint : public exception {
+public:
+  illegal_codepoint( location const &loc, token::value_type const &cp );
+  ~illegal_codepoint() throw();
+
+  /**
+   * Gets the illegal code-point.
+   *
+   * @return Returns said code-point.
+   */
+  token::value_type get_codepoint() const {
+    return codepoint_;
+  }
+
+private:
+  token::value_type codepoint_;
+};
+
+/**
+ * This exception is thrown when an illegal character follows a backslash
+ * (escape) within a string literal.  The legal escape characters are:
+ * ["/\bfnrtu].
+ */
+class illegal_escape : public exception {
+public:
+  illegal_escape( location const &loc, char escape );
+  ~illegal_escape() throw();
+
+  /**
+   * Gets the illegal escape character.
+   *
+   * @return Returns said character.
+   */
+  char get_escape() const {
+    return esc_;
+  }
+
+private:
+  char esc_;
+};
+
+/**
+ * This exception is thrown when a literal other than \c false, \c null, or
+ * \c true is encountered.
+ */
+class illegal_literal : public exception {
+public:
+  illegal_literal( location const &loc );
+  ~illegal_literal() throw();
+};
+
+/**
+ * This exception is thrown when an illegal number is encountered.
+ */
+class illegal_number : public exception {
+public:
+  illegal_number( location const &loc );
+  ~illegal_number() throw();
+};
+
+/**
+ * This exception is thrown when an unexpected token is encountered.
+ */
+class unexpected_token : public exception {
+public:
+  unexpected_token( token const &t );
+  ~unexpected_token() throw();
+
+  /**
+   * Gets the unexpected token
+   *
+   * @return Returns said token.
+   */
+  token const& get_token() const {
+    return token_;
+  }
+
+private:
+  token token_;
+};
+
+/**
+ * This exception is thrown when an EOF is encountered before a string's
+ * terminating quote.
+ */
+class unterminated_string : public exception {
+public:
+  unterminated_string( location const &loc );
+  ~unterminated_string() throw();
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A %lexer extracts JSON tokens from an istream.
+ */
+class lexer {
+public:
+  typedef location::line_type line_type;
+  typedef location::column_type column_type;
+
+  /**
+   * Constructs a %lexer on the given istream.
+   *
+   * @param in The istream to read from.
+   */
+  lexer( std::istream &in );
+
+  /**
+   * Gets the next token, if any.
+   *
+   * @param result A pointer to the token to get into.
+   * @return Returns \c true only if there was a next token.
+   * @throws exception upon error.
+   */
+  bool next( token *result );
+
+  /**
+   * Sets the file location.
+   *
+   * @param file The source file name.
+   * @param line The source line number.
+   * @param col  The source column number.
+   */
+  void set_loc( char const *file, line_type line, column_type col );
+
+private:
+  location cur_loc() const {
+    return location( file_, line_, col_ );
+  }
+
+  bool get_char( char* = nullptr );
+  bool peek_char( char* );
+  unicode::code_point parse_codepoint();
+  token::type parse_literal( char, token::value_type* );
+  void parse_number( char, token::value_type* );
+  void parse_string( token::value_type* );
+
+  std::istream *in_;
+  std::string file_;
+  line_type line_;
+  column_type col_;
+  location cur_loc_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A %parser extracts JSON tokens from an istream while checking to ensure the
+ * token sequence is valid.
+ */
+class parser {
+public:
+  typedef lexer::line_type line_type;
+  typedef lexer::column_type column_type;
+
+  /**
+   * Constructs a %parser on the given istream.
+   *
+   * @param in The istream to read from.
+   */
+  parser( std::istream &in );
+
+  /**
+   * Gets the next token, if any.
+   *
+   * @param result A pointer to the token to get into.
+   * @return Returns \c true only if there was a next token.
+   * @throws exception upon error.
+   */
+  bool next( token *result );
+
+  /**
+   * Sets the file location.
+   *
+   * @param file The source file name.
+   * @param line The source line number.
+   * @param col  The source column number.
+   */
+  void set_loc( char const *file, line_type line, column_type col ) {
+    lexer_.set_loc( file, line, col );
+  }
+
+private:
+  enum state {
+    A0, A1, A2, // Array
+    E0, E1,     // Element
+    J0, J1,     // JSON
+    M0, M1,     // Member
+    O0, O1, O2, // Object
+    P0, P1,     // Pair
+    V0          // Value
+  };
+
+  friend std::ostream& operator<<( std::ostream&, state );
+
+  bool get_token( token* );
+  bool get_token_debug( int, token* );
+  bool matches_token( token::type, token* );
+  bool matches_token_debug( int, token::type, token* );
+  token::type peek_token();
+  token::type peek_token_debug( int );
+  void require_token( token::type, token* );
+  void require_token_debug( int, token::type, token* );
+
+  lexer lexer_;
+  token peeked_token_;
+  std::stack<state> state_stack_;
+  state state_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace json
+} // namespace zorba
+
+#endif /* ZORBA_JSON_PARSER_H */
+/* vim:set et sw=2 ts=2: */

=== added file 'src/util/mem_streambuf.cpp'
--- src/util/mem_streambuf.cpp	1970-01-01 00:00:00 +0000
+++ src/util/mem_streambuf.cpp	2012-01-23 00:53:27 +0000
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ * 
+ * Licensed 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.
+ */
+
+#include <cstring>                      /* for memcpy(3) */
+
+#include "diagnostics/assert.h"
+
+#include "cxx_util.h"
+#include "mem_streambuf.h"
+
+using namespace std;
+
+namespace zorba {
+
+///////////////////////////////////////////////////////////////////////////////
+
+mem_streambuf::mem_streambuf() {
+  set( nullptr, nullptr );
+}
+
+mem_streambuf::mem_streambuf( char_type *begin, char_type *end ) {
+  set( begin, end );
+}
+
+mem_streambuf::mem_streambuf( char_type *begin, off_type size ) {
+  set( begin, size );
+}
+
+mem_streambuf::int_type mem_streambuf::overflow( int_type c ) {
+  if ( traits_type::eq_int_type( c, traits_type::eof() ) )
+    return traits_type::not_eof( c );
+  if ( pptr() >= epptr() )
+    return traits_type::eof();
+  *pptr() = traits_type::to_char_type( c );
+  pbump( 1 );
+  return c;
+}
+
+mem_streambuf::int_type mem_streambuf::pbackfail( int_type c ) {
+  if ( !traits_type::eq_int_type( c, traits_type::eof() ) ) {
+    *pptr() = traits_type::to_int_type( c );
+    pbump( -1 );
+  }
+  return traits_type::to_int_type( *pptr() );
+}
+
+mem_streambuf::pos_type mem_streambuf::seekoff( off_type off,
+                                                ios_base::seekdir dir,
+                                                ios_base::openmode ) {
+  switch ( dir ) {
+    case ios_base::beg:
+      our_setg( begin_ + off );
+      break;
+    case ios_base::cur:
+      our_setg( gptr() + off );
+      break;
+    case ios_base::end:
+      our_setg( end_ + off );
+      break;
+    default:
+      ZORBA_ASSERT( false );
+  }
+  return off;
+}
+
+mem_streambuf::pos_type mem_streambuf::seekpos( pos_type pos,
+                                                ios_base::openmode mode ) {
+  return seekoff( pos, ios_base::beg, mode );
+}
+
+void mem_streambuf::set( char_type *begin, char_type *end ) {
+  begin_ = begin;
+  end_ = end;
+  our_setg( begin );
+  our_setp( end );
+}
+
+streamsize mem_streambuf::showmanyc() {
+  return egptr() - gptr();
+}
+
+mem_streambuf::int_type mem_streambuf::underflow() {
+  return gptr() < egptr() ?
+    traits_type::to_int_type( *gptr() ) : traits_type::eof();
+}
+
+streamsize mem_streambuf::xsgetn( char_type *buf, std::streamsize size ) {
+  streamsize const remaining = showmanyc();
+  if ( size > remaining )
+    size = remaining;
+  ::memcpy( buf, gptr(), size );
+  return size;
+}
+
+streamsize mem_streambuf::xsputn( char_type const *buf, streamsize size ) {
+  streamsize const remaining = epptr() - pptr();
+  if ( size > remaining )
+    size = remaining;
+  ::memcpy( pptr(), buf, size );
+  return size;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace zorba
+/* vim:set et sw=2 ts=2: */

=== added file 'src/util/mem_streambuf.h'
--- src/util/mem_streambuf.h	1970-01-01 00:00:00 +0000
+++ src/util/mem_streambuf.h	2012-01-23 00:53:27 +0000
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ * 
+ * Licensed 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.
+ */
+
+#ifndef ZORBA_MMAP_STREAMBUF_H
+#define ZORBA_MMAP_STREAMBUF_H
+
+#include <streambuf>
+
+namespace zorba {
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A %mem_streambuf is-a std::streambuf for a fixed-size chunk of memory.
+ */
+class mem_streambuf : public std::streambuf {
+public:
+  typedef std::streambuf::char_type char_type;
+  typedef std::streambuf::int_type int_type;
+  typedef std::streambuf::off_type off_type;
+  typedef std::streambuf::pos_type pos_type;
+  typedef std::streambuf::traits_type traits_type;
+
+  /**
+   * Default constructor.
+   */
+  mem_streambuf();
+
+  /**
+   * Constructs a %mem_streambuf.
+   *
+   * @param begin A pointer to the beginning of the memory chunk.
+   * @param end A pointer to one past the end of the memory chunk.
+   */
+  mem_streambuf( char_type *begin, char_type *end );
+
+  /**
+   * Constructs a %mem_streambuf.
+   *
+   * @param begin A pointer to the beginning of the memory chunk.
+   * @param size The size of the memory chunk.
+   */
+  mem_streambuf( char_type *begin, off_type size );
+
+  /**
+   * Sets the memory chunk.
+   *
+   * @param begin A pointer to the beginning of the memory chunk.
+   * @param end A pointer to one past the end of the memory chunk.
+   */
+  void set( char_type *begin, char_type *end );
+
+  /**
+   * Sets the memory chunk.
+   *
+   * @param begin A pointer to the beginning of the memory chunk.
+   * @param size The size of the memory chunk.
+   */
+  void set( char_type *begin, off_type size );
+
+protected:
+  int_type overflow( int_type c );
+  int_type pbackfail( int_type c );
+  pos_type seekoff( off_type, std::ios_base::seekdir, std::ios_base::openmode );
+  pos_type seekpos( pos_type, std::ios_base::openmode  );
+  std::streamsize showmanyc();
+  int_type underflow();
+  std::streamsize xsgetn( char_type*, std::streamsize );
+  std::streamsize xsputn( char_type const*, std::streamsize );
+
+private:
+  char_type *begin_, *end_;
+
+  void our_setg( char_type *ptr ) {
+    setg( begin_, ptr, end_ );
+  }
+
+  void our_setp( char_type *ptr ) {
+    setp( ptr, end_ );
+  }
+
+  // forbid
+  mem_streambuf( mem_streambuf const& );
+  mem_streambuf& operator=( mem_streambuf const& );
+};
+
+inline void mem_streambuf::set( char_type *begin, off_type size ) {
+  set( begin, begin + size );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace zorba
+#endif  /* ZORBA_MMAP_STREAMBUF_H */
+/* vim:set et sw=2 ts=2: */

=== modified file 'src/util/omanip.h'
--- src/util/omanip.h	2011-06-14 17:26:33 +0000
+++ src/util/omanip.h	2012-01-23 00:53:27 +0000
@@ -25,127 +25,275 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 /**
- * An omanip1 is a class for assisting in the creation of ostream manipulators
+ * An %omanip1 is a class for assisting in the creation of ostream manipulators
  * by storing a pointer to a function and its argument to be called later via
  * operator<<().
  *
  * See also: "Standard C++ IOStreams and Locales," Angelika Langer and Klaus
  * Kreft, Addison-Wesley, pp. 179-191.
  */
-template<typename Arg1Type> class omanip1 {
+template<typename Arg1Type>
+class omanip1 {
 public:
 
   /**
-   * The signature of functions this omanip1 can handle.
+   * The signature of functions this %omanip1 can handle.
    */
   typedef std::ostream& (*func_type)( std::ostream&, Arg1Type );
 
   /**
-   * Constructs an omanip1.
+   * Constructs an %omanip1.
    *
-   * @param f     The function to call when this omanip1 is inserted into an
-   *              ostream.
-   * @param arg1  The argument to be passed to the function.
+   * @param f   The function to call when this %omanip1 is inserted into an
+   *            ostream.
+   * @param a1  The argument to be passed to the function.
    */
-  omanip1( func_type f, Arg1Type arg1 ) :
-    f_( f ), arg1_( arg1 )
+  omanip1( func_type f, Arg1Type a1 ) :
+    f_( f ), a1_( a1 )
   {
   }
 
   /**
-   * Inserts the given omanip1 into the given ostream.  This has the effect of
-   * calling the function and argument bound to the omanip1 at the time of its
+   * Inserts the given %omanip1 into the given ostream.  This has the effect of
+   * calling the function and argument bound to the %omanip1 at the time of its
    * construction.
    *
    * @param o The ostream to insert into.
-   * @param m The omanip1 to insert.
+   * @param m The %omanip1 to insert.
    */
   friend std::ostream& operator<<( std::ostream &o, omanip1 const &m ) {
-    return (*m.f_)( o, m.arg1_ );
+    if ( o.good() )
+      (*m.f_)( o, m.a1_ );
+    return o;
   }
 
 private:
   func_type const f_;
-  Arg1Type const arg1_;
+  Arg1Type const a1_;
 };
 
 /**
  * Defines an ostream manipulator "thunk" function that calls an existing
  * non-manipulator function having the same name.
  *
- * @param FN_NAME   The name of the existing function.
- * @param ARG1_TYPE The type of the non-ostream argument.
- * @param ARG1_NAME The name of the non-ostream argument.
+ * @param FN_NAME The name of the existing function.
+ * @param ARG1_T  The type of the non-ostream argument.
  */
-#define DEF_OMANIP1(FN_NAME,ARG1_TYPE,ARG1_NAME)      \
-  inline omanip1<ARG1_TYPE>                           \
-  FN_NAME( ARG1_TYPE ARG1_NAME ) {                    \
-    return omanip1<ARG1_TYPE>( FN_NAME, ARG1_NAME );  \
+#define DEF_OMANIP1(FN_NAME,ARG1_T)        \
+  inline omanip1<ARG1_T>                   \
+  FN_NAME( ARG1_T a1 ) {                   \
+    return omanip1<ARG1_T>( FN_NAME, a1 ); \
   }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 /**
- * An omanip2 is a class for assisting in the creation of ostream manipulators
+ * An %omanip2 is a class for assisting in the creation of ostream manipulators
  * by storing a pointer to a function and its arguments to be called later via
  * operator<<().
  *
  * See also: "Standard C++ IOStreams and Locales," Angelika Langer and Klaus
  * Kreft, Addison-Wesley, pp. 179-191.
  */
-template<typename Arg1Type, typename Arg2Type> class omanip2 {
+template<typename Arg1Type,typename Arg2Type>
+class omanip2 {
 public:
 
   /**
-   * The signature of functions this omanip2 can handle.
+   * The signature of functions this %omanip2 can handle.
    */
   typedef std::ostream& (*func_type)( std::ostream&, Arg1Type, Arg2Type );
 
   /**
-   * Constructs an omanip2.
+   * Constructs an %omanip2.
    *
-   * @param f     The function to call when this omanip2 is inserted into an
-   *              ostream.
-   * @param arg1  The first argument to be passed to the function.
-   * @param arg2  The second argument to be passed to the function.
+   * @param f   The function to call when this %omanip2 is inserted into an
+   *            ostream.
+   * @param a1  The first argument to be passed to the function.
+   * @param a2  The second argument to be passed to the function.
    */
-  omanip2( func_type f, Arg1Type arg1, Arg2Type arg2 ) :
-    f_( f ), arg1_( arg1 ), arg2_( arg2 )
+  omanip2( func_type f, Arg1Type a1, Arg2Type a2 ) :
+    f_( f ), a1_( a1 ), a2_( a2 )
   {
   }
 
   /**
-   * Inserts the given omanip2 into the given ostream.  This has the effect of
-   * calling the function and argument bound to the omanip2 at the time of its
+   * Inserts the given %omanip2 into the given ostream.  This has the effect of
+   * calling the function and argument bound to the %omanip2 at the time of its
    * construction.
    *
    * @param o The ostream to insert into.
-   * @param m The omanip2 to insert.
+   * @param m The %omanip2 to insert.
    */
   friend std::ostream& operator<<( std::ostream &o, omanip2 const &m ) {
-    return (*m.f_)( o, m.arg1_, m.arg2_ );
-  }
-
-private:
-  func_type const f_;
-  Arg1Type const arg1_;
-  Arg2Type const arg2_;
-};
-
-/**
- * Defines an ostream manipulator "thunk" function that calls an existing
- * non-manipulator function having the same name.
- *
- * @param FN_NAME   The name of the existing function.
- * @param ARG1_TYPE The type of the first non-ostream argument.
- * @param ARG1_NAME The name of the first non-ostream argument.
- * @param ARG2_TYPE The type of the second non-ostream argument.
- * @param ARG2_NAME The name of the second non-ostream argument.
- */
-#define DEF_OMANIP2(FN_NAME,ARG1_TYPE,ARG1_NAME,ARG2_TYPE,ARG2_NAME)      \
-  inline omanip2<ARG1_TYPE,ARG2_TYPE>                                     \
-  FN_NAME( ARG1_TYPE ARG1_NAME, ARG2_TYPE ARG2_NAME ) {                   \
-    return omanip2<ARG1_TYPE,ARG2_TYPE>( FN_NAME, ARG1_NAME, ARG2_NAME ); \
+    if ( o.good() )
+      (*m.f_)( o, m.a1_, m.a2_ );
+    return o;
+  }
+
+private:
+  func_type const f_;
+  Arg1Type const a1_;
+  Arg2Type const a2_;
+};
+
+/**
+ * Defines an ostream manipulator "thunk" function that calls an existing
+ * non-manipulator function having the same name.
+ *
+ * @param FN_NAME The name of the existing function.
+ * @param ARG1_T  The type of the first non-ostream argument.
+ * @param ARG2_T  The type of the second non-ostream argument.
+ */
+#define DEF_OMANIP2(FN_NAME,ARG1_T,ARG2_T)            \
+  inline omanip2<ARG1_T,ARG2_T>                       \
+  FN_NAME( ARG1_T a1, ARG2_T a2 ) {                   \
+    return omanip2<ARG1_T,ARG2_T>( FN_NAME, a1, a2 ); \
+  }
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * An %omanip3 is a class for assisting in the creation of ostream manipulators
+ * by storing a pointer to a function and its arguments to be called later via
+ * operator<<().
+ *
+ * See also: "Standard C++ IOStreams and Locales," Angelika Langer and Klaus
+ * Kreft, Addison-Wesley, pp. 179-191.
+ */
+template<typename Arg1Type,typename Arg2Type,typename Arg3Type>
+class omanip3 {
+public:
+
+  /**
+   * The signature of functions this %omanip3 can handle.
+   */
+  typedef std::ostream& (*func_type)( std::ostream&, Arg1Type, Arg2Type,
+                                      Arg3Type );
+
+  /**
+   * Constructs an %omanip3.
+   *
+   * @param f   The function to call when this %omanip3 is inserted into an
+   *            ostream.
+   * @param a1  The first argument to be passed to the function.
+   * @param a2  The second argument to be passed to the function.
+   * @param a3  The third argument to be passed to the function.
+   */
+  omanip3( func_type f, Arg1Type a1, Arg2Type a2, Arg3Type a3 ) :
+    f_( f ), a1_( a1 ), a2_( a2 ), a3_( a3 )
+  {
+  }
+
+  /**
+   * Inserts the given %omanip3 into the given ostream.  This has the effect of
+   * calling the function and argument bound to the %omanip3 at the time of its
+   * construction.
+   *
+   * @param o The ostream to insert into.
+   * @param m The %omanip3 to insert.
+   */
+  friend std::ostream& operator<<( std::ostream &o, omanip3 const &m ) {
+    if ( o.good() )
+      (*m.f_)( o, m.a1_, m.a2_, m.a3_ );
+    return o;
+  }
+
+private:
+  func_type const f_;
+  Arg1Type const a1_;
+  Arg2Type const a2_;
+  Arg3Type const a3_;
+};
+
+/**
+ * Defines an ostream manipulator "thunk" function that calls an existing
+ * non-manipulator function having the same name.
+ *
+ * @param FN_NAME The name of the existing function.
+ * @param ARG1_T  The type of the first non-ostream argument.
+ * @param ARG2_T  The type of the second non-ostream argument.
+ * @param ARG3_T  The type of the third non-ostream argument.
+ */
+#define DEF_OMANIP3(FN_NAME,ARG1_T,ARG2_T,ARG3_T)                \
+  inline omanip3<ARG1_T,ARG2_T,ARG3_T>                           \
+  FN_NAME( ARG1_T a1, ARG2_T a2, ARG3_T a3 ) {                   \
+    return omanip3<ARG1_T,ARG2_T,ARG3_T>( FN_NAME, a1, a2, a3 ); \
+  }
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * An %omanip4 is a class for assisting in the creation of ostream manipulators
+ * by storing a pointer to a function and its arguments to be called later via
+ * operator<<().
+ *
+ * See also: "Standard C++ IOStreams and Locales," Angelika Langer and Klaus
+ * Kreft, Addison-Wesley, pp. 179-191.
+ */
+template<
+  typename Arg1Type,typename Arg2Type,typename Arg3Type,typename Arg4Type
+>
+class omanip4 {
+public:
+
+  /**
+   * The signature of functions this %omanip4 can handle.
+   */
+  typedef std::ostream& (*func_type)( std::ostream&, Arg1Type, Arg2Type,
+                                      Arg3Type, Arg4Type );
+
+  /**
+   * Constructs an %omanip4.
+   *
+   * @param f   The function to call when this %omanip4 is inserted into an
+   *            ostream.
+   * @param a1  The first argument to be passed to the function.
+   * @param a2  The second argument to be passed to the function.
+   * @param a3  The third argument to be passed to the function.
+   * @param a4  The fourth argument to be passed to the function.
+   */
+  omanip4( func_type f, Arg1Type a1, Arg2Type a2, Arg3Type a3, Arg4Type a4 ) :
+    f_( f ), a1_( a1 ), a2_( a2 ), a3_( a3 ), a4_( a4 )
+  {
+  }
+
+  /**
+   * Inserts the given %omanip4 into the given ostream.  This has the effect of
+   * calling the function and argument bound to the %omanip4 at the time of its
+   * construction.
+   *
+   * @param o The ostream to insert into.
+   * @param m The %omanip4 to insert.
+   */
+  friend std::ostream& operator<<( std::ostream &o, omanip4 const &m ) {
+    if ( o.good() )
+      (*m.f_)( o, m.a1_, m.a2_, m.a3_, m.a4_ );
+    return o;
+  }
+
+private:
+  func_type const f_;
+  Arg1Type const a1_;
+  Arg2Type const a2_;
+  Arg3Type const a3_;
+  Arg4Type const a4_;
+};
+
+/**
+ * Defines an ostream manipulator "thunk" function that calls an existing
+ * non-manipulator function having the same name.
+ *
+ * @param FN_NAME The name of the existing function.
+ * @param ARG1_T  The type of the first non-ostream argument.
+ * @param ARG2_T  The type of the second non-ostream argument.
+ * @param ARG3_T  The type of the third non-ostream argument.
+ * @param ARG4_T  The type of the fourth non-ostream argument.
+ */
+#define DEF_OMANIP4(FN_NAME,ARG1_T,ARG2_T,ARG3_T,ARG4_T)                    \
+  inline omanip4<ARG1_T,ARG2_T,ARG3_T,ARG4_T>                               \
+  FN_NAME( ARG1_T a1, ARG2_T a2, ARG3_T a3, ARG4_T a4 ) {                   \
+    return omanip4<ARG1_T,ARG2_T,ARG3_T,ARG4_T>( FN_NAME, a1, a2, a3, a4 ); \
   }
 
 ///////////////////////////////////////////////////////////////////////////////

=== modified file 'src/util/oseparator.h'
--- src/util/oseparator.h	2011-06-14 17:26:33 +0000
+++ src/util/oseparator.h	2012-01-23 00:53:27 +0000
@@ -40,10 +40,22 @@
   }
 
   /**
-   * Reset's the state.
-   */
-  void reset() {
-    print_ = false;
+   * Gets the printing state of this %oseparator.
+   *
+   * @return Returns \c true only if this %oseparator is currently printing.
+   */
+  bool printing() const {
+    return print_;
+  }
+
+  /**
+   * Manually set the printing state.
+   *
+   * @state If \c true, the separator will always print; if \c false, the
+   * separator will not print only the next time it is emitted.
+   */
+  void printing( bool state ) {
+    print_ = state;
   }
 
   /**
@@ -88,7 +100,7 @@
     if ( sep.print_ )
       o << sep.sep_;
     else
-      sep.print_ = true;
+      sep.printing( true );
     return o;
   }
 

=== added directory 'test/rbkt/ExpQueryResults/zorba/json'
=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-01.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-01.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-01.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+<li>list item</li>

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-02.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-02.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-02.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,4 @@
+<ul>
+  <li>list item 1</li>
+  <li>list item 2</li>
+</ul>

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-03.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-03.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-03.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+<file dir="/tmp" name="foo" size="1234" modified="2006-12-31T23:59"/>

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-wikipedia.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-wikipedia.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-wikipedia.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,10 @@
+<person created="2006-11-11T19:23" modified="2006-12-31T23:59">
+  <firstName>Robert</firstName>
+  <lastName>Smith</lastName>
+  <address type="home">
+    <street>12345 Sixth Ave</street>
+    <city>Anytown</city>
+    <state>CA</state>
+    <postalCode>98765-4321</postalCode>
+  </address>
+</person>

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-01.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-01.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-01.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+["li","list item"]

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-02.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-02.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-02.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+["ul",["li","list item 1"],["li","list item 2"]]

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-03.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-03.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-03.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+["file",{"dir":"/tmp","name":"foo","size":"1234","modified":"2006-12-31T23:59"}]

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-indent-wikipedia.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-indent-wikipedia.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-indent-wikipedia.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,11 @@
+[ "person", 
+  { "created" : "2006-11-11T19:23",
+    "modified" : "2006-12-31T23:59" }, 
+  [ "firstName", "Robert" ], 
+  [ "lastName", "Smith" ], 
+  [ "address", 
+    { "type" : "home" }, 
+    [ "street", "12345 Sixth Ave" ], 
+    [ "city", "Anytown" ], 
+    [ "state", "CA" ], 
+    [ "postalCode", "98765-4321" ] ] ]

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-none-wikipedia.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-none-wikipedia.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-none-wikipedia.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+["person",{"created":"2006-11-11T19:23","modified":"2006-12-31T23:59"},["firstName","Robert"],["lastName","Smith"],["address",{"type":"home"},["street","12345 Sixth Ave"],["city","Anytown"],["state","CA"],["postalCode","98765-4321"]]]

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-some-wikipedia.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-some-wikipedia.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-some-wikipedia.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+[ "person", { "created" : "2006-11-11T19:23", "modified" : "2006-12-31T23:59" }, [ "firstName", "Robert" ], [ "lastName", "Smith" ], [ "address", { "type" : "home" }, [ "street", "12345 Sixth Ave" ], [ "city", "Anytown" ], [ "state", "CA" ], [ "postalCode", "98765-4321" ] ] ]

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-01.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-01.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-01.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,3 @@
+<json xmlns="http://john.snelson.org.uk/parsing-json-into-xquery"; type="array">
+  <item type="boolean">true</item>
+</json>

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-02.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-02.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-02.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,3 @@
+<json xmlns="http://john.snelson.org.uk/parsing-json-into-xquery"; type="array">
+  <item type="boolean">false</item>
+</json>

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-03.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-03.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-03.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,3 @@
+<json xmlns="http://john.snelson.org.uk/parsing-json-into-xquery"; type="array">
+  <item type="null"/>
+</json>

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-04.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-04.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-04.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,3 @@
+<json xmlns="http://john.snelson.org.uk/parsing-json-into-xquery"; type="array">
+  <item type="number">1</item>
+</json>

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-05.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-05.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-05.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,4 @@
+<json xmlns="http://john.snelson.org.uk/parsing-json-into-xquery"; type="array">
+  <item type="number">1</item>
+  <item type="number">2</item>
+</json>

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-example.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-example.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-example.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,14 @@
+<json xmlns="http://john.snelson.org.uk/parsing-json-into-xquery"; type="object">
+  <pair name="firstName" type="string">John</pair>
+  <pair name="lastName" type="string">Smith</pair>
+  <pair name="address" type="object">
+    <pair name="streetAddress" type="string">21 2nd Street</pair>
+    <pair name="city" type="string">New York</pair>
+    <pair name="state" type="string">NY</pair>
+    <pair name="postalCode" type="number">10021</pair>
+  </pair>
+  <pair name="phoneNumbers" type="array">
+    <item type="string">212 732-1234</item>
+    <item type="string">646 123-4567</item>
+  </pair>
+</json>

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-object-01.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-object-01.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-object-01.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,3 @@
+<json xmlns="http://john.snelson.org.uk/parsing-json-into-xquery"; type="object">
+  <pair name="a" type="number">1</pair>
+</json>

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-object-02.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-object-02.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-object-02.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,4 @@
+<json xmlns="http://john.snelson.org.uk/parsing-json-into-xquery"; type="object">
+  <pair name="a" type="number">1</pair>
+  <pair name="b" type="number">2</pair>
+</json>

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-01.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-01.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-01.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+[true]

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-02.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-02.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-02.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+[false]

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-03.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-03.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-03.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+[null]

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-04.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-04.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-04.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+[1]

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-05.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-05.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-05.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+[1,2]

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-indent-example.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-indent-example.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-indent-example.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,11 @@
+{
+  "firstName" : "John",
+  "lastName" : "Smith",
+  "address" : {
+    "streetAddress" : "21 2nd Street",
+    "city" : "New York",
+    "state" : "NY",
+    "postalCode" : 10021
+  },
+  "phoneNumbers" : [ "212 732-1234", "646 123-4567" ]
+}

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-none-example.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-none-example.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-none-example.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+{"firstName":"John","lastName":"Smith","address":{"streetAddress":"21 2nd Street","city":"New York","state":"NY","postalCode":10021},"phoneNumbers":["212 732-1234","646 123-4567"]}

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-object-01.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-object-01.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-object-01.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+{"a":1}

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-object-02.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-object-02.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-object-02.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+{"a":1,"b":2}

=== added file 'test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-some-example.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-some-example.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-some-example.xml.res	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+{ "firstName" : "John", "lastName" : "Smith", "address" : { "streetAddress" : "21 2nd Street", "city" : "New York", "state" : "NY", "postalCode" : 10021 }, "phoneNumbers" : [ "212 732-1234", "646 123-4567" ] }

=== added directory 'test/rbkt/Queries/zorba/json'
=== added file 'test/rbkt/Queries/zorba/json/json-jsonml_array-parse-01.xq'
--- test/rbkt/Queries/zorba/json/json-jsonml_array-parse-01.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-jsonml_array-parse-01.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,9 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json := '[ "li", "list item" ]'
+let $options :=
+  <options xmlns="http://www.zorba-xquery.com/modules/converters/json-options";>
+    <json-format value="JsonML-array"/>
+  </options>
+return json:parse( $json, $options )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-jsonml_array-parse-02.xq'
--- test/rbkt/Queries/zorba/json/json-jsonml_array-parse-02.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-jsonml_array-parse-02.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,14 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json := '
+  [ "ul",
+    [ "li", "list item 1" ],
+    [ "li", "list item 2" ]
+  ]
+'
+let $options :=
+  <options xmlns="http://www.zorba-xquery.com/modules/converters/json-options";>
+    <json-format value="JsonML-array"/>
+  </options>
+return json:parse( $json, $options )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-jsonml_array-parse-03.xq'
--- test/rbkt/Queries/zorba/json/json-jsonml_array-parse-03.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-jsonml_array-parse-03.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,18 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json := '
+  [ "file",
+    {
+      "dir" : "/tmp",
+      "name" : "foo",
+      "size" : 1234,
+      "modified" : "2006-12-31T23:59"
+    }
+  ]
+'
+let $options :=
+  <options xmlns="http://www.zorba-xquery.com/modules/converters/json-options";>
+    <json-format value="JsonML-array"/>
+  </options>
+return json:parse( $json, $options )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-jsonml_array-parse-wikipedia.xq'
--- test/rbkt/Queries/zorba/json/json-jsonml_array-parse-wikipedia.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-jsonml_array-parse-wikipedia.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,23 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json := '
+  [ "person",
+    { "created" : "2006-11-11T19:23",
+      "modified" : "2006-12-31T23:59" },
+    [ "firstName", "Robert" ],
+    [ "lastName", "Smith" ],
+    [ "address",
+      { "type" : "home" },
+      [ "street", "12345 Sixth Ave" ],
+      [ "city", "Anytown" ],
+      [ "state", "CA" ],
+      [ "postalCode", "98765-4321" ]
+    ]
+  ]
+'
+let $options :=
+  <options xmlns="http://www.zorba-xquery.com/modules/converters/json-options";>
+    <json-format value="JsonML-array"/>
+  </options>
+return json:parse( $json, $options )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-01.xq'
--- test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-01.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-01.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,10 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <li>list item</li>
+let $options :=
+  <options xmlns="http://www.zorba-xquery.com/modules/converters/json-options";>
+    <json-format value="JsonML-array"/>
+  </options>
+return json:serialize( $json, $options )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-02.xq'
--- test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-02.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-02.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,13 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <ul>
+    <li>list item 1</li>
+    <li>list item 2</li>
+  </ul>
+let $options :=
+  <options xmlns="http://www.zorba-xquery.com/modules/converters/json-options";>
+    <json-format value="JsonML-array"/>
+  </options>
+return json:serialize( $json, $options )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-03.xq'
--- test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-03.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-03.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,10 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <file dir="/tmp" name="foo" size="1234" modified="2006-12-31T23:59"/>
+let $options :=
+  <options xmlns="http://www.zorba-xquery.com/modules/converters/json-options";>
+    <json-format value="JsonML-array"/>
+  </options>
+return json:serialize( $json, $options )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-indent-wikipedia.xq'
--- test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-indent-wikipedia.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-indent-wikipedia.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,20 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <person created="2006-11-11T19:23" modified="2006-12-31T23:59">
+    <firstName>Robert</firstName>
+    <lastName>Smith</lastName>
+    <address type="home">
+      <street>12345 Sixth Ave</street>
+      <city>Anytown</city>
+      <state>CA</state>
+      <postalCode>98765-4321</postalCode>
+    </address>
+  </person>
+let $options :=
+  <options xmlns="http://www.zorba-xquery.com/modules/converters/json-options";>
+    <json-format value="JsonML-array"/>
+    <whitespace value="indent"/>
+  </options>
+return json:serialize( $json, $options )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-none-wikipedia.xq'
--- test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-none-wikipedia.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-none-wikipedia.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,19 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <person created="2006-11-11T19:23" modified="2006-12-31T23:59">
+    <firstName>Robert</firstName>
+    <lastName>Smith</lastName>
+    <address type="home">
+      <street>12345 Sixth Ave</street>
+      <city>Anytown</city>
+      <state>CA</state>
+      <postalCode>98765-4321</postalCode>
+    </address>
+  </person>
+let $options :=
+  <options xmlns="http://www.zorba-xquery.com/modules/converters/json-options";>
+    <json-format value="JsonML-array"/>
+  </options>
+return json:serialize( $json, $options )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-some-wikipedia.xq'
--- test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-some-wikipedia.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-some-wikipedia.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,20 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <person created="2006-11-11T19:23" modified="2006-12-31T23:59">
+    <firstName>Robert</firstName>
+    <lastName>Smith</lastName>
+    <address type="home">
+      <street>12345 Sixth Ave</street>
+      <city>Anytown</city>
+      <state>CA</state>
+      <postalCode>98765-4321</postalCode>
+    </address>
+  </person>
+let $options :=
+  <options xmlns="http://www.zorba-xquery.com/modules/converters/json-options";>
+    <json-format value="JsonML-array"/>
+    <whitespace value="some"/>
+  </options>
+return json:serialize( $json, $options )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-parse-array-01.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-parse-array-01.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-parse-array-01.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,5 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json := '[ true ]'
+return json:parse( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-parse-array-02.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-parse-array-02.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-parse-array-02.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,5 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json := '[ false ]'
+return json:parse( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-parse-array-03.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-parse-array-03.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-parse-array-03.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,5 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json := '[ null ]'
+return json:parse( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-parse-array-04.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-parse-array-04.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-parse-array-04.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,5 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json := '[ 1 ]'
+return json:parse( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-parse-array-05.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-parse-array-05.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-parse-array-05.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,5 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json := '[ 1, 2 ]'
+return json:parse( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-parse-example.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-parse-example.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-parse-example.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,20 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json := '
+  {
+    "firstName": "John",
+    "lastName": "Smith",
+    "address": {
+      "streetAddress": "21 2nd Street",
+      "city": "New York",
+      "state": "NY",
+      "postalCode": 10021
+    },
+    "phoneNumbers": [
+      "212 732-1234",
+      "646 123-4567"
+    ]
+  }
+  '
+return json:parse( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-parse-object-01.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-parse-object-01.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-parse-object-01.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,5 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json := '{ "a" : 1 }'
+return json:parse( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-parse-object-02.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-parse-object-02.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-parse-object-02.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,5 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json := '{ "a" : 1, "b" : 2 }'
+return json:parse( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-01.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-01.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-01.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,8 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <json type="array">
+    <item type="boolean">true</item>
+  </json>
+return json:serialize( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-02.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-02.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-02.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,8 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <json type="array">
+    <item type="boolean">false</item>
+  </json>
+return json:serialize( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-03.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-03.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-03.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,8 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <json type="array">
+    <item type="null"/>
+  </json>
+return json:serialize( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-04.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-04.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-04.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,8 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <json type="array">
+    <item type="number">1</item>
+  </json>
+return json:serialize( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-05.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-05.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-05.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,9 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <json type="array">
+    <item type="number">1</item>
+    <item type="number">2</item>
+  </json>
+return json:serialize( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-06.spec'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-06.spec	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-06.spec	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+Error: http://www.zorba-xquery.com/errors:ZJSE0005

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-06.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-06.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-06.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,8 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <json type="array">
+    <foo type="boolean">true</foo>
+  </json>
+return json:serialize( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-07.spec'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-07.spec	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-07.spec	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+Error: http://www.zorba-xquery.com/errors:ZJSE0008

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-07.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-07.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-07.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,8 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <json type="array">
+    <item type="boolean">foo</item>
+  </json>
+return json:serialize( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-08.spec'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-08.spec	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-08.spec	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+Error: http://www.zorba-xquery.com/errors:ZJSE0002

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-08.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-08.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-08.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,8 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <json type="array">
+    <item>false</item>
+  </json>
+return json:serialize( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-09.spec'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-09.spec	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-09.spec	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+Error: http://www.zorba-xquery.com/errors:ZJSE0003

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-09.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-09.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-09.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,8 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <json type="array">
+    <item type="bool">false</item>
+  </json>
+return json:serialize( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-10.spec'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-10.spec	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-10.spec	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+Error: http://www.zorba-xquery.com/errors:ZJSE0007

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-10.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-10.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-10.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,8 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <json type="array">
+    hello
+  </json>
+return json:serialize( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-11.spec'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-11.spec	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-11.spec	2012-01-23 00:53:27 +0000
@@ -0,0 +1,1 @@
+Error: http://www.zorba-xquery.com/errors:ZJSE0006

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-array-11.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-array-11.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-array-11.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,8 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <json type="array">
+    <item type="boolean"><foo/></item>
+  </json>
+return json:serialize( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-indent-example.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-indent-example.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-indent-example.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,24 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <json type="object">
+    <pair name="firstName" type="string">John</pair>
+    <pair name="lastName" type="string">Smith</pair>
+    <pair name="address" type="object">
+      <pair name="streetAddress" type="string">21 2nd Street</pair>
+      <pair name="city" type="string">New York</pair>
+      <pair name="state" type="string">NY</pair>
+      <pair name="postalCode" type="number">10021</pair>
+    </pair>
+    <pair name="phoneNumbers" type="array">
+      <item type="string">212 732-1234</item>
+      <item type="string">646 123-4567</item>
+    </pair>
+  </json>
+let $options :=
+  <options xmlns="http://www.zorba-xquery.com/modules/converters/json-options";>
+    <json-format value="Snelson"/>
+    <whitespace value="indent"/>
+  </options>
+return json:serialize( $json, $options )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-none-example.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-none-example.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-none-example.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,19 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <json type="object">
+    <pair name="firstName" type="string">John</pair>
+    <pair name="lastName" type="string">Smith</pair>
+    <pair name="address" type="object">
+      <pair name="streetAddress" type="string">21 2nd Street</pair>
+      <pair name="city" type="string">New York</pair>
+      <pair name="state" type="string">NY</pair>
+      <pair name="postalCode" type="number">10021</pair>
+    </pair>
+    <pair name="phoneNumbers" type="array">
+      <item type="string">212 732-1234</item>
+      <item type="string">646 123-4567</item>
+    </pair>
+  </json>
+return json:serialize( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-object-01.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-object-01.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-object-01.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,8 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <json type="object">
+    <pair name="a" type="number">1</pair>
+  </json>
+return json:serialize( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-object-02.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-object-02.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-object-02.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,9 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <json type="object">
+    <pair name="a" type="number">1</pair>
+    <pair name="b" type="number">2</pair>
+  </json>
+return json:serialize( $json )
+(: vim:set et sw=2 ts=2: :)

=== added file 'test/rbkt/Queries/zorba/json/json-snelson-serialize-some-example.xq'
--- test/rbkt/Queries/zorba/json/json-snelson-serialize-some-example.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json/json-snelson-serialize-some-example.xq	2012-01-23 00:53:27 +0000
@@ -0,0 +1,24 @@
+import module namespace json = "http://www.zorba-xquery.com/modules/converters/json";;
+
+let $json :=
+  <json type="object">
+    <pair name="firstName" type="string">John</pair>
+    <pair name="lastName" type="string">Smith</pair>
+    <pair name="address" type="object">
+      <pair name="streetAddress" type="string">21 2nd Street</pair>
+      <pair name="city" type="string">New York</pair>
+      <pair name="state" type="string">NY</pair>
+      <pair name="postalCode" type="number">10021</pair>
+    </pair>
+    <pair name="phoneNumbers" type="array">
+      <item type="string">212 732-1234</item>
+      <item type="string">646 123-4567</item>
+    </pair>
+  </json>
+let $options :=
+  <options xmlns="http://www.zorba-xquery.com/modules/converters/json-options";>
+    <json-format value="Snelson"/>
+    <whitespace value="some"/>
+  </options>
+return json:serialize( $json, $options )
+(: vim:set et sw=2 ts=2: :)

=== modified file 'test/unit/CMakeLists.txt'
--- test/unit/CMakeLists.txt	2012-01-11 20:43:09 +0000
+++ test/unit/CMakeLists.txt	2012-01-23 00:53:27 +0000
@@ -143,3 +143,4 @@
 # ADD NEW UNIT TESTS HERE
 ZORBA_ADD_TEST("test/libunit/uri" LibUnitTest uri)
 EXPECTED_FAILURE(test/libunit/uri 3118348)
+ZORBA_ADD_TEST("test/libunit/json_parser" LibUnitTest json_parser)


Follow ups