changeset 227:8d5de4eb9c2c v2

Reimplemented JsonXmlReader, added support for null values: JSON null values are mapped to empty nodes with 'xsi:nil' attribute set to 'true'
author cin
date Sat, 09 Sep 2017 03:53:13 +0300
parents 9428ea36838e
children 6fa235c5a760
files .hgignore Implab.Format.Test/Implab.Format.Test.csproj Implab.Format.Test/JsonTests.cs Implab.Format.Test/packages.config Implab.Test/Implab.Format.Test/Implab.Format.Test.csproj Implab.Test/Implab.Format.Test/JsonTests.cs Implab.Test/Implab.Format.Test/packages.config Implab.Test/Implab.Test.csproj Implab.sln Implab/Formats/JSON/JSONParser.cs Implab/Formats/JSON/JSONXmlReaderOptions.cs Implab/Implab.csproj Implab/Parallels/AsyncQueue.cs Implab/Xml/JsonXmlReader.cs Implab/Xml/JsonXmlReaderOptions.cs Implab/Xml/JsonXmlReaderPosition.cs Implab/Xml/XmlNameContext.cs Implab/Xml/XmlSimpleAttribute.cs
diffstat 18 files changed, 1107 insertions(+), 209 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Fri Aug 25 02:16:35 2017 +0300
+++ b/.hgignore	Sat Sep 09 03:53:13 2017 +0300
@@ -18,3 +18,6 @@
 Implab.Test/Implab.Format.Test/bin/
 Implab.Test/Implab.Format.Test/obj/
 *.suo
+Implab.Format.Test/bin/
+Implab.Format.Test/obj/
+packages/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.Format.Test/Implab.Format.Test.csproj	Sat Sep 09 03:53:13 2017 +0300
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{4D364996-7ECD-4193-8F90-F223FFEA49DA}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <RootNamespace>Implab.Format.Test</RootNamespace>
+    <AssemblyName>Implab.Format.Test</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <ReleaseVersion>0.2</ReleaseVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG;</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>full</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
+      <HintPath>..\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="JsonTests.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <ProjectReference Include="..\Implab\Implab.csproj">
+      <Project>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</Project>
+      <Name>Implab</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+</Project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.Format.Test/JsonTests.cs	Sat Sep 09 03:53:13 2017 +0300
@@ -0,0 +1,145 @@
+using NUnit.Framework;
+using System;
+using Implab.Formats.JSON;
+using Implab.Automaton;
+using Implab.Xml;
+using System.Xml;
+using System.Text;
+
+namespace Implab.Format.Test {
+    [TestFixture]
+    public class JsonTests {
+        [Test]
+        public void TestScannerValidTokens() {
+            using (var scanner = new JSONScanner(@"9123, -123, 0, 0.1, -0.2, -0.1e3, 1.3E-3, ""some \t\n\u0020 text"", literal []{}:")) {
+
+                Tuple<JsonTokenType, object>[] expexted = {
+                    new Tuple<JsonTokenType,object>(JsonTokenType.Number, 9123d),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.Number, -123d),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0d),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0.1d),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.2d),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.1e3d),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.Number, 1.3E-3d),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.String, "some \t\n  text"),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.Literal, "literal"),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.BeginArray, " ["),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.EndArray, "]"),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.BeginObject, "{"),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.EndObject, "}"),
+                    new Tuple<JsonTokenType,object>(JsonTokenType.NameSeparator, ":")
+                };
+
+                object value;
+                JsonTokenType tokenType;
+                for (var i = 0; i < expexted.Length; i++) {
+
+                    Assert.IsTrue(scanner.ReadToken(out value, out tokenType));
+                    Assert.AreEqual(expexted[i].Item1, tokenType);
+                    Assert.AreEqual(expexted[i].Item2, value);
+                }
+
+                Assert.IsFalse(scanner.ReadToken(out value, out tokenType));
+            }
+        }
+
+        [Test]
+        public void TestScannerBadTokens() {
+            var bad = new[] {
+                " 1",
+                " literal",
+                " \"",
+                "\"unclosed string",
+                "1.bad",
+                "001", // should be read as three numbers
+                "--10",
+                "+10",
+                "1.0.0",
+                "1e1.0",
+                "l1teral0",
+                ".123",
+                "-.123"
+            };
+
+            foreach (var json in bad) {
+                using (var scanner = new JSONScanner(json)) {
+                    try {
+                        object value;
+                        JsonTokenType token;
+                        scanner.ReadToken(out value, out token);
+                        if (!Object.Equals(value, json)) {
+                            Console.WriteLine("'{0}' is read as {1}", json, value is String ? String.Format("'{0}'", value) : value);
+                            continue;
+                        }
+                        Assert.Fail("Token '{0}' shouldn't pass", json);
+                    } catch (ParserException e) {
+                        Console.WriteLine(e.Message);
+                    }
+                }
+            }
+        }
+
+        [Test]
+        public void JsonXmlReaderSimpleTest() {
+            var json = "\"some text\"";
+            //Console.WriteLine($"JSON: {json}");
+            //Console.WriteLine("XML");
+            /*using (var xmlReader = new JsonXmlReader(new JSONParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", RootName = "string", NodesPrefix = "json" })) {
+                Assert.AreEqual(xmlReader.ReadState, System.Xml.ReadState.Initial);
+
+                AssertRead(xmlReader, XmlNodeType.XmlDeclaration);
+                AssertRead(xmlReader, XmlNodeType.Element);
+                AssertRead(xmlReader, XmlNodeType.Text);
+                AssertRead(xmlReader, XmlNodeType.EndElement);
+                Assert.IsFalse(xmlReader.Read());
+            }*/
+
+            //DumpJsonParse("\"text value\"");
+            //DumpJsonParse("null");
+            //DumpJsonParse("true");
+            //DumpJsonParse("{}");
+            //DumpJsonParse("[]");
+            DumpJsonParse("{\"one\":1, \"two\":2}");
+            DumpJsonParse("[1,2,3]");
+            DumpJsonParse("[{\"info\": [7,8,9]}]");
+            DumpJsonFlatParse("[1,2,[3,4],{\"info\": [5,6]},{\"num\": [7,8,null]}, null,[null]]");
+        }
+
+        void AssertRead(XmlReader reader, XmlNodeType expected) {
+            Assert.IsTrue(reader.Read());
+            Console.WriteLine($"{new string(' ', reader.Depth*2)}{reader}");
+            Assert.AreEqual(expected, reader.NodeType);
+        }
+
+        void DumpJsonParse(string json) {
+            Console.WriteLine($"JSON: {json}");
+            Console.WriteLine("XML");
+            using (var xmlReader = new JsonXmlReader(new JSONParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "json" })) {
+                while (xmlReader.Read())
+                    Console.WriteLine($"{new string(' ', xmlReader.Depth * 2)}{xmlReader}");
+            }
+        }
+
+        void DumpJsonFlatParse(string json) {
+            Console.WriteLine($"JSON: {json}");
+            Console.WriteLine("XML");
+            using (var xmlWriter = XmlWriter.Create(Console.Out, new XmlWriterSettings {
+                Indent = true,
+                CloseOutput = false,
+                ConformanceLevel = ConformanceLevel.Document
+            }))
+            using (var xmlReader = new JsonXmlReader(new JSONParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "", FlattenArrays = true })) {
+                xmlWriter.WriteNode(xmlReader, false);
+            }
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab.Format.Test/packages.config	Sat Sep 09 03:53:13 2017 +0300
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="NUnit" version="3.8.1" targetFramework="net45" />
+</packages>
\ No newline at end of file
--- a/Implab.Test/Implab.Format.Test/Implab.Format.Test.csproj	Fri Aug 25 02:16:35 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProductVersion>8.0.30703</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <ProjectGuid>{4D364996-7ECD-4193-8F90-F223FFEA49DA}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <RootNamespace>Implab.Format.Test</RootNamespace>
-    <AssemblyName>Implab.Format.Test</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <ReleaseVersion>0.2</ReleaseVersion>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <ConsolePause>false</ConsolePause>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>full</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <ConsolePause>false</ConsolePause>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="nunit.framework">
-      <HintPath>..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
-    </Reference>
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="JsonTests.cs" />
-  </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <ItemGroup>
-    <ProjectReference Include="..\..\Implab\Implab.csproj">
-      <Project>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</Project>
-      <Name>Implab</Name>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="packages.config" />
-  </ItemGroup>
-  <ItemGroup>
-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
-  </ItemGroup>
-</Project>
\ No newline at end of file
--- a/Implab.Test/Implab.Format.Test/JsonTests.cs	Fri Aug 25 02:16:35 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-using NUnit.Framework;
-using System;
-using Implab.Formats.JSON;
-using Implab.Automaton;
-
-namespace Implab.Format.Test {
-    [TestFixture]
-    public class JsonTests {
-        [Test]
-        public void TestScannerValidTokens() {
-            using (var scanner = new JSONScanner(@"9123, -123, 0, 0.1, -0.2, -0.1e3, 1.3E-3, ""some \t\n\u0020 text"", literal []{}:")) {
-
-                Tuple<JsonTokenType,object>[] expexted = {
-                    new Tuple<JsonTokenType,object>(JsonTokenType.Number, 9123d),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.Number, -123d),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0d),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0.1d),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.2d),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.1e3d),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.Number, 1.3E-3d),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.String, "some \t\n  text"),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.Literal, "literal"),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.BeginArray, " ["),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.EndArray, "]"),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.BeginObject, "{"),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.EndObject, "}"),
-                    new Tuple<JsonTokenType,object>(JsonTokenType.NameSeparator, ":")
-                };
-
-                object value;
-                JsonTokenType tokenType;
-                for (var i = 0; i < expexted.Length; i++) {
-                
-                    Assert.IsTrue(scanner.ReadToken(out value, out tokenType));
-                    Assert.AreEqual(expexted[i].Item1, tokenType);
-                    Assert.AreEqual(expexted[i].Item2, value);
-                }
-
-                Assert.IsFalse(scanner.ReadToken(out value, out tokenType));
-            }
-        }
-
-        [Test]
-        public void TestScannerBadTokens() {
-            var bad = new [] {
-                " 1",
-                " literal",
-                " \"",
-                "\"unclosed string",
-                "1.bad",
-                "001", // should be read as three numbers
-                "--10",
-                "+10",
-                "1.0.0",
-                "1e1.0",
-                "l1teral0",
-                ".123",
-                "-.123"
-            };
-
-            foreach (var json in bad)
-                using (var scanner = new JSONScanner(json)) {
-                    try {
-                        object value;
-                        JsonTokenType token;
-                        scanner.ReadToken(out value, out token);
-                        if (!Object.Equals(value,json)) {
-                            Console.WriteLine("'{0}' is read as {1}", json, value is String ? String.Format("'{0}'", value) : value );
-                            continue;
-                        }
-                        Assert.Fail("Token '{0}' shouldn't pass", json);
-                    } catch (ParserException e) {
-                        Console.WriteLine(e.Message);
-                    }
-                }
-            
-        }
-    }
-}
-
--- a/Implab.Test/Implab.Format.Test/packages.config	Fri Aug 25 02:16:35 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="NUnit" version="2.6.4" targetFramework="net45" />
-</packages>
\ No newline at end of file
--- a/Implab.Test/Implab.Test.csproj	Fri Aug 25 02:16:35 2017 +0300
+++ b/Implab.Test/Implab.Test.csproj	Sat Sep 09 03:53:13 2017 +0300
@@ -76,9 +76,7 @@
       <Name>Implab</Name>
     </ProjectReference>
   </ItemGroup>
-  <ItemGroup>
-    <Folder Include="Implab.Format.Test\" />
-  </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.
--- a/Implab.sln	Fri Aug 25 02:16:35 2017 +0300
+++ b/Implab.sln	Sat Sep 09 03:53:13 2017 +0300
@@ -1,6 +1,8 @@
 
-Microsoft Visual Studio Solution File, Format Version 11.00
-# Visual Studio 2010
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab", "Implab\Implab.csproj", "{F550F1F8-8746-4AD0-9614-855F4C4B7F05}"
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CE8D8D18-437A-445C-B662-4C2CE79A76F6}"
@@ -16,14 +18,32 @@
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Fx.Test", "Implab.Fx.Test\Implab.Fx.Test.csproj", "{2F31E405-E267-4195-A05D-574093C21209}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Format.Test", "Implab.Format.Test\Implab.Format.Test.csproj", "{4D364996-7ECD-4193-8F90-F223FFEA49DA}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug 4.5|Any CPU = Debug 4.5|Any CPU
 		Debug|Any CPU = Debug|Any CPU
+		Release 4.5|Any CPU = Release 4.5|Any CPU
 		Release|Any CPU = Release|Any CPU
-		Debug 4.5|Any CPU = Debug 4.5|Any CPU
-		Release 4.5|Any CPU = Release 4.5|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
+		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
+		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
+		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
+		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.Build.0 = Release|Any CPU
+		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
+		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
+		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
+		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
+		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.Build.0 = Release|Any CPU
 		{06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
 		{06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
 		{06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@@ -40,24 +60,17 @@
 		{2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
 		{2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.Build.0 = Release|Any CPU
-		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
-		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
-		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
-		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
-		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.Build.0 = Release|Any CPU
-		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
-		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
-		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
-		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
-		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4D364996-7ECD-4193-8F90-F223FFEA49DA}.Debug 4.5|Any CPU.ActiveCfg = Debug|Any CPU
+		{4D364996-7ECD-4193-8F90-F223FFEA49DA}.Debug 4.5|Any CPU.Build.0 = Debug|Any CPU
+		{4D364996-7ECD-4193-8F90-F223FFEA49DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4D364996-7ECD-4193-8F90-F223FFEA49DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4D364996-7ECD-4193-8F90-F223FFEA49DA}.Release 4.5|Any CPU.ActiveCfg = Release|Any CPU
+		{4D364996-7ECD-4193-8F90-F223FFEA49DA}.Release 4.5|Any CPU.Build.0 = Release|Any CPU
+		{4D364996-7ECD-4193-8F90-F223FFEA49DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4D364996-7ECD-4193-8F90-F223FFEA49DA}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
-	GlobalSection(NestedProjects) = preSolution
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
 	EndGlobalSection
 	GlobalSection(MonoDevelopProperties) = preSolution
 		StartupItem = Implab\Implab.csproj
@@ -84,7 +97,7 @@
 		$1.inheritsSet = Mono
 		$1.inheritsScope = text/x-csharp
 		$1.scope = text/x-csharp
-		$0.TextStylePolicy = $2
+		$0.TextStylePolicy = $6
 		$2.FileWidth = 120
 		$2.EolMarker = Unix
 		$2.inheritsSet = VisualStudio
@@ -93,7 +106,6 @@
 		$0.DotNetNamingPolicy = $3
 		$3.DirectoryNamespaceAssociation = PrefixedHierarchical
 		$3.ResourceNamePolicy = MSBuild
-		$0.TextStylePolicy = $4
 		$4.FileWidth = 120
 		$4.TabsToSpaces = False
 		$4.inheritsSet = VisualStudio
@@ -103,7 +115,6 @@
 		$5.inheritsSet = Mono
 		$5.inheritsScope = application/xml
 		$5.scope = application/xml
-		$0.TextStylePolicy = $6
 		$6.FileWidth = 120
 		$6.TabsToSpaces = False
 		$6.inheritsSet = VisualStudio
@@ -111,21 +122,19 @@
 		$6.scope = text/plain
 		$0.NameConventionPolicy = $7
 		$7.Rules = $8
-		$8.NamingRule = $9
+		$8.NamingRule = $34
 		$9.Name = Namespaces
 		$9.AffectedEntity = Namespace
 		$9.VisibilityMask = VisibilityMask
 		$9.NamingStyle = PascalCase
 		$9.IncludeInstanceMembers = True
 		$9.IncludeStaticEntities = True
-		$8.NamingRule = $10
 		$10.Name = Types
 		$10.AffectedEntity = Class, Struct, Enum, Delegate
 		$10.VisibilityMask = VisibilityMask
 		$10.NamingStyle = PascalCase
 		$10.IncludeInstanceMembers = True
 		$10.IncludeStaticEntities = True
-		$8.NamingRule = $11
 		$11.Name = Interfaces
 		$11.RequiredPrefixes = $12
 		$12.String = I
@@ -134,7 +143,6 @@
 		$11.NamingStyle = PascalCase
 		$11.IncludeInstanceMembers = True
 		$11.IncludeStaticEntities = True
-		$8.NamingRule = $13
 		$13.Name = Attributes
 		$13.RequiredSuffixes = $14
 		$14.String = Attribute
@@ -143,7 +151,6 @@
 		$13.NamingStyle = PascalCase
 		$13.IncludeInstanceMembers = True
 		$13.IncludeStaticEntities = True
-		$8.NamingRule = $15
 		$15.Name = Event Arguments
 		$15.RequiredSuffixes = $16
 		$16.String = EventArgs
@@ -152,7 +159,6 @@
 		$15.NamingStyle = PascalCase
 		$15.IncludeInstanceMembers = True
 		$15.IncludeStaticEntities = True
-		$8.NamingRule = $17
 		$17.Name = Exceptions
 		$17.RequiredSuffixes = $18
 		$18.String = Exception
@@ -161,35 +167,30 @@
 		$17.NamingStyle = PascalCase
 		$17.IncludeInstanceMembers = True
 		$17.IncludeStaticEntities = True
-		$8.NamingRule = $19
 		$19.Name = Methods
 		$19.AffectedEntity = Methods
 		$19.VisibilityMask = VisibilityMask
 		$19.NamingStyle = PascalCase
 		$19.IncludeInstanceMembers = True
 		$19.IncludeStaticEntities = True
-		$8.NamingRule = $20
 		$20.Name = Static Readonly Fields
 		$20.AffectedEntity = ReadonlyField
 		$20.VisibilityMask = Internal, Protected, Public
 		$20.NamingStyle = CamelCase
 		$20.IncludeInstanceMembers = False
 		$20.IncludeStaticEntities = True
-		$8.NamingRule = $21
 		$21.Name = Fields (Non Private)
 		$21.AffectedEntity = Field
 		$21.VisibilityMask = Internal, Public
 		$21.NamingStyle = CamelCase
 		$21.IncludeInstanceMembers = True
 		$21.IncludeStaticEntities = True
-		$8.NamingRule = $22
 		$22.Name = ReadOnly Fields (Non Private)
 		$22.AffectedEntity = ReadonlyField
 		$22.VisibilityMask = Internal, Public
 		$22.NamingStyle = CamelCase
 		$22.IncludeInstanceMembers = True
 		$22.IncludeStaticEntities = False
-		$8.NamingRule = $23
 		$23.Name = Fields (Private)
 		$23.RequiredPrefixes = $24
 		$24.String = m_
@@ -198,7 +199,6 @@
 		$23.NamingStyle = CamelCase
 		$23.IncludeInstanceMembers = True
 		$23.IncludeStaticEntities = False
-		$8.NamingRule = $25
 		$25.Name = Static Fields (Private)
 		$25.RequiredPrefixes = $26
 		$26.String = _
@@ -207,7 +207,6 @@
 		$25.NamingStyle = CamelCase
 		$25.IncludeInstanceMembers = False
 		$25.IncludeStaticEntities = True
-		$8.NamingRule = $27
 		$27.Name = ReadOnly Fields (Private)
 		$27.RequiredPrefixes = $28
 		$28.String = m_
@@ -216,42 +215,36 @@
 		$27.NamingStyle = CamelCase
 		$27.IncludeInstanceMembers = True
 		$27.IncludeStaticEntities = False
-		$8.NamingRule = $29
 		$29.Name = Constant Fields
 		$29.AffectedEntity = ConstantField
 		$29.VisibilityMask = VisibilityMask
 		$29.NamingStyle = AllUpper
 		$29.IncludeInstanceMembers = True
 		$29.IncludeStaticEntities = True
-		$8.NamingRule = $30
 		$30.Name = Properties
 		$30.AffectedEntity = Property
 		$30.VisibilityMask = VisibilityMask
 		$30.NamingStyle = PascalCase
 		$30.IncludeInstanceMembers = True
 		$30.IncludeStaticEntities = True
-		$8.NamingRule = $31
 		$31.Name = Events
 		$31.AffectedEntity = Event
 		$31.VisibilityMask = VisibilityMask
 		$31.NamingStyle = PascalCase
 		$31.IncludeInstanceMembers = True
 		$31.IncludeStaticEntities = True
-		$8.NamingRule = $32
 		$32.Name = Enum Members
 		$32.AffectedEntity = EnumMember
 		$32.VisibilityMask = VisibilityMask
 		$32.NamingStyle = PascalCase
 		$32.IncludeInstanceMembers = True
 		$32.IncludeStaticEntities = True
-		$8.NamingRule = $33
 		$33.Name = Parameters
 		$33.AffectedEntity = Parameter, LocalVariable
 		$33.VisibilityMask = VisibilityMask
 		$33.NamingStyle = CamelCase
 		$33.IncludeInstanceMembers = True
 		$33.IncludeStaticEntities = True
-		$8.NamingRule = $34
 		$34.Name = Type Parameters
 		$34.RequiredPrefixes = $35
 		$35.String = T
@@ -264,7 +257,4 @@
 	GlobalSection(TestCaseManagementSettings) = postSolution
 		CategoryFile = Implab.vsmdi
 	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
 EndGlobal
--- a/Implab/Formats/JSON/JSONParser.cs	Fri Aug 25 02:16:35 2017 +0300
+++ b/Implab/Formats/JSON/JSONParser.cs	Sat Sep 09 03:53:13 2017 +0300
@@ -110,7 +110,8 @@
         #endregion
 
         readonly JSONScanner m_scanner;
-        MemberContext m_memberContext;
+        // json starts from the value context and may content even a single literal
+        MemberContext m_memberContext = MemberContext.MemberValue;
 
         JSONElementType m_elementType;
         object m_elementValue;
--- a/Implab/Formats/JSON/JSONXmlReaderOptions.cs	Fri Aug 25 02:16:35 2017 +0300
+++ b/Implab/Formats/JSON/JSONXmlReaderOptions.cs	Sat Sep 09 03:53:13 2017 +0300
@@ -1,16 +1,16 @@
 
 using System.Xml;
 
-namespace Implab.Formats.JSON {
+namespace Implab.Xml {
     /// <summary>
     /// Набор необязательных параметров для <see cref="JSONXmlReader"/>, позволяющий управлять процессом
     /// интерпретации <c>JSON</c> документа.
     /// </summary>
-    public class JSONXmlReaderOptions {
+    public class JsonXmlReaderOptions {
         /// <summary>
         /// Пространство имен в котором будут располагаться читаемые элементы документа
         /// </summary>
-        public string NamespaceURI {
+        public string NamespaceUri {
             get;
             set;
         }
--- a/Implab/Implab.csproj	Fri Aug 25 02:16:35 2017 +0300
+++ b/Implab/Implab.csproj	Sat Sep 09 03:53:13 2017 +0300
@@ -198,6 +198,11 @@
     <Compile Include="FailedPromise.cs" />
     <Compile Include="FailedPromiseT.cs" />
     <Compile Include="Components\PollingComponent.cs" />
+    <Compile Include="Xml\JsonXmlReader.cs" />
+    <Compile Include="Xml\JsonXmlReaderOptions.cs" />
+    <Compile Include="Xml\JsonXmlReaderPosition.cs" />
+    <Compile Include="Xml\XmlSimpleAttribute.cs" />
+    <Compile Include="Xml\XmlNameContext.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup />
@@ -210,7 +215,7 @@
           <DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild" />
           <TextStylePolicy FileWidth="120" TabWidth="4" TabsToSpaces="False" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" scope="application/xml" />
           <XmlFormattingPolicy scope="application/xml">
-            <DefaultFormat OmitXmlDeclaration="False" NewLineChars="&#xA;" IndentContent="True" ContentIndentString="&#x9;" AttributesInNewLine="False" MaxAttributesPerLine="10" AttributesIndentString="&#x9;" WrapAttributes="False" AlignAttributes="False" AlignAttributeValues="False" QuoteChar="&quot;" SpacesBeforeAssignment="0" SpacesAfterAssignment="0" EmptyLinesBeforeStart="0" EmptyLinesAfterStart="0" EmptyLinesBeforeEnd="0" EmptyLinesAfterEnd="0" />
+            <DefaultFormat OmitXmlDeclaration="False" NewLineChars="&#xA;" IndentContent="True" ContentIndentString="	" AttributesInNewLine="False" MaxAttributesPerLine="10" AttributesIndentString="	" WrapAttributes="False" AlignAttributes="False" AlignAttributeValues="False" QuoteChar="&quot;" SpacesBeforeAssignment="0" SpacesAfterAssignment="0" EmptyLinesBeforeStart="0" EmptyLinesAfterStart="0" EmptyLinesBeforeEnd="0" EmptyLinesAfterEnd="0" />
           </XmlFormattingPolicy>
           <TextStylePolicy FileWidth="120" TabWidth="4" TabsToSpaces="False" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" scope="text/plain" />
           <NameConventionPolicy>
--- a/Implab/Parallels/AsyncQueue.cs	Fri Aug 25 02:16:35 2017 +0300
+++ b/Implab/Parallels/AsyncQueue.cs	Sat Sep 09 03:53:13 2017 +0300
@@ -385,8 +385,6 @@
             if (next == null) {
 
                 if (first != Interlocked.CompareExchange(ref m_last, null, first)) {
-                    /*while (first.next == null)
-                        Thread.MemoryBarrier();*/
 
                     // race
                     // someone already updated the tail, restore the pointer to the queue head
@@ -394,12 +392,6 @@
                 }
                 // the tail is updated
             }
-
-            // we need to update the head
-            //Interlocked.CompareExchange(ref m_first, next, first);
-            // if the head is already updated then give up
-            //return;
-
         }
 
         public void Clear() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Xml/JsonXmlReader.cs	Sat Sep 09 03:53:13 2017 +0300
@@ -0,0 +1,629 @@
+using Implab.Formats.JSON;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml;
+
+namespace Implab.Xml {
+    public class JsonXmlReader : XmlReader {
+        struct JsonContext {
+            public string localName;
+            public bool skip;
+        }
+
+        JSONParser m_parser;
+        JsonXmlReaderOptions m_options;
+        JsonXmlReaderPosition m_position = JsonXmlReaderPosition.Initial;
+        XmlNameTable m_nameTable;
+
+        readonly string m_jsonRootName;
+        readonly string m_jsonNamespace;
+        readonly string m_jsonPrefix;
+        readonly bool m_jsonFlattenArrays;
+        readonly string m_jsonArrayItemName;
+
+        string m_jsonLocalName;
+        string m_jsonValueName;
+        bool m_jsonSkip; // indicates wheather to generate closing tag for objects or arrays
+
+        readonly Stack<JsonContext> m_jsonNameStack = new Stack<JsonContext>();
+
+        XmlQualifiedName m_elementQName;
+        string m_elementPrefix;
+        int m_elementDepth;
+        bool m_elementIsEmpty;
+
+        XmlQualifiedName m_qName;
+        string m_prefix;
+        int m_xmlDepth;
+
+        XmlSimpleAttribute[] m_attributes;
+        object m_value;
+        bool m_isEmpty;
+
+        XmlNodeType m_nodeType = XmlNodeType.None;
+
+        bool m_isAttribute; // indicates that we are reading attribute nodes
+        int m_currentAttribute;
+        bool m_currentAttributeRead;
+
+
+        XmlNameContext m_context;
+        int m_nextPrefix = 1;
+
+        readonly string m_xmlnsPrefix;
+        readonly string m_xmlnsNamespace;
+        readonly string m_xsiPrefix;
+        readonly string m_xsiNamespace;
+
+
+        public JsonXmlReader(JSONParser parser, JsonXmlReaderOptions options) {
+            Safe.ArgumentNotNull(parser, nameof(parser));
+            m_parser = parser;
+
+            m_options = options ?? new JsonXmlReaderOptions();
+
+            m_jsonFlattenArrays = m_options.FlattenArrays;
+            m_nameTable = m_options.NameTable ?? new NameTable();
+
+            m_jsonRootName = m_nameTable.Add(string.IsNullOrEmpty(m_options.RootName) ? "data" : m_options.RootName);
+            m_jsonArrayItemName = m_nameTable.Add(string.IsNullOrEmpty(m_options.ArrayItemName) ? "item" : m_options.ArrayItemName);
+            m_jsonNamespace = m_nameTable.Add(m_options.NamespaceUri ?? string.Empty);
+            m_jsonPrefix = m_nameTable.Add(m_options.NodesPrefix ?? string.Empty);
+            m_xmlnsPrefix = m_nameTable.Add(XmlNameContext.XmlnsPrefix);
+            m_xmlnsNamespace = m_nameTable.Add(XmlNameContext.XmlnsNamespace);
+            m_xsiPrefix = m_nameTable.Add(XmlNameContext.XsiPrefix);
+            m_xsiNamespace = m_nameTable.Add(XmlNameContext.XsiNamespace);
+
+            // TODO validate m_jsonRootName, m_jsonArrayItemName
+
+            m_context = new XmlNameContext(null);
+        }
+
+        public override int AttributeCount {
+            get {
+                return m_attributes == null ? 0 : m_attributes.Length;
+            }
+        }
+
+        public override string BaseURI {
+            get {
+                return string.Empty;
+            }
+        }
+
+        public override int Depth {
+            get {
+                return m_xmlDepth;
+            }
+        }
+
+        public override bool EOF {
+            get {
+                return m_position == JsonXmlReaderPosition.Eof;
+            }
+        }
+
+        public override bool IsEmptyElement {
+            get { return m_isEmpty; }
+        }
+
+
+        public override string LocalName {
+            get {
+                return m_qName.Name;
+            }
+        }
+
+        public override string NamespaceURI {
+            get {
+                return m_qName.Namespace;
+            }
+        }
+
+        public override XmlNameTable NameTable {
+            get {
+                return m_nameTable;
+            }
+        }
+
+        public override XmlNodeType NodeType {
+            get {
+                return m_nodeType;
+            }
+        }
+
+        public override string Prefix {
+            get {
+                return m_prefix;
+            }
+        }
+
+        public override ReadState ReadState {
+            get {
+                switch (m_position) {
+                    case JsonXmlReaderPosition.Initial:
+                        return ReadState.Initial;
+                    case JsonXmlReaderPosition.Eof:
+                        return ReadState.EndOfFile;
+                    case JsonXmlReaderPosition.Closed:
+                        return ReadState.Closed;
+                    case JsonXmlReaderPosition.Error:
+                        return ReadState.Error;
+                    default:
+                        return ReadState.Interactive;
+                };
+            }
+        }
+
+        public override string Value {
+            get {
+                return ConvertValueToString(m_value);
+            }
+        }
+
+        static string ConvertValueToString(object value) {
+            if (value == null)
+                return string.Empty;
+
+            switch (Convert.GetTypeCode(value)) {
+                case TypeCode.Double:
+                    return ((double)value).ToString(CultureInfo.InvariantCulture);
+                case TypeCode.String:
+                    return (string)value;
+                case TypeCode.Boolean:
+                    return (bool)value ? "true" : "false";
+                default:
+                    return value.ToString();
+            }
+        }
+
+        public override string GetAttribute(int i) {
+            Safe.ArgumentInRange(i, 0, AttributeCount - 1, nameof(i));
+            return ConvertValueToString(m_attributes[i].Value);
+        }
+
+        public override string GetAttribute(string name) {
+            if (m_attributes == null)
+                return null;
+            var qName = m_context.Resolve(name);
+            var attr = Array.Find(m_attributes, x => x.QName == qName);
+            var value = ConvertValueToString(attr?.Value);
+            return value == string.Empty ? null : value;
+        }
+
+        public override string GetAttribute(string name, string namespaceURI) {
+            if (m_attributes == null)
+                return null;
+            var qName = new XmlQualifiedName(name, namespaceURI);
+            var attr = Array.Find(m_attributes, x => x.QName == qName);
+            var value = ConvertValueToString(attr?.Value);
+            return value == string.Empty ? null : value;
+        }
+
+        public override string LookupNamespace(string prefix) {
+            return m_context.ResolvePrefix(prefix);
+        }
+
+        public override bool MoveToAttribute(string name) {
+            if (m_attributes == null || m_attributes.Length == 0)
+                return false;
+
+            var qName = m_context.Resolve(name);
+            var index = Array.FindIndex(m_attributes, x => x.QName == qName);
+            if (index >= 0) {
+                MoveToAttributeImpl(index);
+                return true;
+            }
+            return false;
+        }
+
+        public override bool MoveToAttribute(string name, string ns) {
+            if (m_attributes == null || m_attributes.Length == 0)
+                return false;
+
+            var qName = m_context.Resolve(name);
+            var index = Array.FindIndex(m_attributes, x => x.QName == qName);
+            if (index >= 0) {
+                MoveToAttributeImpl(index);
+                return true;
+            }
+            return false;
+        }
+
+        void MoveToAttributeImpl(int i) {
+            if (!m_isAttribute) {
+                m_elementQName = m_qName;
+                m_elementDepth = m_xmlDepth;
+                m_elementPrefix = m_prefix;
+                m_elementIsEmpty = m_isEmpty;
+                m_isAttribute = true;
+            }
+            
+            var attr = m_attributes[i];
+
+
+            m_currentAttribute = i;
+            m_currentAttributeRead = false;
+            m_nodeType = XmlNodeType.Attribute;
+
+            m_xmlDepth = m_elementDepth + 1;
+            m_qName = attr.QName;
+            m_value = attr.Value;
+            m_prefix = attr.Prefix;
+        }
+
+        public override bool MoveToElement() {
+            if (m_isAttribute) {
+                m_value = null;
+                m_nodeType = XmlNodeType.Element;
+                m_xmlDepth = m_elementDepth;
+                m_prefix = m_elementPrefix;
+                m_qName = m_elementQName;
+                m_isEmpty = m_elementIsEmpty;
+                m_isAttribute = false;
+                return true;
+            }
+            return false;
+        }
+
+        public override bool MoveToFirstAttribute() {
+            if (m_attributes != null && m_attributes.Length > 0) {
+                MoveToAttributeImpl(0);
+                return true;
+            }
+            return false;
+        }
+
+        public override bool MoveToNextAttribute() {
+            if (m_isAttribute) {
+                var next = m_currentAttribute + 1;
+                if (next < AttributeCount) {
+                    MoveToAttributeImpl(next);
+                    return true;
+                }
+                return false;
+            } else {
+                return MoveToFirstAttribute();
+            }
+
+        }
+
+        public override bool ReadAttributeValue() {
+            if (!m_isAttribute || m_currentAttributeRead)
+                return false;
+
+            ValueNode(m_attributes[m_currentAttribute].Value);
+            m_currentAttributeRead = true;
+            return true;
+        }
+
+        public override void ResolveEntity() {
+            /* do nothing */
+        }
+
+        /// <summary>
+        /// Determines do we need to increase depth after the current node
+        /// </summary>
+        /// <returns></returns>
+        public bool IsSibling() {
+            switch (m_nodeType) {
+                case XmlNodeType.None: // start document
+                case XmlNodeType.Attribute: // after attribute only it's content can be iterated with ReadAttributeValue method
+                    return false;
+                case XmlNodeType.Element:
+                    // if the elemnt is empty the next element will be it's sibling
+                    return m_isEmpty;
+
+                case XmlNodeType.Document:
+                case XmlNodeType.DocumentFragment:
+                case XmlNodeType.Entity:
+                case XmlNodeType.Text:
+                case XmlNodeType.CDATA:
+                case XmlNodeType.EntityReference:
+                case XmlNodeType.ProcessingInstruction:
+                case XmlNodeType.Comment:
+                case XmlNodeType.DocumentType:
+                case XmlNodeType.Notation:
+                case XmlNodeType.Whitespace:
+                case XmlNodeType.SignificantWhitespace:
+                case XmlNodeType.EndElement:
+                case XmlNodeType.EndEntity:
+                case XmlNodeType.XmlDeclaration:
+                default:
+                    return true;
+            }
+        }
+
+        void ValueNode(object value) {
+            if (!IsSibling()) // the node is nested
+                m_xmlDepth++;
+
+            m_qName = XmlQualifiedName.Empty;
+            m_nodeType = XmlNodeType.Text;
+            m_prefix = string.Empty;
+            m_value = value;
+            m_isEmpty = false;
+            m_attributes = null;
+        }
+
+        void ElementNode(string name, string ns, XmlSimpleAttribute[] attrs, bool empty) {
+            if (!IsSibling()) // the node is nested
+                m_xmlDepth++;
+
+            m_context = new XmlNameContext(m_context);
+            List<XmlSimpleAttribute> definedAttrs = null;
+
+            // define new namespaces
+            if (attrs != null) {
+                foreach (var attr in attrs) {
+                    if (attr.QName.Name == "xmlns") {
+                        m_context.DefinePrefix(ConvertValueToString(attr.Value), string.Empty);
+                    } else if (attr.Prefix == m_xmlnsPrefix) {
+                        m_context.DefinePrefix(ConvertValueToString(attr.Value), attr.QName.Name);
+                    } else {
+                        string attrPrefix;
+                        if (string.IsNullOrEmpty(attr.QName.Namespace))
+                            continue;
+
+                        // auto-define prefixes
+                        if (!m_context.LookupNamespacePrefix(attr.QName.Namespace, out attrPrefix) || string.IsNullOrEmpty(attrPrefix)) {
+                            // new namespace prefix added
+                            attrPrefix = m_context.CreateNamespacePrefix(attr.QName.Namespace);
+                            attr.Prefix = attrPrefix;
+
+                            if (definedAttrs == null)
+                                definedAttrs = new List<XmlSimpleAttribute>();
+
+                            definedAttrs.Add(new XmlSimpleAttribute(attrPrefix, m_xmlnsNamespace, m_xmlnsPrefix, attr.QName.Namespace));
+                        }
+                    }
+                }
+            }
+
+            string p;
+            // auto-define prefixes
+            if (!m_context.LookupNamespacePrefix(ns, out p)) {
+                p = m_context.CreateNamespacePrefix(ns);
+                if (definedAttrs == null)
+                    definedAttrs = new List<XmlSimpleAttribute>();
+
+                definedAttrs.Add(new XmlSimpleAttribute(p, m_xmlnsNamespace, m_xmlnsPrefix, ns));
+            }
+
+            if (definedAttrs != null) {
+                if (attrs != null)
+                    definedAttrs.AddRange(attrs);
+                attrs = definedAttrs.ToArray();
+            }
+
+            m_nodeType = XmlNodeType.Element;
+            m_qName = new XmlQualifiedName(name, ns);
+            m_prefix = p;
+            m_value = null;
+            m_isEmpty = empty;
+            m_attributes = attrs;
+        }
+
+        void EndElementNode(string name, string ns) {
+            if (IsSibling()) // closing the element which has children
+                m_xmlDepth--;
+
+            string p;
+            if (!m_context.LookupNamespacePrefix(ns, out p))
+                throw new Exception($"Failed to lookup namespace '{ns}'");
+
+            m_context = m_context.ParentContext;
+            m_nodeType = XmlNodeType.EndElement;
+            m_prefix = p;
+            m_qName = new XmlQualifiedName(name, ns);
+            m_value = null;
+            m_attributes = null;
+            m_isEmpty = false;
+        }
+
+        void XmlDeclaration() {
+            if (!IsSibling()) // the node is nested
+                m_xmlDepth++;
+            m_nodeType = XmlNodeType.XmlDeclaration;
+            m_qName = new XmlQualifiedName("xml");
+            m_value = "version='1.0'";
+            m_prefix = string.Empty;
+            m_attributes = null;
+            m_isEmpty = false;
+        }
+
+        public override bool Read() {
+            try {
+                string elementName;
+                XmlSimpleAttribute[] elementAttrs = null;
+                MoveToElement();
+
+                switch (m_position) {
+                    case JsonXmlReaderPosition.Initial:
+                        m_jsonLocalName = m_jsonRootName;
+                        m_jsonSkip = false;
+                        XmlDeclaration();
+                        m_position = JsonXmlReaderPosition.Declaration;
+                        return true;
+                    case JsonXmlReaderPosition.Declaration:
+                        elementAttrs = new[] {
+                            new XmlSimpleAttribute(m_xsiPrefix, m_xmlnsNamespace, m_xmlnsPrefix, m_xsiNamespace),
+                            string.IsNullOrEmpty(m_jsonPrefix) ?
+                                new XmlSimpleAttribute(m_xmlnsPrefix, string.Empty, string.Empty, m_jsonNamespace) :
+                                new XmlSimpleAttribute(m_jsonPrefix, m_xmlnsNamespace, m_xmlnsPrefix, m_jsonNamespace)
+                        };
+                        break;
+                    case JsonXmlReaderPosition.ValueElement:
+                        if (!m_isEmpty) {
+                            ValueNode(m_parser.ElementValue);
+                            m_position = JsonXmlReaderPosition.ValueContent;
+                            return true;
+                        } else {
+                            m_position = JsonXmlReaderPosition.ValueEndElement;
+                            break;
+                        }
+                    case JsonXmlReaderPosition.ValueContent:
+                        EndElementNode(m_jsonValueName, m_jsonNamespace);
+                        m_position = JsonXmlReaderPosition.ValueEndElement;
+                        return true;
+                    case JsonXmlReaderPosition.Eof:
+                    case JsonXmlReaderPosition.Closed:
+                    case JsonXmlReaderPosition.Error:
+                        return false;
+                }
+
+                while (m_parser.Read()) {
+                    var jsonName = m_nameTable.Add(m_parser.ElementName);
+
+                    switch (m_parser.ElementType) {
+                        case JSONElementType.BeginObject:
+                            if (!EnterJsonObject(jsonName, out elementName))
+                                continue;
+
+                            m_position = JsonXmlReaderPosition.BeginObject;
+                            ElementNode(elementName, m_jsonNamespace, elementAttrs, false);
+                            break;
+                        case JSONElementType.EndObject:
+                            if (!LeaveJsonScope(out elementName))
+                                continue;
+
+                            m_position = JsonXmlReaderPosition.EndObject;
+                            EndElementNode(elementName, m_jsonNamespace);
+                            break;
+                        case JSONElementType.BeginArray:
+                            if (!EnterJsonArray(jsonName, out elementName))
+                                continue;
+
+                            m_position = JsonXmlReaderPosition.BeginArray;
+                            ElementNode(elementName, m_jsonNamespace, elementAttrs, false);
+                            break;
+                        case JSONElementType.EndArray:
+                            if (!LeaveJsonScope(out elementName))
+                                continue;
+
+                            m_position = JsonXmlReaderPosition.EndArray;
+                            EndElementNode(elementName, m_jsonNamespace);
+                            break;
+                        case JSONElementType.Value:
+                            if (!VisitJsonValue(jsonName, out m_jsonValueName))
+                                continue;
+
+                            m_position = JsonXmlReaderPosition.ValueElement;
+                            if (m_parser.ElementValue == null)
+                                // generate empty element with xsi:nil="true" attribute
+                                ElementNode(
+                                    m_jsonValueName,
+                                    m_jsonNamespace,
+                                    new[] {
+                                        new XmlSimpleAttribute("nil", m_xsiNamespace, m_xsiPrefix, true)
+                                    },
+                                    true
+                                );
+                            else
+                                ElementNode(m_jsonValueName, m_jsonNamespace, elementAttrs, m_parser.ElementValue as string == string.Empty);
+                            break;
+                        default:
+                            throw new Exception($"Unexpected JSON element {m_parser.ElementType}: {m_parser.ElementName}");
+                    }
+                    return true;
+                }
+
+                m_position = JsonXmlReaderPosition.Eof;
+                return false;
+            } catch {
+                m_position = JsonXmlReaderPosition.Error;
+                throw;
+            }
+        }
+
+        void SaveJsonName() {
+            m_jsonNameStack.Push(new JsonContext {
+                skip = m_jsonSkip,
+                localName = m_jsonLocalName
+            });
+
+        }
+
+        bool EnterJsonObject(string name, out string elementName) {
+            SaveJsonName();
+            m_jsonSkip = false;
+
+            if (string.IsNullOrEmpty(name)) {
+                if (m_jsonNameStack.Count != 1 && !m_jsonFlattenArrays)
+                    m_jsonLocalName = m_jsonArrayItemName;
+            } else {
+                m_jsonLocalName = name;
+            }
+
+            elementName = m_jsonLocalName;
+            return true;
+        }
+
+        /// <summary>
+        /// Called when JSON parser visits BeginArray ('[') element.
+        /// </summary>
+        /// <param name="name">Optional property name if the array is the member of an object</param>
+        /// <returns>true if element should be emited, false otherwise</returns>
+        bool EnterJsonArray(string name, out string elementName) {
+            SaveJsonName();
+
+            if (string.IsNullOrEmpty(name)) {
+                // m_jsonNameStack.Count == 1 means the root node
+                if (m_jsonNameStack.Count != 1 && !m_jsonFlattenArrays)
+                    m_jsonLocalName = m_jsonArrayItemName;
+
+                m_jsonSkip = false; // we should not flatten arrays inside arrays or in the document root
+            } else {
+                m_jsonLocalName = name;
+                m_jsonSkip = m_jsonFlattenArrays;
+            }
+            elementName = m_jsonLocalName;
+
+            return !m_jsonSkip;
+        }
+
+        bool VisitJsonValue(string name, out string elementName) {
+            if (string.IsNullOrEmpty(name)) {
+                // m_jsonNameStack.Count == 0 means that JSON document consists from simple value
+                elementName = (m_jsonNameStack.Count == 0 || m_jsonFlattenArrays) ? m_jsonLocalName : m_jsonArrayItemName;
+            } else {
+                elementName = name;
+            }
+            return true;
+        }
+
+        bool LeaveJsonScope(out string elementName) {
+            elementName = m_jsonLocalName;
+            var skip = m_jsonSkip;
+
+            var prev = m_jsonNameStack.Pop();
+            m_jsonLocalName = prev.localName;
+            m_jsonSkip = prev.skip;
+
+            return !skip;
+        }
+
+        public override string ToString() {
+            switch (NodeType) {
+                case XmlNodeType.Element:
+                    return $"<{Name} {string.Join(" ", (m_attributes ?? new XmlSimpleAttribute[0]).Select(x => $"{x.Prefix}{(string.IsNullOrEmpty(x.Prefix) ? "" : ":")}{x.QName.Name}='{ConvertValueToString(x.Value)}'"))} {(IsEmptyElement ? "/" : "")}>";
+                case XmlNodeType.Attribute:
+                    return $"@{Name}";
+                case XmlNodeType.Text:
+                    return $"{Value}";
+                case XmlNodeType.CDATA:
+                    return $"<![CDATA[{Value}]]>";
+                case XmlNodeType.EntityReference:
+                    return $"&{Name};";
+                case XmlNodeType.EndElement:
+                    return $"</{Name}>";
+                default:
+                    return $".{NodeType} {Name} {Value}";
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Xml/JsonXmlReaderOptions.cs	Sat Sep 09 03:53:13 2017 +0300
@@ -0,0 +1,66 @@
+
+using System;
+using System.Xml;
+
+namespace Implab.Formats.JSON {
+    /// <summary>
+    /// Набор необязательных параметров для <see cref="JSONXmlReader"/>, позволяющий управлять процессом
+    /// интерпретации <c>JSON</c> документа.
+    /// </summary>
+    public class JSONXmlReaderOptions : ICloneable {
+        /// <summary>
+        /// Пространство имен в котором будут располагаться читаемые элементы документа
+        /// </summary>
+        public string NamespaceURI {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// Интерпретировать массивы как множественные элементы (убирает один уровень вложенности), иначе массив
+        /// представляется в виде узла, дочерними элементами которого являются элементы массива, имена дочерних элементов
+        /// определяются свойством <see cref="ArrayItemName"/>. По умолчанию <c>false</c>.
+        /// </summary>
+        public bool FlattenArrays {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// Префикс, для узлов документа
+        /// </summary>
+        public string NodesPrefix {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// Имя корневого элемента в xml документе
+        /// </summary>
+        public string RootName {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// Имя элемента для массивов, если не включена опция <see cref="FlattenArrays"/>.
+        /// По умолчанию <c>item</c>.
+        /// </summary>
+        public string ArrayItemName {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// Таблица атомизированных строк для построения документа.
+        /// </summary>
+        public XmlNameTable NameTable {
+            get;
+            set;
+        }
+
+        public object Clone() {
+            return MemberwiseClone();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Xml/JsonXmlReaderPosition.cs	Sat Sep 09 03:53:13 2017 +0300
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Implab.Xml {
+    public enum JsonXmlReaderPosition {
+        Initial,
+        Declaration,
+        BeginArray,
+        BeginObject,
+        EndArray,
+        EndObject,
+        ValueElement,
+        ValueContent,
+        ValueEndElement,
+        Eof,
+        Closed,
+        Error
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Xml/XmlNameContext.cs	Sat Sep 09 03:53:13 2017 +0300
@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml;
+
+namespace Implab.Xml {
+    public class XmlNameContext {
+        public const string XmlnsNamespace = "http://www.w3.org/2000/xmlns/";
+        public const string XmlnsPrefix = "xmlns";
+        public const string XmlNamespace = "http://www.w3.org/XML/1998/namespace";
+        public const string XmlPrefix = "xml";
+        public const string XsiNamespace = "http://www.w3.org/2001/XMLSchema-instance";
+        public const string XsiPrefix = "xsi";
+
+        readonly static char[] _qNameDelim = new[] { ':' };
+
+        Dictionary<string, string> m_ns2prefix;
+        Dictionary<string, string> m_prefix2ns;
+        int m_nextPrefix = 1;
+        
+        public XmlNameContext ParentContext { get; private set; }
+
+        public XmlNameContext(XmlNameContext parent) {
+            ParentContext = parent;
+            if (parent == null) {
+                DefinePrefixNoCheck(XmlnsNamespace, XmlnsPrefix);
+                DefinePrefixNoCheck(XmlNamespace, XmlPrefix);
+            } else {
+                m_nextPrefix = parent.m_nextPrefix;
+            }
+        }
+
+        public bool LookupNamespacePrefix(string ns, out string prefix) {
+            if (ns == null)
+                ns = string.Empty;
+
+            prefix = null;
+            for (var ctx = this; ctx != null; ctx = ctx.ParentContext) {
+                if (ctx.m_ns2prefix?.TryGetValue(ns, out prefix) == true) {
+                    if (ctx != this) // cache for the future use
+                        DefinePrefixNoCheck(ns, prefix);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public string CreateNamespacePrefix(string ns) {
+            var prefix = $"p{m_nextPrefix++}";
+            DefinePrefixNoCheck(ns, prefix);
+            return prefix;
+        }
+
+        void DefinePrefixNoCheck(string ns, string prefix) {
+            if (ns == null)
+                ns = string.Empty;
+            if (prefix == null)
+                prefix = string.Empty;
+
+            if (m_ns2prefix == null)
+                m_ns2prefix = new Dictionary<string, string>();
+            m_ns2prefix[ns] = prefix;
+
+            if (m_prefix2ns == null)
+                m_prefix2ns = new Dictionary<string, string>();
+            m_prefix2ns[prefix] = ns;
+        }
+
+        public void DefinePrefix(string ns, string prefix) {
+            // according to https://www.w3.org/TR/xml-names/#ns-decl
+
+            // It MUST NOT be declared . Other prefixes MUST NOT be bound to this namespace name, and it MUST NOT be declared as the default namespace
+            if (ns == XmlnsNamespace)
+                throw new Exception($"Attempt to define xmlns:{prefix}='{ns}'");
+
+            // It MAY, but need not, be declared, and MUST NOT be bound to any other namespace name
+            if (ns == XmlNamespace && prefix != XmlPrefix)
+                throw new Exception($"Attempt to define xmlns:{prefix}='{ns}'");
+
+            // add mapping
+            DefinePrefixNoCheck(ns, prefix);
+        }
+
+        public string ResolvePrefix(string prefix) {
+            if (prefix == null)
+                prefix = string.Empty;
+            string ns = null;
+            for(var ctx = this; ctx != null; ctx = ctx.ParentContext) {
+                if (ctx.m_prefix2ns?.TryGetValue(prefix, out ns) == true) {
+                    if (ctx != this) // cache for the future use
+                        DefinePrefixNoCheck(ns, prefix);
+                    return ns;
+                }
+            }
+            return null;
+        }
+        
+        public XmlQualifiedName Resolve(string name) {
+            Safe.ArgumentNotEmpty(name, nameof(name));
+            var parts = name.Split(_qNameDelim, 2, StringSplitOptions.RemoveEmptyEntries);
+
+            if (parts.Length == 2) {
+                return new XmlQualifiedName(parts[1], ResolvePrefix(parts[0]));
+            } else {
+                return new XmlQualifiedName(parts[0], ResolvePrefix(string.Empty));
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Xml/XmlSimpleAttribute.cs	Sat Sep 09 03:53:13 2017 +0300
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml;
+
+namespace Implab.Xml {
+    public class XmlSimpleAttribute {
+        public XmlSimpleAttribute(string name, string ns, string prefix, object value) {
+            QName = new XmlQualifiedName(name, ns);
+            Prefix = prefix;
+            Value = value;
+        }
+
+        public XmlQualifiedName QName { get; set; }
+
+        public string Prefix { get; set; }
+
+        public object Value { get; set; }
+    }
+}