diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..7b90091e
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,49 @@
+*.doc diff=astextplain
+*.DOC diff=astextplain
+*.docx diff=astextplain
+*.DOCX diff=astextplain
+*.dot diff=astextplain
+*.DOT diff=astextplain
+*.pdf diff=astextplain
+*.PDF diff=astextplain
+*.rtf diff=astextplain
+*.RTF diff=astextplain
+
+*.jpg binary
+*.png binary
+*.gif binary
+
+*.cs text diff=csharp
+*.vb text
+*.c text
+*.cpp text
+*.cxx text
+*.h text
+*.hxx text
+*.py text
+*.rb text
+*.java text
+*.html text
+*.htm text
+*.css text
+*.scss text
+*.sass text
+*.less text
+*.js text
+*.lisp text
+*.clj text
+*.sql text
+*.php text
+*.lua text
+*.m text
+*.asm text
+*.erl text
+*.fs text
+*.fsx text
+*.hs text
+
+*.csproj text merge=union
+*.vbproj text merge=union
+*.fsproj text merge=union
+*.dbproj text merge=union
+*.sln text eol=crlf merge=union
diff --git a/Build/build.ps1 b/Build/build.ps1
index fc673f04..faaed2b8 100644
--- a/Build/build.ps1
+++ b/Build/build.ps1
@@ -17,7 +17,7 @@
$workingDir = "$baseDir\Working"
$builds = @(
@{Name = "Newtonsoft.Json"; TestsName = "Newtonsoft.Json.Tests"; Constants=""; FinalDir="Net40"; NuGetDir = "net40"; Framework="net-4.0"; Sign=$true},
- @{Name = "Newtonsoft.Json.Metro"; TestsName = $null; Constants="NETFX_CORE"; FinalDir="Metro"; NuGetDir = "winrt45"; Framework="net-4.5"; Sign=$true},
+ #@{Name = "Newtonsoft.Json.Metro"; TestsName = $null; Constants="NETFX_CORE"; FinalDir="Metro"; NuGetDir = "winrt45"; Framework="net-4.5"; Sign=$true},
# unsigned SL/WP
@{Name = "Newtonsoft.Json.WindowsPhone"; TestsName = $null; Constants="SILVERLIGHT;WINDOWS_PHONE"; FinalDir="WindowsPhone"; NuGetDir = "sl3-wp,sl4-windowsphone71"; Framework="net-4.0"; Sign=$false},
diff --git a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs
index c4e4c93d..baea14c8 100644
--- a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs
+++ b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs
@@ -1,1801 +1,1811 @@
-#region License
-// Copyright (c) 2007 James Newton-King
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-#endregion
-
-#if !SILVERLIGHT && !NETFX_CORE
-using System;
-using System.Collections.Generic;
-using Newtonsoft.Json.Tests.Serialization;
-using Newtonsoft.Json.Tests.TestObjects;
-#if !NETFX_CORE
-using NUnit.Framework;
-#else
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using TestFixture = Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute;
-using Test = Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute;
-#endif
-using Newtonsoft.Json;
-using System.IO;
-using System.Xml;
-using Newtonsoft.Json.Converters;
-using Newtonsoft.Json.Utilities;
-using Newtonsoft.Json.Linq;
-#if !NET20
-using System.Xml.Linq;
-#endif
-
-namespace Newtonsoft.Json.Tests.Converters
-{
- [TestFixture]
- public class XmlNodeConverterTest : TestFixtureBase
- {
- private string SerializeXmlNode(XmlNode node)
- {
- string json = JsonConvert.SerializeXmlNode(node, Formatting.Indented);
- XmlNodeReader reader = new XmlNodeReader(node);
-
-#if !NET20
- XObject xNode;
- if (node is XmlDocument)
- {
- xNode = XDocument.Load(reader);
- }
- else if (node is XmlAttribute)
- {
- XmlAttribute attribute = (XmlAttribute) node;
- xNode = new XAttribute(XName.Get(attribute.LocalName, attribute.NamespaceURI), attribute.Value);
- }
- else
- {
- reader.MoveToContent();
- xNode = XNode.ReadFrom(reader);
- }
-
- string linqJson = JsonConvert.SerializeXNode(xNode, Formatting.Indented);
-
- Assert.AreEqual(json, linqJson);
-#endif
-
- return json;
- }
-
- private XmlNode DeserializeXmlNode(string json)
- {
- return DeserializeXmlNode(json, null);
- }
-
- private XmlNode DeserializeXmlNode(string json, string deserializeRootElementName)
- {
- JsonTextReader reader;
-
- reader = new JsonTextReader(new StringReader(json));
- reader.Read();
- XmlNodeConverter converter = new XmlNodeConverter();
- if (deserializeRootElementName != null)
- converter.DeserializeRootElementName = deserializeRootElementName;
-
- XmlNode node = (XmlNode)converter.ReadJson(reader, typeof (XmlDocument), null, new JsonSerializer());
-
-#if !NET20
- string xmlText = node.OuterXml;
-
- reader = new JsonTextReader(new StringReader(json));
- reader.Read();
- XDocument d = (XDocument) converter.ReadJson(reader, typeof (XDocument), null, new JsonSerializer());
-
- string linqXmlText = d.ToString(SaveOptions.DisableFormatting);
- if (d.Declaration != null)
- linqXmlText = d.Declaration + linqXmlText;
-
- Assert.AreEqual(xmlText, linqXmlText);
-#endif
-
- return node;
- }
-
- [Test]
- public void DocumentSerializeIndented()
- {
- string xml = @"
-
-
-
- Web 2.0 Conference
- October 5
- 7
- Argent Hotel, San Francisco, CA
-
-";
- XmlDocument doc = new XmlDocument();
- doc.LoadXml(xml);
-
- string jsonText = SerializeXmlNode(doc);
- string expected = @"{
- ""?xml"": {
- ""@version"": ""1.0"",
- ""@standalone"": ""no""
- },
- ""?xml-stylesheet"": ""href=\""classic.xsl\"" type=\""text/xml\"""",
- ""span"": {
- ""@class"": ""vevent"",
- ""a"": {
- ""@class"": ""url"",
- ""@href"": ""http://www.web2con.com/"",
- ""span"": [
- {
- ""@class"": ""summary"",
- ""#text"": ""Web 2.0 Conference"",
- ""#cdata-section"": ""my escaped text""
- },
- {
- ""@class"": ""location"",
- ""#text"": ""Argent Hotel, San Francisco, CA""
- }
- ],
- ""abbr"": [
- {
- ""@class"": ""dtstart"",
- ""@title"": ""2005-10-05"",
- ""#text"": ""October 5""
- },
- {
- ""@class"": ""dtend"",
- ""@title"": ""2005-10-08"",
- ""#text"": ""7""
- }
- ]
- }
- }
-}";
-
- Assert.AreEqual(expected, jsonText);
-
- Console.WriteLine("DocumentSerializeIndented");
- Console.WriteLine(jsonText);
- Console.WriteLine();
- }
-
- [Test]
- public void SerializeNodeTypes()
- {
- XmlDocument doc = new XmlDocument();
- string jsonText;
-
- Console.WriteLine("SerializeNodeTypes");
-
- string xml = @"
-
-
-
-";
-
- XmlDocument document = new XmlDocument();
- document.LoadXml(xml);
-
- // XmlAttribute
- XmlAttribute attribute = document.DocumentElement.ChildNodes[0].Attributes["IsDataSet", "urn:schemas-microsoft-com:xml-msdata"];
- attribute.Value = "true";
-
- jsonText = JsonConvert.SerializeXmlNode(attribute);
-
- Console.WriteLine(jsonText);
- Assert.AreEqual(@"{""@msdata:IsDataSet"":""true""}", jsonText);
-
-#if !NET20
- XDocument d = XDocument.Parse(xml);
- XAttribute a = d.Root.Element("{http://www.w3.org/2001/XMLSchema}element").Attribute("{urn:schemas-microsoft-com:xml-msdata}IsDataSet");
-
- jsonText = JsonConvert.SerializeXNode(a);
-
- Assert.AreEqual(@"{""@msdata:IsDataSet"":""true""}", jsonText);
-#endif
-
- // XmlProcessingInstruction
- XmlProcessingInstruction instruction = doc.CreateProcessingInstruction("xml-stylesheet", @"href=""classic.xsl"" type=""text/xml""");
-
- jsonText = JsonConvert.SerializeXmlNode(instruction);
-
- Console.WriteLine(jsonText);
- Assert.AreEqual(@"{""?xml-stylesheet"":""href=\""classic.xsl\"" type=\""text/xml\""""}", jsonText);
-
-
- // XmlProcessingInstruction
- XmlCDataSection cDataSection = doc.CreateCDataSection("true");
-
- jsonText = JsonConvert.SerializeXmlNode(cDataSection);
-
- Console.WriteLine(jsonText);
- Assert.AreEqual(@"{""#cdata-section"":""true""}", jsonText);
-
-
- // XmlElement
- XmlElement element = doc.CreateElement("xs", "Choice", "http://www.w3.org/2001/XMLSchema");
- element.SetAttributeNode(doc.CreateAttribute("msdata", "IsDataSet", "urn:schemas-microsoft-com:xml-msdata"));
-
- XmlAttribute aa = doc.CreateAttribute(@"xmlns", "xs", "http://www.w3.org/2000/xmlns/");
- aa.Value = "http://www.w3.org/2001/XMLSchema";
- element.SetAttributeNode(aa);
-
- aa = doc.CreateAttribute(@"xmlns", "msdata", "http://www.w3.org/2000/xmlns/");
- aa.Value = "urn:schemas-microsoft-com:xml-msdata";
- element.SetAttributeNode(aa);
-
- element.AppendChild(instruction);
- element.AppendChild(cDataSection);
-
- doc.AppendChild(element);
-
- jsonText = JsonConvert.SerializeXmlNode(element, Formatting.Indented);
-
- Assert.AreEqual(@"{
- ""xs:Choice"": {
- ""@msdata:IsDataSet"": """",
- ""@xmlns:xs"": ""http://www.w3.org/2001/XMLSchema"",
- ""@xmlns:msdata"": ""urn:schemas-microsoft-com:xml-msdata"",
- ""?xml-stylesheet"": ""href=\""classic.xsl\"" type=\""text/xml\"""",
- ""#cdata-section"": ""true""
- }
-}", jsonText);
- }
-
- [Test]
- public void DocumentFragmentSerialize()
- {
- XmlDocument doc = new XmlDocument();
-
- XmlDocumentFragment fragement = doc.CreateDocumentFragment();
-
- fragement.InnerXml = "- widget
- widget
";
-
- string jsonText = JsonConvert.SerializeXmlNode(fragement);
-
- string expected = @"{""Item"":[""widget"",""widget""]}";
-
- Assert.AreEqual(expected, jsonText);
-
- Console.WriteLine("DocumentFragmentSerialize");
- Console.WriteLine(jsonText);
- Console.WriteLine();
- }
-
- [Test]
- public void NamespaceSerializeDeserialize()
- {
- string xml = @"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-";
-
- XmlDocument doc = new XmlDocument();
- doc.LoadXml(xml);
-
- string jsonText = SerializeXmlNode(doc);
-
- string expected = @"{
- ""?xml"": {
- ""@version"": ""1.0"",
- ""@encoding"": ""utf-8""
- },
- ""xs:schema"": {
- ""@xs:id"": ""SomeID"",
- ""@xmlns"": """",
- ""@xmlns:xs"": ""http://www.w3.org/2001/XMLSchema"",
- ""@xmlns:msdata"": ""urn:schemas-microsoft-com:xml-msdata"",
- ""xs:element"": {
- ""@name"": ""MyDataSet"",
- ""@msdata:IsDataSet"": ""true"",
- ""xs:complexType"": {
- ""xs:choice"": {
- ""@maxOccurs"": ""unbounded"",
- ""xs:element"": {
- ""@name"": ""customers"",
- ""xs:complexType"": {
- ""xs:sequence"": {
- ""xs:element"": [
- {
- ""@name"": ""CustomerID"",
- ""@type"": ""xs:integer"",
- ""@minOccurs"": ""0""
- },
- {
- ""@name"": ""CompanyName"",
- ""@type"": ""xs:string"",
- ""@minOccurs"": ""0""
- },
- {
- ""@name"": ""Phone"",
- ""@type"": ""xs:string""
- }
- ]
- }
- }
- }
- }
- }
- }
- }
-}";
-
- Assert.AreEqual(expected, jsonText);
-
- XmlDocument deserializedDoc = (XmlDocument)DeserializeXmlNode(jsonText);
-
- Assert.AreEqual(doc.InnerXml, deserializedDoc.InnerXml);
-
- Console.WriteLine("NamespaceSerializeDeserialize");
- Console.WriteLine(jsonText);
- Console.WriteLine(deserializedDoc.InnerXml);
- Console.WriteLine();
- }
-
- [Test]
- public void DocumentDeserialize()
- {
- string jsonText = @"{
- ""?xml"": {
- ""@version"": ""1.0"",
- ""@standalone"": ""no""
- },
- ""span"": {
- ""@class"": ""vevent"",
- ""a"": {
- ""@class"": ""url"",
- ""@href"": ""http://www.web2con.com/"",
- ""span"": {
- ""@class"": ""summary"",
- ""#text"": ""Web 2.0 Conference"",
- ""#cdata-section"": ""my escaped text""
- }
- }
- }
-}";
-
- XmlDocument doc = (XmlDocument)DeserializeXmlNode(jsonText);
-
- string expected = @"
-
-
- Web 2.0 Conference
-
-";
-
- string formattedXml = GetIndentedInnerXml(doc);
-
- Console.WriteLine("DocumentDeserialize");
- Console.WriteLine(formattedXml);
- Console.WriteLine();
-
- Assert.AreEqual(expected, formattedXml);
- }
-
- private string GetIndentedInnerXml(XmlNode node)
- {
- XmlWriterSettings settings = new XmlWriterSettings();
- settings.Indent = true;
-
- StringWriter sw = new StringWriter();
-
- using (XmlWriter writer = XmlWriter.Create(sw, settings))
- {
- node.WriteTo(writer);
- }
-
- return sw.ToString();
- }
-
- [Test]
- public void SingleTextNode()
- {
- string xml = @"
-
-
- Alan
- http://www.google.com
-
-
- Louis
- http://www.yahoo.com
-
- ";
-
- XmlDocument doc = new XmlDocument();
- doc.LoadXml(xml);
-
- string jsonText = SerializeXmlNode(doc);
-
- XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
-
- Assert.AreEqual(doc.InnerXml, newDoc.InnerXml);
- }
-
- [Test]
- public void EmptyNode()
- {
- string xml = @"
-
-
- Alan
-
-
-
- Louis
- http://www.yahoo.com
-
- ";
-
- XmlDocument doc = new XmlDocument();
- doc.LoadXml(xml);
-
- string jsonText = SerializeXmlNode(doc);
-
- Console.WriteLine(jsonText);
-
- XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
-
- Assert.AreEqual(doc.InnerXml, newDoc.InnerXml);
- }
-
- [Test]
- public void OtherElementDataTypes()
- {
- string jsonText = @"{""?xml"":{""@version"":""1.0"",""@standalone"":""no""},""root"":{""person"":[{""@id"":""1"",""Float"":2.5,""Integer"":99},{""@id"":""2"",""Boolean"":true,""date"":""\/Date(954374400000)\/""}]}}";
-
- XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
-
- string expected = @"2.599true2000-03-30T00:00:00Z";
-
- Assert.AreEqual(expected, newDoc.InnerXml);
- }
-
- [Test]
- [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "XmlNodeConverter can only convert JSON that begins with an object.")]
- public void NoRootObject()
- {
- XmlDocument newDoc = (XmlDocument)JsonConvert.DeserializeXmlNode(@"[1]");
- }
-
- [Test]
- [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifing a DeserializeRootElementName.")]
- public void RootObjectMultipleProperties()
- {
- XmlDocument newDoc = (XmlDocument)JsonConvert.DeserializeXmlNode(@"{Prop1:1,Prop2:2}");
- }
-
- [Test]
- public void JavaScriptConstructor()
- {
- string jsonText = @"{root:{r:new Date(34343, 55)}}";
-
- XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
-
- string expected = @"3434355";
-
- Assert.AreEqual(expected, newDoc.InnerXml);
-
- string json = SerializeXmlNode(newDoc);
- expected = @"{
- ""root"": {
- ""r"": {
- ""Date"": [
- ""34343"",
- ""55""
- ]
- }
- }
-}";
-
- Assert.AreEqual(expected, json);
- }
-
- [Test]
- public void ForceJsonArray()
- {
- string arrayXml = @"
-
- Alan
- http://www.google.com
- Admin
-
- ";
-
- XmlDocument arrayDoc = new XmlDocument();
- arrayDoc.LoadXml(arrayXml);
-
- string arrayJsonText = SerializeXmlNode(arrayDoc);
- string expected = @"{
- ""root"": {
- ""person"": {
- ""@id"": ""1"",
- ""name"": ""Alan"",
- ""url"": ""http://www.google.com"",
- ""role"": [
- ""Admin""
- ]
- }
- }
-}";
- Assert.AreEqual(expected, arrayJsonText);
-
- arrayXml = @"
-
- Alan
- http://www.google.com
- Admin1
- Admin2
-
- ";
-
- arrayDoc = new XmlDocument();
- arrayDoc.LoadXml(arrayXml);
-
- arrayJsonText = SerializeXmlNode(arrayDoc);
- expected = @"{
- ""root"": {
- ""person"": {
- ""@id"": ""1"",
- ""name"": ""Alan"",
- ""url"": ""http://www.google.com"",
- ""role"": [
- ""Admin1"",
- ""Admin2""
- ]
- }
- }
-}";
- Assert.AreEqual(expected, arrayJsonText);
-
- arrayXml = @"
-
- Alan
- http://www.google.com
- Admin1
-
- ";
-
- arrayDoc = new XmlDocument();
- arrayDoc.LoadXml(arrayXml);
-
- arrayJsonText = SerializeXmlNode(arrayDoc);
- expected = @"{
- ""root"": {
- ""person"": {
- ""@id"": ""1"",
- ""name"": ""Alan"",
- ""url"": ""http://www.google.com"",
- ""role"": ""Admin1""
- }
- }
-}";
- Assert.AreEqual(expected, arrayJsonText);
- }
-
- [Test]
- [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifing a DeserializeRootElementName.")]
- public void MultipleRootPropertiesXmlDocument()
- {
- string json = @"{""count"": 773840,""photos"": null}";
-
- JsonConvert.DeserializeXmlNode(json);
- }
-
-#if !NET20
- [Test]
- [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifing a DeserializeRootElementName.")]
- public void MultipleRootPropertiesXDocument()
- {
- string json = @"{""count"": 773840,""photos"": null}";
-
- JsonConvert.DeserializeXNode(json);
- }
-#endif
-
- [Test]
- public void MultipleRootPropertiesAddRootElement()
- {
- string json = @"{""count"": 773840,""photos"": 773840}";
-
- XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot");
-
- Assert.AreEqual(@"773840773840", newDoc.InnerXml);
-
-#if !NET20
- XDocument newXDoc = JsonConvert.DeserializeXNode(json, "myRoot");
-
- Assert.AreEqual(@"773840773840", newXDoc.ToString(SaveOptions.DisableFormatting));
-#endif
- }
-
- [Test]
- public void NestedArrays()
- {
- string json = @"{
- ""available_sizes"": [
- [
- ""assets/images/resized/0001/1070/11070v1-max-150x150.jpg"",
- ""assets/images/resized/0001/1070/11070v1-max-150x150.jpg""
- ],
- [
- ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg"",
- ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
- ],
- [
- ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
- ]
- ]
-}";
-
- XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot");
-
- string xml = IndentXml(newDoc.InnerXml);
-
- Assert.AreEqual(@"
-
- assets/images/resized/0001/1070/11070v1-max-150x150.jpg
- assets/images/resized/0001/1070/11070v1-max-150x150.jpg
-
-
- assets/images/resized/0001/1070/11070v1-max-250x250.jpg
- assets/images/resized/0001/1070/11070v1-max-250x250.jpg
-
-
- assets/images/resized/0001/1070/11070v1-max-250x250.jpg
-
-", IndentXml(newDoc.InnerXml));
-
-#if !NET20
- XDocument newXDoc = JsonConvert.DeserializeXNode(json, "myRoot");
-
- Assert.AreEqual(@"
-
- assets/images/resized/0001/1070/11070v1-max-150x150.jpg
- assets/images/resized/0001/1070/11070v1-max-150x150.jpg
-
-
- assets/images/resized/0001/1070/11070v1-max-250x250.jpg
- assets/images/resized/0001/1070/11070v1-max-250x250.jpg
-
-
- assets/images/resized/0001/1070/11070v1-max-250x250.jpg
-
-", IndentXml(newXDoc.ToString(SaveOptions.DisableFormatting)));
-#endif
-
- string newJson = JsonConvert.SerializeXmlNode(newDoc, Formatting.Indented);
- Console.WriteLine(newJson);
- }
-
- [Test]
- public void RoundTripNestedArrays()
- {
- string json = @"{
- ""available_sizes"": [
- [
- ""assets/images/resized/0001/1070/11070v1-max-150x150.jpg"",
- ""assets/images/resized/0001/1070/11070v1-max-150x150.jpg""
- ],
- [
- ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg"",
- ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
- ],
- [
- ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
- ]
- ]
-}";
-
- XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot", true);
-
- Assert.AreEqual(@"
-
- assets/images/resized/0001/1070/11070v1-max-150x150.jpg
- assets/images/resized/0001/1070/11070v1-max-150x150.jpg
-
-
- assets/images/resized/0001/1070/11070v1-max-250x250.jpg
- assets/images/resized/0001/1070/11070v1-max-250x250.jpg
-
-
- assets/images/resized/0001/1070/11070v1-max-250x250.jpg
-
-", IndentXml(newDoc.InnerXml));
-
-#if !NET20
- XDocument newXDoc = JsonConvert.DeserializeXNode(json, "myRoot", true);
-
- Console.WriteLine(IndentXml(newXDoc.ToString(SaveOptions.DisableFormatting)));
-
- Assert.AreEqual(@"
-
- assets/images/resized/0001/1070/11070v1-max-150x150.jpg
- assets/images/resized/0001/1070/11070v1-max-150x150.jpg
-
-
- assets/images/resized/0001/1070/11070v1-max-250x250.jpg
- assets/images/resized/0001/1070/11070v1-max-250x250.jpg
-
-
- assets/images/resized/0001/1070/11070v1-max-250x250.jpg
-
-", IndentXml(newXDoc.ToString(SaveOptions.DisableFormatting)));
-#endif
-
- string newJson = JsonConvert.SerializeXmlNode(newDoc, Formatting.Indented, true);
- Assert.AreEqual(json, newJson);
- }
-
- [Test]
- public void MultipleNestedArraysToXml()
- {
- string json = @"{
- ""available_sizes"": [
- [
- [113, 150],
- ""assets/images/resized/0001/1070/11070v1-max-150x150.jpg""
- ],
- [
- [189, 250],
- ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
- ],
- [
- [341, 450],
- ""assets/images/resized/0001/1070/11070v1-max-450x450.jpg""
- ]
- ]
-}";
-
- XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot");
-
- Assert.AreEqual(@"113150assets/images/resized/0001/1070/11070v1-max-150x150.jpg189250assets/images/resized/0001/1070/11070v1-max-250x250.jpg341450assets/images/resized/0001/1070/11070v1-max-450x450.jpg", newDoc.InnerXml);
-
-#if !NET20
- XDocument newXDoc = JsonConvert.DeserializeXNode(json, "myRoot");
-
- Assert.AreEqual(@"113150assets/images/resized/0001/1070/11070v1-max-150x150.jpg189250assets/images/resized/0001/1070/11070v1-max-250x250.jpg341450assets/images/resized/0001/1070/11070v1-max-450x450.jpg", newXDoc.ToString(SaveOptions.DisableFormatting));
-#endif
- }
-
- [Test]
- public void Encoding()
- {
- XmlDocument doc = new XmlDocument();
-
- doc.LoadXml(@"O""Connor"); // i use "" so it will be easier to see the problem
-
- string json = SerializeXmlNode(doc);
- Assert.AreEqual(@"{
- ""name"": ""O\""Connor""
-}", json);
- }
-
- [Test]
- public void SerializeComment()
- {
- string xml = @"
- Text
-";
- XmlDocument doc = new XmlDocument();
- doc.LoadXml(xml);
-
- string jsonText = SerializeXmlNode(doc);
-
- string expected = @"{
- ""span"": {
- ""@class"": ""vevent"",
- ""a"": {
- ""@class"": ""url"",
- ""@href"": ""http://www.web2con.com/"",
- ""#text"": ""Text""
- }/* Hi! */
- }
-}";
-
- Assert.AreEqual(expected, jsonText);
-
- XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
- Assert.AreEqual(@"Text", newDoc.InnerXml);
- }
-
- [Test]
- public void SerializeExample()
- {
- string xml = @"
-
-
- Alan
- http://www.google.com
-
-
- Louis
- http://www.yahoo.com
-
- ";
-
- XmlDocument doc = new XmlDocument();
- doc.LoadXml(xml);
-
- string jsonText = SerializeXmlNode(doc);
- // {
- // "?xml": {
- // "@version": "1.0",
- // "@standalone": "no"
- // },
- // "root": {
- // "person": [
- // {
- // "@id": "1",
- // "name": "Alan",
- // "url": "http://www.google.com"
- // },
- // {
- // "@id": "2",
- // "name": "Louis",
- // "url": "http://www.yahoo.com"
- // }
- // ]
- // }
- // }
-
- // format
- jsonText = JObject.Parse(jsonText).ToString();
-
- Assert.AreEqual(@"{
- ""?xml"": {
- ""@version"": ""1.0"",
- ""@standalone"": ""no""
- },
- ""root"": {
- ""person"": [
- {
- ""@id"": ""1"",
- ""name"": ""Alan"",
- ""url"": ""http://www.google.com""
- },
- {
- ""@id"": ""2"",
- ""name"": ""Louis"",
- ""url"": ""http://www.yahoo.com""
- }
- ]
- }
-}", jsonText);
-
- XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
-
- Assert.AreEqual(doc.InnerXml, newDoc.InnerXml);
- }
-
- [Test]
- public void DeserializeExample()
- {
- string json = @"{
- ""?xml"": {
- ""@version"": ""1.0"",
- ""@standalone"": ""no""
- },
- ""root"": {
- ""person"": [
- {
- ""@id"": ""1"",
- ""name"": ""Alan"",
- ""url"": ""http://www.google.com""
- },
- {
- ""@id"": ""2"",
- ""name"": ""Louis"",
- ""url"": ""http://www.yahoo.com""
- }
- ]
- }
- }";
-
- XmlDocument doc = (XmlDocument)DeserializeXmlNode(json);
- //
- //
- //
- // Alan
- // http://www.google.com
- //
- //
- // Louis
- // http://www.yahoo.com
- //
- //
-
- Assert.AreEqual(@"
-
-
-Alan
-http://www.google.com
-
-
-Louis
-http://www.yahoo.com
-
-".Replace(Environment.NewLine, string.Empty), doc.InnerXml);
- }
-
- [Test]
- public void SerializeDeserializeSpecialProperties()
- {
- PreserveReferencesHandlingTests.CircularDictionary circularDictionary = new PreserveReferencesHandlingTests.CircularDictionary();
- circularDictionary.Add("other", new PreserveReferencesHandlingTests.CircularDictionary { { "blah", null } });
- circularDictionary.Add("self", circularDictionary);
-
- string json = JsonConvert.SerializeObject(circularDictionary, Formatting.Indented,
- new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
-
- Assert.AreEqual(@"{
- ""$id"": ""1"",
- ""other"": {
- ""$id"": ""2"",
- ""blah"": null
- },
- ""self"": {
- ""$ref"": ""1""
- }
-}", json);
-
- XmlNode node = DeserializeXmlNode(json, "root");
- string xml = GetIndentedInnerXml(node);
- string expected = @"
-
-
-
-
-
-";
-
- Assert.AreEqual(expected, xml);
-
- string xmlJson = SerializeXmlNode(node);
- string expectedXmlJson = @"{
- ""root"": {
- ""$id"": ""1"",
- ""other"": {
- ""$id"": ""2"",
- ""blah"": null
- },
- ""self"": {
- ""$ref"": ""1""
- }
- }
-}";
-
- Assert.AreEqual(expectedXmlJson, xmlJson);
- }
-
- [Test]
- [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "XmlNodeConverter cannot convert JSON with an empty property name to XML.")]
- public void EmptyPropertyName()
- {
- string json = @"{
- ""8452309520V2"": {
- """": {
- ""CLIENT"": {
- ""ID_EXPIRATION_1"": {
- ""VALUE"": ""12/12/2000"",
- ""DATATYPE"": ""D"",
- ""MSG"": ""Missing Identification Exp. Date 1""
- },
- ""ID_ISSUEDATE_1"": {
- ""VALUE"": """",
- ""DATATYPE"": ""D"",
- ""MSG"": ""Missing Identification Issue Date 1""
- }
- }
- },
- ""457463534534"": {
- ""ACCOUNT"": {
- ""FUNDING_SOURCE"": {
- ""VALUE"": ""FS0"",
- ""DATATYPE"": ""L"",
- ""MSG"": ""Missing Source of Funds""
- }
- }
- }
- }
-}{
- ""34534634535345"": {
- """": {
- ""CLIENT"": {
- ""ID_NUMBER_1"": {
- ""VALUE"": """",
- ""DATATYPE"": ""S"",
- ""MSG"": ""Missing Picture ID""
- },
- ""ID_EXPIRATION_1"": {
- ""VALUE"": ""12/12/2000"",
- ""DATATYPE"": ""D"",
- ""MSG"": ""Missing Picture ID""
- },
- ""WALK_IN"": {
- ""VALUE"": """",
- ""DATATYPE"": ""L"",
- ""MSG"": ""Missing Walk in""
- },
- ""PERSONAL_MEETING"": {
- ""VALUE"": ""PM1"",
- ""DATATYPE"": ""L"",
- ""MSG"": ""Missing Met Client in Person""
- },
- ""ID_ISSUEDATE_1"": {
- ""VALUE"": """",
- ""DATATYPE"": ""D"",
- ""MSG"": ""Missing Picture ID""
- },
- ""PHOTO_ID"": {
- ""VALUE"": """",
- ""DATATYPE"": ""L"",
- ""MSG"": ""Missing Picture ID""
- },
- ""ID_TYPE_1"": {
- ""VALUE"": """",
- ""DATATYPE"": ""L"",
- ""MSG"": ""Missing Picture ID""
- }
- }
- },
- ""45635624523"": {
- ""ACCOUNT"": {
- ""FUNDING_SOURCE"": {
- ""VALUE"": ""FS1"",
- ""DATATYPE"": ""L"",
- ""MSG"": ""Missing Source of Funds""
- }
- }
- }
- }
-}";
-
- DeserializeXmlNode(json);
- }
-
- [Test]
- public void SingleItemArrayPropertySerialization()
- {
- Product product = new Product();
-
- product.Name = "Apple";
- product.ExpiryDate = new DateTime(2008, 12, 28, 0, 0, 0, DateTimeKind.Utc);
- product.Price = 3.99M;
- product.Sizes = new string[] { "Small" };
-
- string output = JsonConvert.SerializeObject(product, new IsoDateTimeConverter());
-
- XmlDocument xmlProduct = JsonConvert.DeserializeXmlNode(output, "product", true);
-
- Assert.AreEqual(@"
- Apple
- 2008-12-28T00:00:00Z
- 3.99
- Small
-", IndentXml(xmlProduct.InnerXml));
-
- string output2 = JsonConvert.SerializeXmlNode(xmlProduct.DocumentElement, Formatting.Indented);
-
- Assert.AreEqual(@"{
- ""product"": {
- ""Name"": ""Apple"",
- ""ExpiryDate"": ""2008-12-28T00:00:00Z"",
- ""Price"": ""3.99"",
- ""Sizes"": [
- ""Small""
- ]
- }
-}", output2);
- }
-
- public class TestComplexArrayClass
- {
- public string Name { get; set; }
- public IList Products { get; set; }
- }
-
- [Test]
- public void ComplexSingleItemArrayPropertySerialization()
- {
- TestComplexArrayClass o = new TestComplexArrayClass
- {
- Name = "Hi",
- Products = new List
- {
- new Product { Name = "First" }
- }
- };
-
- string output = JsonConvert.SerializeObject(o, new IsoDateTimeConverter());
-
- XmlDocument xmlProduct = JsonConvert.DeserializeXmlNode(output, "test", true);
-
- Assert.AreEqual(@"
- Hi
-
- First
- 2000-01-01T00:00:00Z
- 0
-
-
-", IndentXml(xmlProduct.InnerXml));
-
- string output2 = JsonConvert.SerializeXmlNode(xmlProduct.DocumentElement, Formatting.Indented, true);
-
- Assert.AreEqual(@"{
- ""Name"": ""Hi"",
- ""Products"": [
- {
- ""Name"": ""First"",
- ""ExpiryDate"": ""2000-01-01T00:00:00Z"",
- ""Price"": ""0"",
- ""Sizes"": null
- }
- ]
-}", output2);
- }
-
- private string IndentXml(string xml)
- {
- XmlReader reader = XmlReader.Create(new StringReader(xml));
-
- StringWriter sw = new StringWriter();
- XmlWriter writer = XmlWriter.Create(sw, new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true });
-
- while (reader.Read())
- {
- writer.WriteNode(reader, false);
- }
-
- writer.Flush();
-
- return sw.ToString();
- }
-
- [Test]
- public void OmitRootObject()
- {
- string xml = @"
- Hi
- Hi
-
- First
- 2000-01-01T00:00:00Z
- 0
-
-
-";
-
- XmlDocument d = new XmlDocument();
- d.LoadXml(xml);
-
- string output = JsonConvert.SerializeXmlNode(d, Formatting.Indented, true);
-
- Assert.AreEqual(@"{
- ""Name"": [
- ""Hi"",
- ""Hi""
- ],
- ""Products"": [
- {
- ""Name"": ""First"",
- ""ExpiryDate"": ""2000-01-01T00:00:00Z"",
- ""Price"": ""0"",
- ""Sizes"": null
- }
- ]
-}", output);
- }
-
- [Test]
- public void EmtpyElementWithArrayAttributeShouldWriteAttributes()
- {
- string xml = @"
-
-
-
-
-
-
-";
-
- XmlDocument d = new XmlDocument();
- d.LoadXml(xml);
-
- string json = JsonConvert.SerializeXmlNode(d, Formatting.Indented);
-
- Assert.AreEqual(@"{
- ""?xml"": {
- ""@version"": ""1.0"",
- ""@encoding"": ""utf-8""
- },
- ""root"": {
- ""A"": {
- ""B"": [
- {
- ""@name"": ""sample""
- }
- ],
- ""C"": [
- null,
- null
- ]
- }
- }
-}", json);
- }
-
- [Test]
- public void DeserializeNonInt64IntegerValues()
- {
- var dict = new Dictionary { { "Int16", (short)1 }, { "Float", 2f }, { "Int32", 3 } };
- var obj = JObject.FromObject(dict);
- var serializer = JsonSerializer.Create(new JsonSerializerSettings { Converters = { new XmlNodeConverter() { DeserializeRootElementName = "root" } } });
- using (var reader = obj.CreateReader())
- {
- var value = (XmlDocument)serializer.Deserialize(reader, typeof(XmlDocument));
-
- Assert.AreEqual(@"123", value.InnerXml);
- }
- }
-
- [Test]
- public void DeserializingBooleanValues()
- {
- MemoryStream ms = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(@"{root:{""@booleanType"":true}}"));
- MemoryStream xml = new MemoryStream();
-
- JsonBodyToSoapXml(ms, xml);
-
- string xmlString = System.Text.Encoding.UTF8.GetString(xml.ToArray());
-
- Assert.AreEqual(@"", xmlString);
- }
-
- private static void JsonBodyToSoapXml(Stream json, Stream xml)
- {
- Newtonsoft.Json.JsonSerializerSettings settings = new Newtonsoft.Json.JsonSerializerSettings();
- settings.Converters.Add(new Newtonsoft.Json.Converters.XmlNodeConverter());
- Newtonsoft.Json.JsonSerializer serializer = Newtonsoft.Json.JsonSerializer.Create(settings);
- using (Newtonsoft.Json.JsonTextReader reader = new Newtonsoft.Json.JsonTextReader(new System.IO.StreamReader(json)))
- {
- XmlDocument doc = (XmlDocument)serializer.Deserialize(reader, typeof(XmlDocument));
- if (reader.Read() && reader.TokenType != JsonToken.Comment)
- throw new JsonSerializationException("Additional text found in JSON string after finishing deserializing object.");
- using (XmlWriter writer = XmlWriter.Create(xml))
- {
- doc.Save(writer);
- }
- }
- }
-
-#if !NET20
- [Test]
- public void DeserializeXNodeDefaultNamespace()
- {
- string xaml = @"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-";
-
- string json = JsonConvert.SerializeXNode(XDocument.Parse(xaml), Formatting.Indented);
-
- string expectedJson = @"{
- ""Grid"": {
- ""@xmlns"": ""http://schemas.microsoft.com/winfx/2006/xaml/presentation"",
- ""@xmlns:x"": ""http://schemas.microsoft.com/winfx/2006/xaml"",
- ""@xmlns:toolkit"": ""clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"",
- ""@Style"": ""{StaticResource trimFormGrid}"",
- ""@x:Name"": ""TrimObjectForm"",
- ""Grid.ColumnDefinitions"": {
- ""ColumnDefinition"": [
- {
- ""@Width"": ""63*""
- },
- {
- ""@Width"": ""320*""
- }
- ]
- },
- ""Grid.RowDefinitions"": {
- ""@xmlns"": """",
- ""RowDefinition"": [
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null
- ]
- },
- ""TextBox"": [
- {
- ""@Style"": ""{StaticResource trimFormGrid_TB}"",
- ""@Text"": ""{Binding TypedTitle, Converter={StaticResource trimPropertyConverter}}"",
- ""@Name"": ""RecordTypedTitle"",
- ""@Grid.Column"": ""1"",
- ""@Grid.Row"": ""0"",
- ""@xmlns"": """"
- },
- {
- ""@Style"": ""{StaticResource trimFormGrid_TB}"",
- ""@Text"": ""{Binding ExternalReference, Converter={StaticResource trimPropertyConverter}}"",
- ""@Name"": ""RecordExternalReference"",
- ""@Grid.Column"": ""1"",
- ""@Grid.Row"": ""1"",
- ""@xmlns"": """"
- },
- {
- ""@Style"": ""{StaticResource trimFormGrid_TB}"",
- ""@Text"": ""{Binding Author, Converter={StaticResource trimPropertyConverter}}"",
- ""@Name"": ""RecordAuthor"",
- ""@Grid.Column"": ""1"",
- ""@Grid.Row"": ""4"",
- ""@xmlns"": """"
- },
- {
- ""@Style"": ""{StaticResource trimFormGrid_TB}"",
- ""@Text"": ""{Binding Container, Converter={StaticResource trimPropertyConverter}}"",
- ""@Name"": ""RecordContainer"",
- ""@Grid.Column"": ""1"",
- ""@Grid.Row"": ""5"",
- ""@xmlns"": """"
- },
- {
- ""@Style"": ""{StaticResource trimFormGrid_TB}"",
- ""@Text"": ""{Binding IsEnclosed, Converter={StaticResource trimPropertyConverter}}"",
- ""@Name"": ""RecordIsEnclosed"",
- ""@Grid.Column"": ""1"",
- ""@Grid.Row"": ""6"",
- ""@xmlns"": """"
- },
- {
- ""@Style"": ""{StaticResource trimFormGrid_TB}"",
- ""@Text"": ""{Binding Assignee, Converter={StaticResource trimPropertyConverter}}"",
- ""@Name"": ""RecordAssignee"",
- ""@Grid.Column"": ""1"",
- ""@Grid.Row"": ""7"",
- ""@xmlns"": """"
- }
- ],
- ""toolkit:DatePicker"": [
- {
- ""@Style"": ""{StaticResource trimFormGrid_DP}"",
- ""@Value"": ""{Binding DateCreated, Converter={StaticResource trimPropertyConverter}}"",
- ""@Name"": ""RecordDateCreated"",
- ""@Grid.Column"": ""1"",
- ""@Grid.Row"": ""2""
- },
- {
- ""@Style"": ""{StaticResource trimFormGrid_DP}"",
- ""@Value"": ""{Binding DateDue, Converter={StaticResource trimPropertyConverter}}"",
- ""@Name"": ""RecordDateDue"",
- ""@Grid.Column"": ""1"",
- ""@Grid.Row"": ""3""
- }
- ],
- ""TextBlock"": [
- {
- ""@Grid.Column"": ""0"",
- ""@Text"": ""Title (Free Text Part)"",
- ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
- ""@Grid.Row"": ""0"",
- ""@xmlns"": """"
- },
- {
- ""@Grid.Column"": ""0"",
- ""@Text"": ""External ID"",
- ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
- ""@Grid.Row"": ""1"",
- ""@xmlns"": """"
- },
- {
- ""@Grid.Column"": ""0"",
- ""@Text"": ""Date Created"",
- ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
- ""@Grid.Row"": ""2"",
- ""@xmlns"": """"
- },
- {
- ""@Grid.Column"": ""0"",
- ""@Text"": ""Date Due"",
- ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
- ""@Grid.Row"": ""3"",
- ""@xmlns"": """"
- },
- {
- ""@Grid.Column"": ""0"",
- ""@Text"": ""Author"",
- ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
- ""@Grid.Row"": ""4"",
- ""@xmlns"": """"
- },
- {
- ""@Grid.Column"": ""0"",
- ""@Text"": ""Container"",
- ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
- ""@Grid.Row"": ""5"",
- ""@xmlns"": """"
- },
- {
- ""@Grid.Column"": ""0"",
- ""@Text"": ""Enclosed?"",
- ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
- ""@Grid.Row"": ""6"",
- ""@xmlns"": """"
- },
- {
- ""@Grid.Column"": ""0"",
- ""@Text"": ""Assignee"",
- ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
- ""@Grid.Row"": ""7"",
- ""@xmlns"": """"
- }
- ]
- }
-}";
-
- Assert.AreEqual(expectedJson, json);
-
- XNode node = JsonConvert.DeserializeXNode(json);
-
- string xaml2 = node.ToString();
-
- string expectedXaml = @"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-";
-
- Assert.AreEqual(expectedXaml, xaml2);
- }
-#endif
-
- [Test]
- public void DeserializeXmlNodeDefaultNamespace()
- {
- string xaml = @"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-";
-
- XmlDocument document = new XmlDocument();
- document.LoadXml(xaml);
-
- string json = JsonConvert.SerializeXmlNode(document, Formatting.Indented);
-
- string expectedJson = @"{
- ""Grid"": {
- ""@xmlns"": ""http://schemas.microsoft.com/winfx/2006/xaml/presentation"",
- ""@xmlns:x"": ""http://schemas.microsoft.com/winfx/2006/xaml"",
- ""@xmlns:toolkit"": ""clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"",
- ""@Style"": ""{StaticResource trimFormGrid}"",
- ""@x:Name"": ""TrimObjectForm"",
- ""Grid.ColumnDefinitions"": {
- ""ColumnDefinition"": [
- {
- ""@Width"": ""63*""
- },
- {
- ""@Width"": ""320*""
- }
- ]
- },
- ""Grid.RowDefinitions"": {
- ""@xmlns"": """",
- ""RowDefinition"": [
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null
- ]
- },
- ""TextBox"": [
- {
- ""@Style"": ""{StaticResource trimFormGrid_TB}"",
- ""@Text"": ""{Binding TypedTitle, Converter={StaticResource trimPropertyConverter}}"",
- ""@Name"": ""RecordTypedTitle"",
- ""@Grid.Column"": ""1"",
- ""@Grid.Row"": ""0"",
- ""@xmlns"": """"
- },
- {
- ""@Style"": ""{StaticResource trimFormGrid_TB}"",
- ""@Text"": ""{Binding ExternalReference, Converter={StaticResource trimPropertyConverter}}"",
- ""@Name"": ""RecordExternalReference"",
- ""@Grid.Column"": ""1"",
- ""@Grid.Row"": ""1"",
- ""@xmlns"": """"
- },
- {
- ""@Style"": ""{StaticResource trimFormGrid_TB}"",
- ""@Text"": ""{Binding Author, Converter={StaticResource trimPropertyConverter}}"",
- ""@Name"": ""RecordAuthor"",
- ""@Grid.Column"": ""1"",
- ""@Grid.Row"": ""4"",
- ""@xmlns"": """"
- },
- {
- ""@Style"": ""{StaticResource trimFormGrid_TB}"",
- ""@Text"": ""{Binding Container, Converter={StaticResource trimPropertyConverter}}"",
- ""@Name"": ""RecordContainer"",
- ""@Grid.Column"": ""1"",
- ""@Grid.Row"": ""5"",
- ""@xmlns"": """"
- },
- {
- ""@Style"": ""{StaticResource trimFormGrid_TB}"",
- ""@Text"": ""{Binding IsEnclosed, Converter={StaticResource trimPropertyConverter}}"",
- ""@Name"": ""RecordIsEnclosed"",
- ""@Grid.Column"": ""1"",
- ""@Grid.Row"": ""6"",
- ""@xmlns"": """"
- },
- {
- ""@Style"": ""{StaticResource trimFormGrid_TB}"",
- ""@Text"": ""{Binding Assignee, Converter={StaticResource trimPropertyConverter}}"",
- ""@Name"": ""RecordAssignee"",
- ""@Grid.Column"": ""1"",
- ""@Grid.Row"": ""7"",
- ""@xmlns"": """"
- }
- ],
- ""toolkit:DatePicker"": [
- {
- ""@Style"": ""{StaticResource trimFormGrid_DP}"",
- ""@Value"": ""{Binding DateCreated, Converter={StaticResource trimPropertyConverter}}"",
- ""@Name"": ""RecordDateCreated"",
- ""@Grid.Column"": ""1"",
- ""@Grid.Row"": ""2""
- },
- {
- ""@Style"": ""{StaticResource trimFormGrid_DP}"",
- ""@Value"": ""{Binding DateDue, Converter={StaticResource trimPropertyConverter}}"",
- ""@Name"": ""RecordDateDue"",
- ""@Grid.Column"": ""1"",
- ""@Grid.Row"": ""3""
- }
- ],
- ""TextBlock"": [
- {
- ""@Grid.Column"": ""0"",
- ""@Text"": ""Title (Free Text Part)"",
- ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
- ""@Grid.Row"": ""0"",
- ""@xmlns"": """"
- },
- {
- ""@Grid.Column"": ""0"",
- ""@Text"": ""External ID"",
- ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
- ""@Grid.Row"": ""1"",
- ""@xmlns"": """"
- },
- {
- ""@Grid.Column"": ""0"",
- ""@Text"": ""Date Created"",
- ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
- ""@Grid.Row"": ""2"",
- ""@xmlns"": """"
- },
- {
- ""@Grid.Column"": ""0"",
- ""@Text"": ""Date Due"",
- ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
- ""@Grid.Row"": ""3"",
- ""@xmlns"": """"
- },
- {
- ""@Grid.Column"": ""0"",
- ""@Text"": ""Author"",
- ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
- ""@Grid.Row"": ""4"",
- ""@xmlns"": """"
- },
- {
- ""@Grid.Column"": ""0"",
- ""@Text"": ""Container"",
- ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
- ""@Grid.Row"": ""5"",
- ""@xmlns"": """"
- },
- {
- ""@Grid.Column"": ""0"",
- ""@Text"": ""Enclosed?"",
- ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
- ""@Grid.Row"": ""6"",
- ""@xmlns"": """"
- },
- {
- ""@Grid.Column"": ""0"",
- ""@Text"": ""Assignee"",
- ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
- ""@Grid.Row"": ""7"",
- ""@xmlns"": """"
- }
- ]
- }
-}";
-
- Assert.AreEqual(expectedJson, json);
-
- XmlNode node = JsonConvert.DeserializeXmlNode(json);
-
- StringWriter sw = new StringWriter();
- XmlWriter writer = XmlWriter.Create(sw, new XmlWriterSettings
- {
- Indent = true,
- OmitXmlDeclaration = true
- });
- node.WriteTo(writer);
- writer.Flush();
-
- string xaml2 = sw.ToString();
-
- string expectedXaml = @"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-";
-
- Assert.AreEqual(expectedXaml, xaml2);
- }
- }
-}
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#if !SILVERLIGHT && !NETFX_CORE
+using System;
+using System.Collections.Generic;
+using Newtonsoft.Json.Tests.Serialization;
+using Newtonsoft.Json.Tests.TestObjects;
+#if !NETFX_CORE
+using NUnit.Framework;
+#else
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using TestFixture = Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute;
+using Test = Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute;
+#endif
+using Newtonsoft.Json;
+using System.IO;
+using System.Xml;
+using Newtonsoft.Json.Converters;
+using Newtonsoft.Json.Utilities;
+using Newtonsoft.Json.Linq;
+#if !NET20
+using System.Xml.Linq;
+#endif
+
+namespace Newtonsoft.Json.Tests.Converters
+{
+ [TestFixture]
+ public class XmlNodeConverterTest : TestFixtureBase
+ {
+ private string SerializeXmlNode(XmlNode node)
+ {
+ string json = JsonConvert.SerializeXmlNode(node, Formatting.Indented);
+ XmlNodeReader reader = new XmlNodeReader(node);
+
+#if !NET20
+ XObject xNode;
+ if (node is XmlDocument)
+ {
+ xNode = XDocument.Load(reader);
+ }
+ else if (node is XmlAttribute)
+ {
+ XmlAttribute attribute = (XmlAttribute) node;
+ xNode = new XAttribute(XName.Get(attribute.LocalName, attribute.NamespaceURI), attribute.Value);
+ }
+ else
+ {
+ reader.MoveToContent();
+ xNode = XNode.ReadFrom(reader);
+ }
+
+ string linqJson = JsonConvert.SerializeXNode(xNode, Formatting.Indented);
+
+ Assert.AreEqual(json, linqJson);
+#endif
+
+ return json;
+ }
+
+ private XmlNode DeserializeXmlNode(string json)
+ {
+ return DeserializeXmlNode(json, null);
+ }
+
+ private XmlNode DeserializeXmlNode(string json, string deserializeRootElementName)
+ {
+ JsonTextReader reader;
+
+ reader = new JsonTextReader(new StringReader(json));
+ reader.Read();
+ XmlNodeConverter converter = new XmlNodeConverter();
+ if (deserializeRootElementName != null)
+ converter.DeserializeRootElementName = deserializeRootElementName;
+
+ XmlNode node = (XmlNode)converter.ReadJson(reader, typeof (XmlDocument), null, new JsonSerializer());
+
+#if !NET20
+ string xmlText = node.OuterXml;
+
+ reader = new JsonTextReader(new StringReader(json));
+ reader.Read();
+ XDocument d = (XDocument) converter.ReadJson(reader, typeof (XDocument), null, new JsonSerializer());
+
+ string linqXmlText = d.ToString(SaveOptions.DisableFormatting);
+ if (d.Declaration != null)
+ linqXmlText = d.Declaration + linqXmlText;
+
+ Assert.AreEqual(xmlText, linqXmlText);
+#endif
+
+ return node;
+ }
+
+ [Test]
+ public void DocumentSerializeIndented()
+ {
+ string xml = @"
+
+
+
+ Web 2.0 Conference
+ October 5
+ 7
+ Argent Hotel, San Francisco, CA
+
+";
+ XmlDocument doc = new XmlDocument();
+ doc.LoadXml(xml);
+
+ string jsonText = SerializeXmlNode(doc);
+ string expected = @"{
+ ""?xml"": {
+ ""@version"": ""1.0"",
+ ""@standalone"": ""no""
+ },
+ ""?xml-stylesheet"": ""href=\""classic.xsl\"" type=\""text/xml\"""",
+ ""span"": {
+ ""@class"": ""vevent"",
+ ""a"": {
+ ""@class"": ""url"",
+ ""@href"": ""http://www.web2con.com/"",
+ ""span"": [
+ {
+ ""@class"": ""summary"",
+ ""#text"": ""Web 2.0 Conference"",
+ ""#cdata-section"": ""my escaped text""
+ },
+ {
+ ""@class"": ""location"",
+ ""#text"": ""Argent Hotel, San Francisco, CA""
+ }
+ ],
+ ""abbr"": [
+ {
+ ""@class"": ""dtstart"",
+ ""@title"": ""2005-10-05"",
+ ""#text"": ""October 5""
+ },
+ {
+ ""@class"": ""dtend"",
+ ""@title"": ""2005-10-08"",
+ ""#text"": ""7""
+ }
+ ]
+ }
+ }
+}";
+
+ Assert.AreEqual(expected, jsonText);
+
+ Console.WriteLine("DocumentSerializeIndented");
+ Console.WriteLine(jsonText);
+ Console.WriteLine();
+ }
+
+ [Test]
+ public void SerializeNodeTypes()
+ {
+ XmlDocument doc = new XmlDocument();
+ string jsonText;
+
+ Console.WriteLine("SerializeNodeTypes");
+
+ string xml = @"
+
+
+
+";
+
+ XmlDocument document = new XmlDocument();
+ document.LoadXml(xml);
+
+ // XmlAttribute
+ XmlAttribute attribute = document.DocumentElement.ChildNodes[0].Attributes["IsDataSet", "urn:schemas-microsoft-com:xml-msdata"];
+ attribute.Value = "true";
+
+ jsonText = JsonConvert.SerializeXmlNode(attribute);
+
+ Console.WriteLine(jsonText);
+ Assert.AreEqual(@"{""@msdata:IsDataSet"":""true""}", jsonText);
+
+#if !NET20
+ XDocument d = XDocument.Parse(xml);
+ XAttribute a = d.Root.Element("{http://www.w3.org/2001/XMLSchema}element").Attribute("{urn:schemas-microsoft-com:xml-msdata}IsDataSet");
+
+ jsonText = JsonConvert.SerializeXNode(a);
+
+ Assert.AreEqual(@"{""@msdata:IsDataSet"":""true""}", jsonText);
+#endif
+
+ // XmlProcessingInstruction
+ XmlProcessingInstruction instruction = doc.CreateProcessingInstruction("xml-stylesheet", @"href=""classic.xsl"" type=""text/xml""");
+
+ jsonText = JsonConvert.SerializeXmlNode(instruction);
+
+ Console.WriteLine(jsonText);
+ Assert.AreEqual(@"{""?xml-stylesheet"":""href=\""classic.xsl\"" type=\""text/xml\""""}", jsonText);
+
+
+ // XmlProcessingInstruction
+ XmlCDataSection cDataSection = doc.CreateCDataSection("true");
+
+ jsonText = JsonConvert.SerializeXmlNode(cDataSection);
+
+ Console.WriteLine(jsonText);
+ Assert.AreEqual(@"{""#cdata-section"":""true""}", jsonText);
+
+
+ // XmlElement
+ XmlElement element = doc.CreateElement("xs", "Choice", "http://www.w3.org/2001/XMLSchema");
+ element.SetAttributeNode(doc.CreateAttribute("msdata", "IsDataSet", "urn:schemas-microsoft-com:xml-msdata"));
+
+ XmlAttribute aa = doc.CreateAttribute(@"xmlns", "xs", "http://www.w3.org/2000/xmlns/");
+ aa.Value = "http://www.w3.org/2001/XMLSchema";
+ element.SetAttributeNode(aa);
+
+ aa = doc.CreateAttribute(@"xmlns", "msdata", "http://www.w3.org/2000/xmlns/");
+ aa.Value = "urn:schemas-microsoft-com:xml-msdata";
+ element.SetAttributeNode(aa);
+
+ element.AppendChild(instruction);
+ element.AppendChild(cDataSection);
+
+ doc.AppendChild(element);
+
+ jsonText = JsonConvert.SerializeXmlNode(element, Formatting.Indented);
+
+ Assert.AreEqual(@"{
+ ""xs:Choice"": {
+ ""@msdata:IsDataSet"": """",
+ ""@xmlns:xs"": ""http://www.w3.org/2001/XMLSchema"",
+ ""@xmlns:msdata"": ""urn:schemas-microsoft-com:xml-msdata"",
+ ""?xml-stylesheet"": ""href=\""classic.xsl\"" type=\""text/xml\"""",
+ ""#cdata-section"": ""true""
+ }
+}", jsonText);
+ }
+
+ [Test]
+ public void DocumentFragmentSerialize()
+ {
+ XmlDocument doc = new XmlDocument();
+
+ XmlDocumentFragment fragement = doc.CreateDocumentFragment();
+
+ fragement.InnerXml = "- widget
- widget
";
+
+ string jsonText = JsonConvert.SerializeXmlNode(fragement);
+
+ string expected = @"{""Item"":[""widget"",""widget""]}";
+
+ Assert.AreEqual(expected, jsonText);
+
+ Console.WriteLine("DocumentFragmentSerialize");
+ Console.WriteLine(jsonText);
+ Console.WriteLine();
+ }
+
+ [Test]
+ public void NamespaceSerializeDeserialize()
+ {
+ string xml = @"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+";
+
+ XmlDocument doc = new XmlDocument();
+ doc.LoadXml(xml);
+
+ string jsonText = SerializeXmlNode(doc);
+
+ string expected = @"{
+ ""?xml"": {
+ ""@version"": ""1.0"",
+ ""@encoding"": ""utf-8""
+ },
+ ""xs:schema"": {
+ ""@xs:id"": ""SomeID"",
+ ""@xmlns"": """",
+ ""@xmlns:xs"": ""http://www.w3.org/2001/XMLSchema"",
+ ""@xmlns:msdata"": ""urn:schemas-microsoft-com:xml-msdata"",
+ ""xs:element"": {
+ ""@name"": ""MyDataSet"",
+ ""@msdata:IsDataSet"": ""true"",
+ ""xs:complexType"": {
+ ""xs:choice"": {
+ ""@maxOccurs"": ""unbounded"",
+ ""xs:element"": {
+ ""@name"": ""customers"",
+ ""xs:complexType"": {
+ ""xs:sequence"": {
+ ""xs:element"": [
+ {
+ ""@name"": ""CustomerID"",
+ ""@type"": ""xs:integer"",
+ ""@minOccurs"": ""0""
+ },
+ {
+ ""@name"": ""CompanyName"",
+ ""@type"": ""xs:string"",
+ ""@minOccurs"": ""0""
+ },
+ {
+ ""@name"": ""Phone"",
+ ""@type"": ""xs:string""
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}";
+
+ Assert.AreEqual(expected, jsonText);
+
+ XmlDocument deserializedDoc = (XmlDocument)DeserializeXmlNode(jsonText);
+
+ Assert.AreEqual(doc.InnerXml, deserializedDoc.InnerXml);
+
+ Console.WriteLine("NamespaceSerializeDeserialize");
+ Console.WriteLine(jsonText);
+ Console.WriteLine(deserializedDoc.InnerXml);
+ Console.WriteLine();
+ }
+
+ [Test]
+ public void DocumentDeserialize()
+ {
+ string jsonText = @"{
+ ""?xml"": {
+ ""@version"": ""1.0"",
+ ""@standalone"": ""no""
+ },
+ ""span"": {
+ ""@class"": ""vevent"",
+ ""a"": {
+ ""@class"": ""url"",
+ ""span"": {
+ ""@class"": ""summary"",
+ ""#text"": ""Web 2.0 Conference"",
+ ""#cdata-section"": ""my escaped text""
+ },
+ ""@href"": ""http://www.web2con.com/""
+ }
+ }
+}";
+
+ XmlDocument doc = (XmlDocument)DeserializeXmlNode(jsonText);
+
+ string expected = @"
+
+
+ Web 2.0 Conference
+
+";
+
+ string formattedXml = GetIndentedInnerXml(doc);
+
+ Console.WriteLine("DocumentDeserialize");
+ Console.WriteLine(formattedXml);
+ Console.WriteLine();
+
+ Assert.AreEqual(expected, formattedXml);
+ }
+
+ private string GetIndentedInnerXml(XmlNode node)
+ {
+ XmlWriterSettings settings = new XmlWriterSettings();
+ settings.Indent = true;
+
+ StringWriter sw = new StringWriter();
+
+ using (XmlWriter writer = XmlWriter.Create(sw, settings))
+ {
+ node.WriteTo(writer);
+ }
+
+ return sw.ToString();
+ }
+
+ [Test]
+ public void SingleTextNode()
+ {
+ string xml = @"
+
+
+ Alan
+ http://www.google.com
+
+
+ Louis
+ http://www.yahoo.com
+
+ ";
+
+ XmlDocument doc = new XmlDocument();
+ doc.LoadXml(xml);
+
+ string jsonText = SerializeXmlNode(doc);
+
+ XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
+
+ Assert.AreEqual(doc.InnerXml, newDoc.InnerXml);
+ }
+
+ [Test]
+ public void EmptyNode()
+ {
+ string xml = @"
+
+
+ Alan
+
+
+
+ Louis
+ http://www.yahoo.com
+
+ ";
+
+ XmlDocument doc = new XmlDocument();
+ doc.LoadXml(xml);
+
+ string jsonText = SerializeXmlNode(doc);
+
+ Console.WriteLine(jsonText);
+
+ XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
+
+ Assert.AreEqual(doc.InnerXml, newDoc.InnerXml);
+ }
+
+ [Test]
+ public void OtherElementDataTypes()
+ {
+ string jsonText = @"{""?xml"":{""@version"":""1.0"",""@standalone"":""no""},""root"":{""person"":[{""@id"":""1"",""Float"":2.5,""Integer"":99},{""Boolean"":true,""@id"":""2"",""date"":""\/Date(954374400000)\/""}]}}";
+
+ XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
+
+ string expected = @"2.599true2000-03-30T00:00:00Z";
+
+ Assert.AreEqual(expected, newDoc.InnerXml);
+ }
+
+ [Test]
+ [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "XmlNodeConverter can only convert JSON that begins with an object.")]
+ public void NoRootObject()
+ {
+ XmlDocument newDoc = (XmlDocument)JsonConvert.DeserializeXmlNode(@"[1]");
+ }
+
+ [Test]
+ [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifing a DeserializeRootElementName.")]
+ public void RootObjectMultipleProperties()
+ {
+ XmlDocument newDoc = (XmlDocument)JsonConvert.DeserializeXmlNode(@"{Prop1:1,Prop2:2}");
+ }
+
+ [Test]
+ public void JavaScriptConstructor()
+ {
+ string jsonText = @"{root:{r:new Date(34343, 55)}}";
+
+ XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
+
+ string expected = @"3434355";
+
+ Assert.AreEqual(expected, newDoc.InnerXml);
+
+ string json = SerializeXmlNode(newDoc);
+ expected = @"{
+ ""root"": {
+ ""r"": {
+ ""Date"": [
+ ""34343"",
+ ""55""
+ ]
+ }
+ }
+}";
+
+ Assert.AreEqual(expected, json);
+ }
+
+ [Test]
+ public void ForceJsonArray()
+ {
+ string arrayXml = @"
+
+ Alan
+ http://www.google.com
+ Admin
+
+ ";
+
+ XmlDocument arrayDoc = new XmlDocument();
+ arrayDoc.LoadXml(arrayXml);
+
+ string arrayJsonText = SerializeXmlNode(arrayDoc);
+ string expected = @"{
+ ""root"": {
+ ""person"": {
+ ""@id"": ""1"",
+ ""name"": ""Alan"",
+ ""url"": ""http://www.google.com"",
+ ""role"": [
+ ""Admin""
+ ]
+ }
+ }
+}";
+ Assert.AreEqual(expected, arrayJsonText);
+
+ arrayXml = @"
+
+ Alan
+ http://www.google.com
+ Admin1
+ Admin2
+
+ ";
+
+ arrayDoc = new XmlDocument();
+ arrayDoc.LoadXml(arrayXml);
+
+ arrayJsonText = SerializeXmlNode(arrayDoc);
+ expected = @"{
+ ""root"": {
+ ""person"": {
+ ""@id"": ""1"",
+ ""name"": ""Alan"",
+ ""url"": ""http://www.google.com"",
+ ""role"": [
+ ""Admin1"",
+ ""Admin2""
+ ]
+ }
+ }
+}";
+ Assert.AreEqual(expected, arrayJsonText);
+
+ arrayXml = @"
+
+ Alan
+ http://www.google.com
+ Admin1
+
+ ";
+
+ arrayDoc = new XmlDocument();
+ arrayDoc.LoadXml(arrayXml);
+
+ arrayJsonText = SerializeXmlNode(arrayDoc);
+ expected = @"{
+ ""root"": {
+ ""person"": {
+ ""@id"": ""1"",
+ ""name"": ""Alan"",
+ ""url"": ""http://www.google.com"",
+ ""role"": ""Admin1""
+ }
+ }
+}";
+ Assert.AreEqual(expected, arrayJsonText);
+ }
+
+ [Test]
+ [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifing a DeserializeRootElementName.")]
+ public void MultipleRootPropertiesXmlDocument()
+ {
+ string json = @"{""count"": 773840,""photos"": null}";
+
+ JsonConvert.DeserializeXmlNode(json);
+ }
+
+#if !NET20
+ [Test]
+ [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifing a DeserializeRootElementName.")]
+ public void MultipleRootPropertiesXDocument()
+ {
+ string json = @"{""count"": 773840,""photos"": null}";
+
+ JsonConvert.DeserializeXNode(json);
+ }
+#endif
+
+ [Test]
+ public void MultipleRootPropertiesAddRootElement()
+ {
+ string json = @"{""count"": 773840,""photos"": 773840}";
+
+ XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot");
+
+ Assert.AreEqual(@"773840773840", newDoc.InnerXml);
+
+#if !NET20
+ XDocument newXDoc = JsonConvert.DeserializeXNode(json, "myRoot");
+
+ Assert.AreEqual(@"773840773840", newXDoc.ToString(SaveOptions.DisableFormatting));
+#endif
+ }
+
+ [Test]
+ public void NestedArrays()
+ {
+ string json = @"{
+ ""available_sizes"": [
+ [
+ ""assets/images/resized/0001/1070/11070v1-max-150x150.jpg"",
+ ""assets/images/resized/0001/1070/11070v1-max-150x150.jpg""
+ ],
+ [
+ ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg"",
+ ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
+ ],
+ [
+ ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
+ ]
+ ]
+}";
+
+ XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot");
+
+ string xml = IndentXml(newDoc.InnerXml);
+
+ Assert.AreEqual(@"
+
+ assets/images/resized/0001/1070/11070v1-max-150x150.jpg
+ assets/images/resized/0001/1070/11070v1-max-150x150.jpg
+
+
+ assets/images/resized/0001/1070/11070v1-max-250x250.jpg
+ assets/images/resized/0001/1070/11070v1-max-250x250.jpg
+
+
+ assets/images/resized/0001/1070/11070v1-max-250x250.jpg
+
+", IndentXml(newDoc.InnerXml));
+
+#if !NET20
+ XDocument newXDoc = JsonConvert.DeserializeXNode(json, "myRoot");
+
+ Assert.AreEqual(@"
+
+ assets/images/resized/0001/1070/11070v1-max-150x150.jpg
+ assets/images/resized/0001/1070/11070v1-max-150x150.jpg
+
+
+ assets/images/resized/0001/1070/11070v1-max-250x250.jpg
+ assets/images/resized/0001/1070/11070v1-max-250x250.jpg
+
+
+ assets/images/resized/0001/1070/11070v1-max-250x250.jpg
+
+", IndentXml(newXDoc.ToString(SaveOptions.DisableFormatting)));
+#endif
+
+ string newJson = JsonConvert.SerializeXmlNode(newDoc, Formatting.Indented);
+ Console.WriteLine(newJson);
+ }
+
+ [Test]
+ public void RoundTripNestedArrays()
+ {
+ string json = @"{
+ ""available_sizes"": [
+ [
+ ""assets/images/resized/0001/1070/11070v1-max-150x150.jpg"",
+ ""assets/images/resized/0001/1070/11070v1-max-150x150.jpg""
+ ],
+ [
+ ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg"",
+ ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
+ ],
+ [
+ ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
+ ]
+ ]
+}";
+
+ XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot", true);
+
+ Assert.AreEqual(@"
+
+ assets/images/resized/0001/1070/11070v1-max-150x150.jpg
+ assets/images/resized/0001/1070/11070v1-max-150x150.jpg
+
+
+ assets/images/resized/0001/1070/11070v1-max-250x250.jpg
+ assets/images/resized/0001/1070/11070v1-max-250x250.jpg
+
+
+ assets/images/resized/0001/1070/11070v1-max-250x250.jpg
+
+", IndentXml(newDoc.InnerXml));
+
+#if !NET20
+ XDocument newXDoc = JsonConvert.DeserializeXNode(json, "myRoot", true);
+
+ Console.WriteLine(IndentXml(newXDoc.ToString(SaveOptions.DisableFormatting)));
+
+ Assert.AreEqual(@"
+
+ assets/images/resized/0001/1070/11070v1-max-150x150.jpg
+ assets/images/resized/0001/1070/11070v1-max-150x150.jpg
+
+
+ assets/images/resized/0001/1070/11070v1-max-250x250.jpg
+ assets/images/resized/0001/1070/11070v1-max-250x250.jpg
+
+
+ assets/images/resized/0001/1070/11070v1-max-250x250.jpg
+
+", IndentXml(newXDoc.ToString(SaveOptions.DisableFormatting)));
+#endif
+
+ string newJson = JsonConvert.SerializeXmlNode(newDoc, Formatting.Indented, true);
+ Assert.AreEqual(json, newJson);
+ }
+
+ [Test]
+ public void MultipleNestedArraysToXml()
+ {
+ string json = @"{
+ ""available_sizes"": [
+ [
+ [113, 150],
+ ""assets/images/resized/0001/1070/11070v1-max-150x150.jpg""
+ ],
+ [
+ [189, 250],
+ ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
+ ],
+ [
+ [341, 450],
+ ""assets/images/resized/0001/1070/11070v1-max-450x450.jpg""
+ ]
+ ]
+}";
+
+ XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot");
+
+ Assert.AreEqual(@"113150assets/images/resized/0001/1070/11070v1-max-150x150.jpg189250assets/images/resized/0001/1070/11070v1-max-250x250.jpg341450assets/images/resized/0001/1070/11070v1-max-450x450.jpg", newDoc.InnerXml);
+
+#if !NET20
+ XDocument newXDoc = JsonConvert.DeserializeXNode(json, "myRoot");
+
+ Assert.AreEqual(@"113150assets/images/resized/0001/1070/11070v1-max-150x150.jpg189250assets/images/resized/0001/1070/11070v1-max-250x250.jpg341450assets/images/resized/0001/1070/11070v1-max-450x450.jpg", newXDoc.ToString(SaveOptions.DisableFormatting));
+#endif
+ }
+
+ [Test]
+ public void Encoding()
+ {
+ XmlDocument doc = new XmlDocument();
+
+ doc.LoadXml(@"O""Connor"); // i use "" so it will be easier to see the problem
+
+ string json = SerializeXmlNode(doc);
+ Assert.AreEqual(@"{
+ ""name"": ""O\""Connor""
+}", json);
+ }
+
+ [Test]
+ public void SerializeComment()
+ {
+ string xml = @"
+ Text
+";
+ XmlDocument doc = new XmlDocument();
+ doc.LoadXml(xml);
+
+ string jsonText = SerializeXmlNode(doc);
+
+ string expected = @"{
+ ""span"": {
+ ""@class"": ""vevent"",
+ ""a"": {
+ ""@class"": ""url"",
+ ""@href"": ""http://www.web2con.com/"",
+ ""#text"": ""Text""
+ }/* Hi! */
+ }
+}";
+
+ Assert.AreEqual(expected, jsonText);
+
+ XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
+ Assert.AreEqual(@"Text", newDoc.InnerXml);
+ }
+
+ [Test]
+ public void SerializeExample()
+ {
+ string xml = @"
+
+
+ Alan
+ http://www.google.com
+
+
+ Louis
+ http://www.yahoo.com
+
+ ";
+
+ XmlDocument doc = new XmlDocument();
+ doc.LoadXml(xml);
+
+ string jsonText = SerializeXmlNode(doc);
+ // {
+ // "?xml": {
+ // "@version": "1.0",
+ // "@standalone": "no"
+ // },
+ // "root": {
+ // "person": [
+ // {
+ // "@id": "1",
+ // "name": "Alan",
+ // "url": "http://www.google.com"
+ // },
+ // {
+ // "@id": "2",
+ // "name": "Louis",
+ // "url": "http://www.yahoo.com"
+ // }
+ // ]
+ // }
+ // }
+
+ // format
+ jsonText = JObject.Parse(jsonText).ToString();
+
+ Assert.AreEqual(@"{
+ ""?xml"": {
+ ""@version"": ""1.0"",
+ ""@standalone"": ""no""
+ },
+ ""root"": {
+ ""person"": [
+ {
+ ""@id"": ""1"",
+ ""name"": ""Alan"",
+ ""url"": ""http://www.google.com""
+ },
+ {
+ ""@id"": ""2"",
+ ""name"": ""Louis"",
+ ""url"": ""http://www.yahoo.com""
+ }
+ ]
+ }
+}", jsonText);
+
+ XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
+
+ Assert.AreEqual(doc.InnerXml, newDoc.InnerXml);
+ }
+
+ [Test]
+ public void DeserializeExample()
+ {
+ string json = @"{
+ ""?xml"": {
+ ""@version"": ""1.0"",
+ ""@standalone"": ""no""
+ },
+ ""root"": {
+ ""person"": [
+ {
+ ""@id"": ""1"",
+ ""name"": ""Alan"",
+ ""url"": ""http://www.google.com""
+ },
+ {
+ ""@id"": ""2"",
+ ""name"": ""Louis"",
+ ""url"": ""http://www.yahoo.com""
+ }
+ ]
+ }
+ }";
+
+ XmlDocument doc = (XmlDocument)DeserializeXmlNode(json);
+ //
+ //
+ //
+ // Alan
+ // http://www.google.com
+ //
+ //
+ // Louis
+ // http://www.yahoo.com
+ //
+ //
+
+ Assert.AreEqual(@"
+
+
+Alan
+http://www.google.com
+
+
+Louis
+http://www.yahoo.com
+
+".Replace(Environment.NewLine, string.Empty), doc.InnerXml);
+ }
+
+ [Test]
+ public void SerializeDeserializeSpecialProperties()
+ {
+ PreserveReferencesHandlingTests.CircularDictionary circularDictionary = new PreserveReferencesHandlingTests.CircularDictionary();
+ circularDictionary.Add("other", new PreserveReferencesHandlingTests.CircularDictionary { { "blah", null } });
+ circularDictionary.Add("self", circularDictionary);
+
+ string json = JsonConvert.SerializeObject(circularDictionary, Formatting.Indented,
+ new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
+
+ Assert.AreEqual(@"{
+ ""$id"": ""1"",
+ ""other"": {
+ ""$id"": ""2"",
+ ""blah"": null
+ },
+ ""self"": {
+ ""$ref"": ""1""
+ }
+}", json);
+
+ XmlNode node = DeserializeXmlNode(json, "root");
+ string xml = GetIndentedInnerXml(node);
+ string expected = @"
+
+
+
+
+
+";
+
+ Assert.AreEqual(expected, xml);
+
+ string xmlJson = SerializeXmlNode(node);
+ string expectedXmlJson = @"{
+ ""root"": {
+ ""$id"": ""1"",
+ ""other"": {
+ ""$id"": ""2"",
+ ""blah"": null
+ },
+ ""self"": {
+ ""$ref"": ""1""
+ }
+ }
+}";
+
+ Assert.AreEqual(expectedXmlJson, xmlJson);
+ }
+
+ [Test]
+ [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "XmlNodeConverter cannot convert JSON with an empty property name to XML.")]
+ public void EmptyPropertyName()
+ {
+ string json = @"{
+ ""8452309520V2"": {
+ """": {
+ ""CLIENT"": {
+ ""ID_EXPIRATION_1"": {
+ ""VALUE"": ""12/12/2000"",
+ ""DATATYPE"": ""D"",
+ ""MSG"": ""Missing Identification Exp. Date 1""
+ },
+ ""ID_ISSUEDATE_1"": {
+ ""VALUE"": """",
+ ""DATATYPE"": ""D"",
+ ""MSG"": ""Missing Identification Issue Date 1""
+ }
+ }
+ },
+ ""457463534534"": {
+ ""ACCOUNT"": {
+ ""FUNDING_SOURCE"": {
+ ""VALUE"": ""FS0"",
+ ""DATATYPE"": ""L"",
+ ""MSG"": ""Missing Source of Funds""
+ }
+ }
+ }
+ }
+}{
+ ""34534634535345"": {
+ """": {
+ ""CLIENT"": {
+ ""ID_NUMBER_1"": {
+ ""VALUE"": """",
+ ""DATATYPE"": ""S"",
+ ""MSG"": ""Missing Picture ID""
+ },
+ ""ID_EXPIRATION_1"": {
+ ""VALUE"": ""12/12/2000"",
+ ""DATATYPE"": ""D"",
+ ""MSG"": ""Missing Picture ID""
+ },
+ ""WALK_IN"": {
+ ""VALUE"": """",
+ ""DATATYPE"": ""L"",
+ ""MSG"": ""Missing Walk in""
+ },
+ ""PERSONAL_MEETING"": {
+ ""VALUE"": ""PM1"",
+ ""DATATYPE"": ""L"",
+ ""MSG"": ""Missing Met Client in Person""
+ },
+ ""ID_ISSUEDATE_1"": {
+ ""VALUE"": """",
+ ""DATATYPE"": ""D"",
+ ""MSG"": ""Missing Picture ID""
+ },
+ ""PHOTO_ID"": {
+ ""VALUE"": """",
+ ""DATATYPE"": ""L"",
+ ""MSG"": ""Missing Picture ID""
+ },
+ ""ID_TYPE_1"": {
+ ""VALUE"": """",
+ ""DATATYPE"": ""L"",
+ ""MSG"": ""Missing Picture ID""
+ }
+ }
+ },
+ ""45635624523"": {
+ ""ACCOUNT"": {
+ ""FUNDING_SOURCE"": {
+ ""VALUE"": ""FS1"",
+ ""DATATYPE"": ""L"",
+ ""MSG"": ""Missing Source of Funds""
+ }
+ }
+ }
+ }
+}";
+
+ DeserializeXmlNode(json);
+ }
+
+ [Test]
+ public void SingleItemArrayPropertySerialization()
+ {
+ Product product = new Product();
+
+ product.Name = "Apple";
+ product.ExpiryDate = new DateTime(2008, 12, 28, 0, 0, 0, DateTimeKind.Utc);
+ product.Price = 3.99M;
+ product.Sizes = new string[] { "Small" };
+
+ string output = JsonConvert.SerializeObject(product, new IsoDateTimeConverter());
+
+ XmlDocument xmlProduct = JsonConvert.DeserializeXmlNode(output, "product", true);
+
+ Assert.AreEqual(@"
+ Apple
+ 2008-12-28T00:00:00Z
+ 3.99
+ Small
+", IndentXml(xmlProduct.InnerXml));
+
+ string output2 = JsonConvert.SerializeXmlNode(xmlProduct.DocumentElement, Formatting.Indented);
+
+ Assert.AreEqual(@"{
+ ""product"": {
+ ""Name"": ""Apple"",
+ ""ExpiryDate"": ""2008-12-28T00:00:00Z"",
+ ""Price"": ""3.99"",
+ ""Sizes"": [
+ ""Small""
+ ]
+ }
+}", output2);
+ }
+
+ public class TestComplexArrayClass
+ {
+ public string Name { get; set; }
+ public IList Products { get; set; }
+ }
+
+ [Test]
+ public void ComplexSingleItemArrayPropertySerialization()
+ {
+ TestComplexArrayClass o = new TestComplexArrayClass
+ {
+ Name = "Hi",
+ Products = new List
+ {
+ new Product { Name = "First" }
+ }
+ };
+
+ string output = JsonConvert.SerializeObject(o, new IsoDateTimeConverter());
+
+ XmlDocument xmlProduct = JsonConvert.DeserializeXmlNode(output, "test", true);
+
+ Assert.AreEqual(@"
+ Hi
+
+ First
+ 2000-01-01T00:00:00Z
+ 0
+
+
+", IndentXml(xmlProduct.InnerXml));
+
+ string output2 = JsonConvert.SerializeXmlNode(xmlProduct.DocumentElement, Formatting.Indented, true);
+
+ Assert.AreEqual(@"{
+ ""Name"": ""Hi"",
+ ""Products"": [
+ {
+ ""Name"": ""First"",
+ ""ExpiryDate"": ""2000-01-01T00:00:00Z"",
+ ""Price"": ""0"",
+ ""Sizes"": null
+ }
+ ]
+}", output2);
+ }
+
+ private string IndentXml(string xml)
+ {
+ XmlReader reader = XmlReader.Create(new StringReader(xml));
+
+ StringWriter sw = new StringWriter();
+ XmlWriter writer = XmlWriter.Create(sw, new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true });
+
+ while (reader.Read())
+ {
+ writer.WriteNode(reader, false);
+ }
+
+ writer.Flush();
+
+ return sw.ToString();
+ }
+
+ [Test]
+ public void OmitRootObject()
+ {
+ string xml = @"
+ Hi
+ Hi
+
+ First
+ 2000-01-01T00:00:00Z
+ 0
+
+
+";
+
+ XmlDocument d = new XmlDocument();
+ d.LoadXml(xml);
+
+ string output = JsonConvert.SerializeXmlNode(d, Formatting.Indented, true);
+
+ Assert.AreEqual(@"{
+ ""Name"": [
+ ""Hi"",
+ ""Hi""
+ ],
+ ""Products"": [
+ {
+ ""Name"": ""First"",
+ ""ExpiryDate"": ""2000-01-01T00:00:00Z"",
+ ""Price"": ""0"",
+ ""Sizes"": null
+ }
+ ]
+}", output);
+ }
+
+ [Test]
+ public void EmtpyElementWithArrayAttributeShouldWriteAttributes()
+ {
+ string xml = @"
+
+
+
+
+
+
+";
+
+ XmlDocument d = new XmlDocument();
+ d.LoadXml(xml);
+
+ string json = JsonConvert.SerializeXmlNode(d, Formatting.Indented);
+
+ Assert.AreEqual(@"{
+ ""?xml"": {
+ ""@version"": ""1.0"",
+ ""@encoding"": ""utf-8""
+ },
+ ""root"": {
+ ""A"": {
+ ""B"": [
+ {
+ ""@name"": ""sample""
+ }
+ ],
+ ""C"": [
+ null,
+ null
+ ]
+ }
+ }
+}", json);
+ }
+
+ [Test]
+ public void DeserializeNonInt64IntegerValues()
+ {
+ var dict = new Dictionary { { "Int16", (short)1 }, { "Float", 2f }, { "Int32", 3 } };
+ var obj = JObject.FromObject(dict);
+ var serializer = JsonSerializer.Create(new JsonSerializerSettings { Converters = { new XmlNodeConverter() { DeserializeRootElementName = "root" } } });
+ using (var reader = obj.CreateReader())
+ {
+ var value = (XmlDocument)serializer.Deserialize(reader, typeof(XmlDocument));
+
+ Assert.AreEqual(@"123", value.InnerXml);
+ }
+ }
+
+ [Test]
+ public void DeserializingBooleanValues()
+ {
+ MemoryStream ms = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(@"{root:{""@booleanType"":true}}"));
+ MemoryStream xml = new MemoryStream();
+
+ JsonBodyToSoapXml(ms, xml);
+
+ string xmlString = System.Text.Encoding.UTF8.GetString(xml.ToArray());
+
+ Assert.AreEqual(@"", xmlString);
+ }
+
+ private static void JsonBodyToSoapXml(Stream json, Stream xml)
+ {
+ Newtonsoft.Json.JsonSerializerSettings settings = new Newtonsoft.Json.JsonSerializerSettings();
+ settings.Converters.Add(new Newtonsoft.Json.Converters.XmlNodeConverter());
+ Newtonsoft.Json.JsonSerializer serializer = Newtonsoft.Json.JsonSerializer.Create(settings);
+ using (Newtonsoft.Json.JsonTextReader reader = new Newtonsoft.Json.JsonTextReader(new System.IO.StreamReader(json)))
+ {
+ XmlDocument doc = (XmlDocument)serializer.Deserialize(reader, typeof(XmlDocument));
+ if (reader.Read() && reader.TokenType != JsonToken.Comment)
+ throw new JsonSerializationException("Additional text found in JSON string after finishing deserializing object.");
+ using (XmlWriter writer = XmlWriter.Create(xml))
+ {
+ doc.Save(writer);
+ }
+ }
+ }
+
+#if !NET20
+ [Test]
+ public void DeserializeXNodeDefaultNamespace()
+ {
+ string xaml = @"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+";
+
+ string json = JsonConvert.SerializeXNode(XDocument.Parse(xaml), Formatting.Indented);
+
+ string expectedJson = @"{
+ ""Grid"": {
+ ""@xmlns"": ""http://schemas.microsoft.com/winfx/2006/xaml/presentation"",
+ ""@xmlns:x"": ""http://schemas.microsoft.com/winfx/2006/xaml"",
+ ""@xmlns:toolkit"": ""clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"",
+ ""@Style"": ""{StaticResource trimFormGrid}"",
+ ""@x:Name"": ""TrimObjectForm"",
+ ""Grid.ColumnDefinitions"": {
+ ""ColumnDefinition"": [
+ {
+ ""@Width"": ""63*""
+ },
+ {
+ ""@Width"": ""320*""
+ }
+ ]
+ },
+ ""Grid.RowDefinitions"": {
+ ""@xmlns"": """",
+ ""RowDefinition"": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ]
+ },
+ ""TextBox"": [
+ {
+ ""@Style"": ""{StaticResource trimFormGrid_TB}"",
+ ""@Text"": ""{Binding TypedTitle, Converter={StaticResource trimPropertyConverter}}"",
+ ""@Name"": ""RecordTypedTitle"",
+ ""@Grid.Column"": ""1"",
+ ""@Grid.Row"": ""0"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Style"": ""{StaticResource trimFormGrid_TB}"",
+ ""@Text"": ""{Binding ExternalReference, Converter={StaticResource trimPropertyConverter}}"",
+ ""@Name"": ""RecordExternalReference"",
+ ""@Grid.Column"": ""1"",
+ ""@Grid.Row"": ""1"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Style"": ""{StaticResource trimFormGrid_TB}"",
+ ""@Text"": ""{Binding Author, Converter={StaticResource trimPropertyConverter}}"",
+ ""@Name"": ""RecordAuthor"",
+ ""@Grid.Column"": ""1"",
+ ""@Grid.Row"": ""4"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Style"": ""{StaticResource trimFormGrid_TB}"",
+ ""@Text"": ""{Binding Container, Converter={StaticResource trimPropertyConverter}}"",
+ ""@Name"": ""RecordContainer"",
+ ""@Grid.Column"": ""1"",
+ ""@Grid.Row"": ""5"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Style"": ""{StaticResource trimFormGrid_TB}"",
+ ""@Text"": ""{Binding IsEnclosed, Converter={StaticResource trimPropertyConverter}}"",
+ ""@Name"": ""RecordIsEnclosed"",
+ ""@Grid.Column"": ""1"",
+ ""@Grid.Row"": ""6"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Style"": ""{StaticResource trimFormGrid_TB}"",
+ ""@Text"": ""{Binding Assignee, Converter={StaticResource trimPropertyConverter}}"",
+ ""@Name"": ""RecordAssignee"",
+ ""@Grid.Column"": ""1"",
+ ""@Grid.Row"": ""7"",
+ ""@xmlns"": """"
+ }
+ ],
+ ""toolkit:DatePicker"": [
+ {
+ ""@Style"": ""{StaticResource trimFormGrid_DP}"",
+ ""@Value"": ""{Binding DateCreated, Converter={StaticResource trimPropertyConverter}}"",
+ ""@Name"": ""RecordDateCreated"",
+ ""@Grid.Column"": ""1"",
+ ""@Grid.Row"": ""2""
+ },
+ {
+ ""@Style"": ""{StaticResource trimFormGrid_DP}"",
+ ""@Value"": ""{Binding DateDue, Converter={StaticResource trimPropertyConverter}}"",
+ ""@Name"": ""RecordDateDue"",
+ ""@Grid.Column"": ""1"",
+ ""@Grid.Row"": ""3""
+ }
+ ],
+ ""TextBlock"": [
+ {
+ ""@Grid.Column"": ""0"",
+ ""@Text"": ""Title (Free Text Part)"",
+ ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
+ ""@Grid.Row"": ""0"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Grid.Column"": ""0"",
+ ""@Text"": ""External ID"",
+ ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
+ ""@Grid.Row"": ""1"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Grid.Column"": ""0"",
+ ""@Text"": ""Date Created"",
+ ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
+ ""@Grid.Row"": ""2"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Grid.Column"": ""0"",
+ ""@Text"": ""Date Due"",
+ ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
+ ""@Grid.Row"": ""3"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Grid.Column"": ""0"",
+ ""@Text"": ""Author"",
+ ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
+ ""@Grid.Row"": ""4"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Grid.Column"": ""0"",
+ ""@Text"": ""Container"",
+ ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
+ ""@Grid.Row"": ""5"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Grid.Column"": ""0"",
+ ""@Text"": ""Enclosed?"",
+ ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
+ ""@Grid.Row"": ""6"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Grid.Column"": ""0"",
+ ""@Text"": ""Assignee"",
+ ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
+ ""@Grid.Row"": ""7"",
+ ""@xmlns"": """"
+ }
+ ]
+ }
+}";
+
+ Assert.AreEqual(expectedJson, json);
+
+ XNode node = JsonConvert.DeserializeXNode(json);
+
+ string xaml2 = node.ToString();
+
+ string expectedXaml = @"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+";
+
+ Assert.AreEqual(expectedXaml, xaml2);
+ }
+#endif
+
+ [Test]
+ public void DeserializeXmlNodeDefaultNamespace()
+ {
+ string xaml = @"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+";
+
+ XmlDocument document = new XmlDocument();
+ document.LoadXml(xaml);
+
+ string json = JsonConvert.SerializeXmlNode(document, Formatting.Indented);
+
+ string expectedJson = @"{
+ ""Grid"": {
+ ""@xmlns"": ""http://schemas.microsoft.com/winfx/2006/xaml/presentation"",
+ ""@xmlns:x"": ""http://schemas.microsoft.com/winfx/2006/xaml"",
+ ""@xmlns:toolkit"": ""clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"",
+ ""@Style"": ""{StaticResource trimFormGrid}"",
+ ""@x:Name"": ""TrimObjectForm"",
+ ""Grid.ColumnDefinitions"": {
+ ""ColumnDefinition"": [
+ {
+ ""@Width"": ""63*""
+ },
+ {
+ ""@Width"": ""320*""
+ }
+ ]
+ },
+ ""Grid.RowDefinitions"": {
+ ""@xmlns"": """",
+ ""RowDefinition"": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ]
+ },
+ ""TextBox"": [
+ {
+ ""@Style"": ""{StaticResource trimFormGrid_TB}"",
+ ""@Text"": ""{Binding TypedTitle, Converter={StaticResource trimPropertyConverter}}"",
+ ""@Name"": ""RecordTypedTitle"",
+ ""@Grid.Column"": ""1"",
+ ""@Grid.Row"": ""0"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Style"": ""{StaticResource trimFormGrid_TB}"",
+ ""@Text"": ""{Binding ExternalReference, Converter={StaticResource trimPropertyConverter}}"",
+ ""@Name"": ""RecordExternalReference"",
+ ""@Grid.Column"": ""1"",
+ ""@Grid.Row"": ""1"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Style"": ""{StaticResource trimFormGrid_TB}"",
+ ""@Text"": ""{Binding Author, Converter={StaticResource trimPropertyConverter}}"",
+ ""@Name"": ""RecordAuthor"",
+ ""@Grid.Column"": ""1"",
+ ""@Grid.Row"": ""4"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Style"": ""{StaticResource trimFormGrid_TB}"",
+ ""@Text"": ""{Binding Container, Converter={StaticResource trimPropertyConverter}}"",
+ ""@Name"": ""RecordContainer"",
+ ""@Grid.Column"": ""1"",
+ ""@Grid.Row"": ""5"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Style"": ""{StaticResource trimFormGrid_TB}"",
+ ""@Text"": ""{Binding IsEnclosed, Converter={StaticResource trimPropertyConverter}}"",
+ ""@Name"": ""RecordIsEnclosed"",
+ ""@Grid.Column"": ""1"",
+ ""@Grid.Row"": ""6"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Style"": ""{StaticResource trimFormGrid_TB}"",
+ ""@Text"": ""{Binding Assignee, Converter={StaticResource trimPropertyConverter}}"",
+ ""@Name"": ""RecordAssignee"",
+ ""@Grid.Column"": ""1"",
+ ""@Grid.Row"": ""7"",
+ ""@xmlns"": """"
+ }
+ ],
+ ""toolkit:DatePicker"": [
+ {
+ ""@Style"": ""{StaticResource trimFormGrid_DP}"",
+ ""@Value"": ""{Binding DateCreated, Converter={StaticResource trimPropertyConverter}}"",
+ ""@Name"": ""RecordDateCreated"",
+ ""@Grid.Column"": ""1"",
+ ""@Grid.Row"": ""2""
+ },
+ {
+ ""@Style"": ""{StaticResource trimFormGrid_DP}"",
+ ""@Value"": ""{Binding DateDue, Converter={StaticResource trimPropertyConverter}}"",
+ ""@Name"": ""RecordDateDue"",
+ ""@Grid.Column"": ""1"",
+ ""@Grid.Row"": ""3""
+ }
+ ],
+ ""TextBlock"": [
+ {
+ ""@Grid.Column"": ""0"",
+ ""@Text"": ""Title (Free Text Part)"",
+ ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
+ ""@Grid.Row"": ""0"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Grid.Column"": ""0"",
+ ""@Text"": ""External ID"",
+ ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
+ ""@Grid.Row"": ""1"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Grid.Column"": ""0"",
+ ""@Text"": ""Date Created"",
+ ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
+ ""@Grid.Row"": ""2"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Grid.Column"": ""0"",
+ ""@Text"": ""Date Due"",
+ ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
+ ""@Grid.Row"": ""3"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Grid.Column"": ""0"",
+ ""@Text"": ""Author"",
+ ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
+ ""@Grid.Row"": ""4"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Grid.Column"": ""0"",
+ ""@Text"": ""Container"",
+ ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
+ ""@Grid.Row"": ""5"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Grid.Column"": ""0"",
+ ""@Text"": ""Enclosed?"",
+ ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
+ ""@Grid.Row"": ""6"",
+ ""@xmlns"": """"
+ },
+ {
+ ""@Grid.Column"": ""0"",
+ ""@Text"": ""Assignee"",
+ ""@Style"": ""{StaticResource trimFormGrid_LBL}"",
+ ""@Grid.Row"": ""7"",
+ ""@xmlns"": """"
+ }
+ ]
+ }
+}";
+
+ Assert.AreEqual(expectedJson, json);
+
+ XmlNode node = JsonConvert.DeserializeXmlNode(json);
+
+ StringWriter sw = new StringWriter();
+ XmlWriter writer = XmlWriter.Create(sw, new XmlWriterSettings
+ {
+ Indent = true,
+ OmitXmlDeclaration = true
+ });
+ node.WriteTo(writer);
+ writer.Flush();
+
+ string xaml2 = sw.ToString();
+
+ string expectedXaml = @"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+";
+
+ Assert.AreEqual(expectedXaml, xaml2);
+ }
+
+ [Test]
+ public void DeserializeAttributePropertyNotAtStart()
+ {
+ string json = @"{""item"": {""@action"": ""update"", ""@itemid"": ""1"", ""elements"": [{""@action"": ""none"", ""@id"": ""2""},{""@action"": ""none"", ""@id"": ""3""}],""@description"": ""temp""}}";
+
+ XmlDocument xmldoc = JsonConvert.DeserializeXmlNode(json);
+
+ Assert.AreEqual(@" ", xmldoc.InnerXml);
+ }
+ }
+}
#endif
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs
index faa3bdfc..2c4beb8d 100644
--- a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs
+++ b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs
@@ -1,1551 +1,1567 @@
-#region License
-// Copyright (c) 2007 James Newton-King
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-#endregion
-
-#if (!SILVERLIGHT || WINDOWS_PHONE)
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Xml;
-#if !NET20
-using System.Xml.Linq;
-#endif
-using Newtonsoft.Json.Utilities;
-#if NET20
-using Newtonsoft.Json.Utilities.LinqBridge;
-#else
-using System.Linq;
-#endif
-
-namespace Newtonsoft.Json.Converters
-{
- #region XmlNodeWrappers
-#if !SILVERLIGHT && !NETFX_CORE
- internal class XmlDocumentWrapper : XmlNodeWrapper, IXmlDocument
- {
- private readonly XmlDocument _document;
-
- public XmlDocumentWrapper(XmlDocument document)
- : base(document)
- {
- _document = document;
- }
-
- public IXmlNode CreateComment(string data)
- {
- return new XmlNodeWrapper(_document.CreateComment(data));
- }
-
- public IXmlNode CreateTextNode(string text)
- {
- return new XmlNodeWrapper(_document.CreateTextNode(text));
- }
-
- public IXmlNode CreateCDataSection(string data)
- {
- return new XmlNodeWrapper(_document.CreateCDataSection(data));
- }
-
- public IXmlNode CreateWhitespace(string text)
- {
- return new XmlNodeWrapper(_document.CreateWhitespace(text));
- }
-
- public IXmlNode CreateSignificantWhitespace(string text)
- {
- return new XmlNodeWrapper(_document.CreateSignificantWhitespace(text));
- }
-
- public IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone)
- {
- return new XmlNodeWrapper(_document.CreateXmlDeclaration(version, encoding, standalone));
- }
-
- public IXmlNode CreateProcessingInstruction(string target, string data)
- {
- return new XmlNodeWrapper(_document.CreateProcessingInstruction(target, data));
- }
-
- public IXmlElement CreateElement(string elementName)
- {
- return new XmlElementWrapper(_document.CreateElement(elementName));
- }
-
- public IXmlElement CreateElement(string qualifiedName, string namespaceUri)
- {
- return new XmlElementWrapper(_document.CreateElement(qualifiedName, namespaceUri));
- }
-
- public IXmlNode CreateAttribute(string name, string value)
- {
- XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(name));
- attribute.Value = value;
-
- return attribute;
- }
-
- public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value)
- {
- XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(qualifiedName, namespaceUri));
- attribute.Value = value;
-
- return attribute;
- }
-
- public IXmlElement DocumentElement
- {
- get
- {
- if (_document.DocumentElement == null)
- return null;
-
- return new XmlElementWrapper(_document.DocumentElement);
- }
- }
- }
-
- internal class XmlElementWrapper : XmlNodeWrapper, IXmlElement
- {
- private readonly XmlElement _element;
-
- public XmlElementWrapper(XmlElement element)
- : base(element)
- {
- _element = element;
- }
-
- public void SetAttributeNode(IXmlNode attribute)
- {
- XmlNodeWrapper xmlAttributeWrapper = (XmlNodeWrapper)attribute;
-
- _element.SetAttributeNode((XmlAttribute) xmlAttributeWrapper.WrappedNode);
- }
-
- public string GetPrefixOfNamespace(string namespaceUri)
- {
- return _element.GetPrefixOfNamespace(namespaceUri);
- }
- }
-
- internal class XmlDeclarationWrapper : XmlNodeWrapper, IXmlDeclaration
- {
- private readonly XmlDeclaration _declaration;
-
- public XmlDeclarationWrapper(XmlDeclaration declaration)
- : base(declaration)
- {
- _declaration = declaration;
- }
-
- public string Version
- {
- get { return _declaration.Version; }
- }
-
- public string Encoding
- {
- get { return _declaration.Encoding; }
- set { _declaration.Encoding = value; }
- }
-
- public string Standalone
- {
- get { return _declaration.Standalone; }
- set { _declaration.Standalone = value; }
- }
- }
-
- internal class XmlNodeWrapper : IXmlNode
- {
- private readonly XmlNode _node;
-
- public XmlNodeWrapper(XmlNode node)
- {
- _node = node;
- }
-
- public object WrappedNode
- {
- get { return _node; }
- }
-
- public XmlNodeType NodeType
- {
- get { return _node.NodeType; }
- }
-
- public string Name
- {
- get { return _node.Name; }
- }
-
- public string LocalName
- {
- get { return _node.LocalName; }
- }
-
- public IList ChildNodes
- {
- get { return _node.ChildNodes.Cast().Select(n => WrapNode(n)).ToList(); }
- }
-
- private IXmlNode WrapNode(XmlNode node)
- {
- switch (node.NodeType)
- {
- case XmlNodeType.Element:
- return new XmlElementWrapper((XmlElement) node);
- case XmlNodeType.XmlDeclaration:
- return new XmlDeclarationWrapper((XmlDeclaration) node);
- default:
- return new XmlNodeWrapper(node);
- }
- }
-
- public IList Attributes
- {
- get
- {
- if (_node.Attributes == null)
- return null;
-
- return _node.Attributes.Cast().Select(a => WrapNode(a)).ToList();
- }
- }
-
- public IXmlNode ParentNode
- {
- get
- {
- XmlNode node = (_node is XmlAttribute)
- ? ((XmlAttribute) _node).OwnerElement
- : _node.ParentNode;
-
- if (node == null)
- return null;
-
- return WrapNode(node);
- }
- }
-
- public string Value
- {
- get { return _node.Value; }
- set { _node.Value = value; }
- }
-
- public IXmlNode AppendChild(IXmlNode newChild)
- {
- XmlNodeWrapper xmlNodeWrapper = (XmlNodeWrapper) newChild;
- _node.AppendChild(xmlNodeWrapper._node);
-
- return newChild;
- }
-
- public string Prefix
- {
- get { return _node.Prefix; }
- }
-
- public string NamespaceUri
- {
- get { return _node.NamespaceURI; }
- }
- }
-#endif
- #endregion
-
- #region Interfaces
- internal interface IXmlDocument : IXmlNode
- {
- IXmlNode CreateComment(string text);
- IXmlNode CreateTextNode(string text);
- IXmlNode CreateCDataSection(string data);
- IXmlNode CreateWhitespace(string text);
- IXmlNode CreateSignificantWhitespace(string text);
- IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone);
- IXmlNode CreateProcessingInstruction(string target, string data);
- IXmlElement CreateElement(string elementName);
- IXmlElement CreateElement(string qualifiedName, string namespaceUri);
- IXmlNode CreateAttribute(string name, string value);
- IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value);
-
- IXmlElement DocumentElement { get; }
- }
-
- internal interface IXmlDeclaration : IXmlNode
- {
- string Version { get; }
- string Encoding { get; set; }
- string Standalone { get; set; }
- }
-
- internal interface IXmlElement : IXmlNode
- {
- void SetAttributeNode(IXmlNode attribute);
- string GetPrefixOfNamespace(string namespaceUri);
- }
-
- internal interface IXmlNode
- {
- XmlNodeType NodeType { get; }
- string LocalName { get; }
- IList ChildNodes { get; }
- IList Attributes { get; }
- IXmlNode ParentNode { get; }
- string Value { get; set; }
- IXmlNode AppendChild(IXmlNode newChild);
- string NamespaceUri { get; }
- object WrappedNode { get; }
- }
- #endregion
-
- #region XNodeWrappers
-#if !NET20
- internal class XDeclarationWrapper : XObjectWrapper, IXmlDeclaration
- {
- internal XDeclaration Declaration { get; private set; }
-
- public XDeclarationWrapper(XDeclaration declaration)
- : base(null)
- {
- Declaration = declaration;
- }
-
- public override XmlNodeType NodeType
- {
- get { return XmlNodeType.XmlDeclaration; }
- }
-
- public string Version
- {
- get { return Declaration.Version; }
- }
-
- public string Encoding
- {
- get { return Declaration.Encoding; }
- set { Declaration.Encoding = value; }
- }
-
- public string Standalone
- {
- get { return Declaration.Standalone; }
- set { Declaration.Standalone = value; }
- }
- }
-
- internal class XDocumentWrapper : XContainerWrapper, IXmlDocument
- {
- private XDocument Document
- {
- get { return (XDocument)WrappedNode; }
- }
-
- public XDocumentWrapper(XDocument document)
- : base(document)
- {
- }
-
- public override IList ChildNodes
- {
- get
- {
- IList childNodes = base.ChildNodes;
-
- if (Document.Declaration != null)
- childNodes.Insert(0, new XDeclarationWrapper(Document.Declaration));
-
- return childNodes;
- }
- }
-
- public IXmlNode CreateComment(string text)
- {
- return new XObjectWrapper(new XComment(text));
- }
-
- public IXmlNode CreateTextNode(string text)
- {
- return new XObjectWrapper(new XText(text));
- }
-
- public IXmlNode CreateCDataSection(string data)
- {
- return new XObjectWrapper(new XCData(data));
- }
-
- public IXmlNode CreateWhitespace(string text)
- {
- return new XObjectWrapper(new XText(text));
- }
-
- public IXmlNode CreateSignificantWhitespace(string text)
- {
- return new XObjectWrapper(new XText(text));
- }
-
- public IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone)
- {
- return new XDeclarationWrapper(new XDeclaration(version, encoding, standalone));
- }
-
- public IXmlNode CreateProcessingInstruction(string target, string data)
- {
- return new XProcessingInstructionWrapper(new XProcessingInstruction(target, data));
- }
-
- public IXmlElement CreateElement(string elementName)
- {
- return new XElementWrapper(new XElement(elementName));
- }
-
- public IXmlElement CreateElement(string qualifiedName, string namespaceUri)
- {
- string localName = MiscellaneousUtils.GetLocalName(qualifiedName);
- return new XElementWrapper(new XElement(XName.Get(localName, namespaceUri)));
- }
-
- public IXmlNode CreateAttribute(string name, string value)
- {
- return new XAttributeWrapper(new XAttribute(name, value));
- }
-
- public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value)
- {
- string localName = MiscellaneousUtils.GetLocalName(qualifiedName);
- return new XAttributeWrapper(new XAttribute(XName.Get(localName, namespaceUri), value));
- }
-
- public IXmlElement DocumentElement
- {
- get
- {
- if (Document.Root == null)
- return null;
-
- return new XElementWrapper(Document.Root);
- }
- }
-
- public override IXmlNode AppendChild(IXmlNode newChild)
- {
- XDeclarationWrapper declarationWrapper = newChild as XDeclarationWrapper;
- if (declarationWrapper != null)
- {
- Document.Declaration = declarationWrapper.Declaration;
- return declarationWrapper;
- }
- else
- {
- return base.AppendChild(newChild);
- }
- }
- }
-
- internal class XTextWrapper : XObjectWrapper
- {
- private XText Text
- {
- get { return (XText)WrappedNode; }
- }
-
- public XTextWrapper(XText text)
- : base(text)
- {
- }
-
- public override string Value
- {
- get { return Text.Value; }
- set { Text.Value = value; }
- }
-
- public override IXmlNode ParentNode
- {
- get
- {
- if (Text.Parent == null)
- return null;
-
- return XContainerWrapper.WrapNode(Text.Parent);
- }
- }
- }
-
- internal class XCommentWrapper : XObjectWrapper
- {
- private XComment Text
- {
- get { return (XComment)WrappedNode; }
- }
-
- public XCommentWrapper(XComment text)
- : base(text)
- {
- }
-
- public override string Value
- {
- get { return Text.Value; }
- set { Text.Value = value; }
- }
-
- public override IXmlNode ParentNode
- {
- get
- {
- if (Text.Parent == null)
- return null;
-
- return XContainerWrapper.WrapNode(Text.Parent);
- }
- }
- }
-
- internal class XProcessingInstructionWrapper : XObjectWrapper
- {
- private XProcessingInstruction ProcessingInstruction
- {
- get { return (XProcessingInstruction)WrappedNode; }
- }
-
- public XProcessingInstructionWrapper(XProcessingInstruction processingInstruction)
- : base(processingInstruction)
- {
- }
-
- public override string LocalName
- {
- get { return ProcessingInstruction.Target; }
- }
-
- public override string Value
- {
- get { return ProcessingInstruction.Data; }
- set { ProcessingInstruction.Data = value; }
- }
- }
-
- internal class XContainerWrapper : XObjectWrapper
- {
- private XContainer Container
- {
- get { return (XContainer)WrappedNode; }
- }
-
- public XContainerWrapper(XContainer container)
- : base(container)
- {
- }
-
- public override IList ChildNodes
- {
- get { return Container.Nodes().Select(n => WrapNode(n)).ToList(); }
- }
-
- public override IXmlNode ParentNode
- {
- get
- {
- if (Container.Parent == null)
- return null;
-
- return WrapNode(Container.Parent);
- }
- }
-
- internal static IXmlNode WrapNode(XObject node)
- {
- if (node is XDocument)
- return new XDocumentWrapper((XDocument)node);
- else if (node is XElement)
- return new XElementWrapper((XElement)node);
- else if (node is XContainer)
- return new XContainerWrapper((XContainer)node);
- else if (node is XProcessingInstruction)
- return new XProcessingInstructionWrapper((XProcessingInstruction)node);
- else if (node is XText)
- return new XTextWrapper((XText)node);
- else if (node is XComment)
- return new XCommentWrapper((XComment)node);
- else if (node is XAttribute)
- return new XAttributeWrapper((XAttribute) node);
- else
- return new XObjectWrapper(node);
- }
-
- public override IXmlNode AppendChild(IXmlNode newChild)
- {
- Container.Add(newChild.WrappedNode);
- return newChild;
- }
- }
-
- internal class XObjectWrapper : IXmlNode
- {
- private readonly XObject _xmlObject;
-
- public XObjectWrapper(XObject xmlObject)
- {
- _xmlObject = xmlObject;
- }
-
- public object WrappedNode
- {
- get { return _xmlObject; }
- }
-
- public virtual XmlNodeType NodeType
- {
- get { return _xmlObject.NodeType; }
- }
-
- public virtual string LocalName
- {
- get { return null; }
- }
-
- public virtual IList ChildNodes
- {
- get { return new List(); }
- }
-
- public virtual IList Attributes
- {
- get { return null; }
- }
-
- public virtual IXmlNode ParentNode
- {
- get { return null; }
- }
-
- public virtual string Value
- {
- get { return null; }
- set { throw new InvalidOperationException(); }
- }
-
- public virtual IXmlNode AppendChild(IXmlNode newChild)
- {
- throw new InvalidOperationException();
- }
-
- public virtual string NamespaceUri
- {
- get { return null; }
- }
- }
-
- internal class XAttributeWrapper : XObjectWrapper
- {
- private XAttribute Attribute
- {
- get { return (XAttribute)WrappedNode; }
- }
-
- public XAttributeWrapper(XAttribute attribute)
- : base(attribute)
- {
- }
-
- public override string Value
- {
- get { return Attribute.Value; }
- set { Attribute.Value = value; }
- }
-
- public override string LocalName
- {
- get { return Attribute.Name.LocalName; }
- }
-
- public override string NamespaceUri
- {
- get { return Attribute.Name.NamespaceName; }
- }
-
- public override IXmlNode ParentNode
- {
- get
- {
- if (Attribute.Parent == null)
- return null;
-
- return XContainerWrapper.WrapNode(Attribute.Parent);
- }
- }
- }
-
- internal class XElementWrapper : XContainerWrapper, IXmlElement
- {
- private XElement Element
- {
- get { return (XElement) WrappedNode; }
- }
-
- public XElementWrapper(XElement element)
- : base(element)
- {
- }
-
- public void SetAttributeNode(IXmlNode attribute)
- {
- XObjectWrapper wrapper = (XObjectWrapper)attribute;
- Element.Add(wrapper.WrappedNode);
- }
-
- public override IList Attributes
- {
- get { return Element.Attributes().Select(a => new XAttributeWrapper(a)).Cast().ToList(); }
- }
-
- public override string Value
- {
- get { return Element.Value; }
- set { Element.Value = value; }
- }
-
- public override string LocalName
- {
- get { return Element.Name.LocalName; }
- }
-
- public override string NamespaceUri
- {
- get { return Element.Name.NamespaceName; }
- }
-
- public string GetPrefixOfNamespace(string namespaceUri)
- {
- return Element.GetPrefixOfNamespace(namespaceUri);
- }
- }
-#endif
- #endregion
-
- ///
- /// Converts XML to and from JSON.
- ///
- public class XmlNodeConverter : JsonConverter
- {
- private const string TextName = "#text";
- private const string CommentName = "#comment";
- private const string CDataName = "#cdata-section";
- private const string WhitespaceName = "#whitespace";
- private const string SignificantWhitespaceName = "#significant-whitespace";
- private const string DeclarationName = "?xml";
- private const string JsonNamespaceUri = "http://james.newtonking.com/projects/json";
-
- ///
- /// Gets or sets the name of the root element to insert when deserializing to XML if the JSON structure has produces multiple root elements.
- ///
- /// The name of the deserialize root element.
- public string DeserializeRootElementName { get; set; }
-
- ///
- /// Gets or sets a flag to indicate whether to write the Json.NET array attribute.
- /// This attribute helps preserve arrays when converting the written XML back to JSON.
- ///
- /// true if the array attibute is written to the XML; otherwise, false.
- public bool WriteArrayAttribute { get; set; }
-
- ///
- /// Gets or sets a value indicating whether to write the root JSON object.
- ///
- /// true if the JSON root object is omitted; otherwise, false.
- public bool OmitRootObject { get; set; }
-
- #region Writing
- ///
- /// Writes the JSON representation of the object.
- ///
- /// The to write to.
- /// The calling serializer.
- /// The value.
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
- {
- IXmlNode node = WrapXml(value);
-
- XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
- PushParentNamespaces(node, manager);
-
- if (!OmitRootObject)
- writer.WriteStartObject();
-
- SerializeNode(writer, node, manager, !OmitRootObject);
-
- if (!OmitRootObject)
- writer.WriteEndObject();
- }
-
- private IXmlNode WrapXml(object value)
- {
-#if !NET20
- if (value is XObject)
- return XContainerWrapper.WrapNode((XObject)value);
-#endif
-#if !(SILVERLIGHT || NETFX_CORE)
- if (value is XmlNode)
- return new XmlNodeWrapper((XmlNode)value);
-#endif
-
- throw new ArgumentException("Value must be an XML object.", "value");
- }
-
- private void PushParentNamespaces(IXmlNode node, XmlNamespaceManager manager)
- {
- List parentElements = null;
-
- IXmlNode parent = node;
- while ((parent = parent.ParentNode) != null)
- {
- if (parent.NodeType == XmlNodeType.Element)
- {
- if (parentElements == null)
- parentElements = new List();
-
- parentElements.Add(parent);
- }
- }
-
- if (parentElements != null)
- {
- parentElements.Reverse();
-
- foreach (IXmlNode parentElement in parentElements)
- {
- manager.PushScope();
- foreach (IXmlNode attribute in parentElement.Attributes)
- {
- if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/" && attribute.LocalName != "xmlns")
- manager.AddNamespace(attribute.LocalName, attribute.Value);
- }
- }
- }
- }
-
- private string ResolveFullName(IXmlNode node, XmlNamespaceManager manager)
- {
- string prefix = (node.NamespaceUri == null || (node.LocalName == "xmlns" && node.NamespaceUri == "http://www.w3.org/2000/xmlns/"))
- ? null
- : manager.LookupPrefix(node.NamespaceUri);
-
- if (!string.IsNullOrEmpty(prefix))
- return prefix + ":" + node.LocalName;
- else
- return node.LocalName;
- }
-
- private string GetPropertyName(IXmlNode node, XmlNamespaceManager manager)
- {
- switch (node.NodeType)
- {
- case XmlNodeType.Attribute:
- if (node.NamespaceUri == JsonNamespaceUri)
- return "$" + node.LocalName;
- else
- return "@" + ResolveFullName(node, manager);
- case XmlNodeType.CDATA:
- return CDataName;
- case XmlNodeType.Comment:
- return CommentName;
- case XmlNodeType.Element:
- return ResolveFullName(node, manager);
- case XmlNodeType.ProcessingInstruction:
- return "?" + ResolveFullName(node, manager);
- case XmlNodeType.XmlDeclaration:
- return DeclarationName;
- case XmlNodeType.SignificantWhitespace:
- return SignificantWhitespaceName;
- case XmlNodeType.Text:
- return TextName;
- case XmlNodeType.Whitespace:
- return WhitespaceName;
- default:
- throw new JsonSerializationException("Unexpected XmlNodeType when getting node name: " + node.NodeType);
- }
- }
-
- private bool IsArray(IXmlNode node)
- {
- IXmlNode jsonArrayAttribute = (node.Attributes != null)
- ? node.Attributes.SingleOrDefault(a => a.LocalName == "Array" && a.NamespaceUri == JsonNamespaceUri)
- : null;
-
- return (jsonArrayAttribute != null && XmlConvert.ToBoolean(jsonArrayAttribute.Value));
- }
-
- private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
- {
- // group nodes together by name
- Dictionary> nodesGroupedByName = new Dictionary>();
-
- for (int i = 0; i < node.ChildNodes.Count; i++)
- {
- IXmlNode childNode = node.ChildNodes[i];
- string nodeName = GetPropertyName(childNode, manager);
-
- List nodes;
- if (!nodesGroupedByName.TryGetValue(nodeName, out nodes))
- {
- nodes = new List();
- nodesGroupedByName.Add(nodeName, nodes);
- }
-
- nodes.Add(childNode);
- }
-
- // loop through grouped nodes. write single name instances as normal,
- // write multiple names together in an array
- foreach (KeyValuePair> nodeNameGroup in nodesGroupedByName)
- {
- List groupedNodes = nodeNameGroup.Value;
- bool writeArray;
-
- if (groupedNodes.Count == 1)
- {
- writeArray = IsArray(groupedNodes[0]);
- }
- else
- {
- writeArray = true;
- }
-
- if (!writeArray)
- {
- SerializeNode(writer, groupedNodes[0], manager, writePropertyName);
- }
- else
- {
- string elementNames = nodeNameGroup.Key;
-
- if (writePropertyName)
- writer.WritePropertyName(elementNames);
-
- writer.WriteStartArray();
-
- for (int i = 0; i < groupedNodes.Count; i++)
- {
- SerializeNode(writer, groupedNodes[i], manager, false);
- }
-
- writer.WriteEndArray();
- }
- }
- }
-
- private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
- {
- switch (node.NodeType)
- {
- case XmlNodeType.Document:
- case XmlNodeType.DocumentFragment:
- SerializeGroupedNodes(writer, node, manager, writePropertyName);
- break;
- case XmlNodeType.Element:
- if (IsArray(node) && node.ChildNodes.All(n => n.LocalName == node.LocalName) && node.ChildNodes.Count > 0)
- {
- SerializeGroupedNodes(writer, node, manager, false);
- }
- else
- {
- foreach (IXmlNode attribute in node.Attributes)
- {
- if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/")
- {
- string prefix = (attribute.LocalName != "xmlns")
- ? attribute.LocalName
- : string.Empty;
-
- manager.AddNamespace(prefix, attribute.Value);
- }
- }
-
- if (writePropertyName)
- writer.WritePropertyName(GetPropertyName(node, manager));
-
- if (!ValueAttributes(node.Attributes).Any() && node.ChildNodes.Count == 1
- && node.ChildNodes[0].NodeType == XmlNodeType.Text)
- {
- // write elements with a single text child as a name value pair
- writer.WriteValue(node.ChildNodes[0].Value);
- }
- else if (node.ChildNodes.Count == 0 && CollectionUtils.IsNullOrEmpty(node.Attributes))
- {
- // empty element
- writer.WriteNull();
- }
- else
- {
- writer.WriteStartObject();
-
- for (int i = 0; i < node.Attributes.Count; i++)
- {
- SerializeNode(writer, node.Attributes[i], manager, true);
- }
-
- SerializeGroupedNodes(writer, node, manager, true);
-
- writer.WriteEndObject();
- }
- }
-
- break;
- case XmlNodeType.Comment:
- if (writePropertyName)
- writer.WriteComment(node.Value);
- break;
- case XmlNodeType.Attribute:
- case XmlNodeType.Text:
- case XmlNodeType.CDATA:
- case XmlNodeType.ProcessingInstruction:
- case XmlNodeType.Whitespace:
- case XmlNodeType.SignificantWhitespace:
- if (node.NamespaceUri == "http://www.w3.org/2000/xmlns/" && node.Value == JsonNamespaceUri)
- return;
-
- if (node.NamespaceUri == JsonNamespaceUri)
- {
- if (node.LocalName == "Array")
- return;
- }
-
- if (writePropertyName)
- writer.WritePropertyName(GetPropertyName(node, manager));
- writer.WriteValue(node.Value);
- break;
- case XmlNodeType.XmlDeclaration:
- IXmlDeclaration declaration = (IXmlDeclaration)node;
- writer.WritePropertyName(GetPropertyName(node, manager));
- writer.WriteStartObject();
-
- if (!string.IsNullOrEmpty(declaration.Version))
- {
- writer.WritePropertyName("@version");
- writer.WriteValue(declaration.Version);
- }
- if (!string.IsNullOrEmpty(declaration.Encoding))
- {
- writer.WritePropertyName("@encoding");
- writer.WriteValue(declaration.Encoding);
- }
- if (!string.IsNullOrEmpty(declaration.Standalone))
- {
- writer.WritePropertyName("@standalone");
- writer.WriteValue(declaration.Standalone);
- }
-
- writer.WriteEndObject();
- break;
- default:
- throw new JsonSerializationException("Unexpected XmlNodeType when serializing nodes: " + node.NodeType);
- }
- }
- #endregion
-
- #region Reading
- ///
- /// Reads the JSON representation of the object.
- ///
- /// The to read from.
- /// Type of the object.
- /// The existing value of object being read.
- /// The calling serializer.
- /// The object value.
- public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
- {
- XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
- IXmlDocument document = null;
- IXmlNode rootNode = null;
-
-#if !NET20
- if (typeof(XObject).IsAssignableFrom(objectType))
- {
- if (objectType != typeof (XDocument) && objectType != typeof (XElement))
- throw new JsonSerializationException("XmlNodeConverter only supports deserializing XDocument or XElement.");
-
- XDocument d = new XDocument();
- document = new XDocumentWrapper(d);
- rootNode = document;
- }
-#endif
-#if !(SILVERLIGHT || NETFX_CORE)
- if (typeof(XmlNode).IsAssignableFrom(objectType))
- {
- if (objectType != typeof (XmlDocument))
- throw new JsonSerializationException("XmlNodeConverter only supports deserializing XmlDocuments");
-
- XmlDocument d = new XmlDocument();
- document = new XmlDocumentWrapper(d);
- rootNode = document;
- }
-#endif
-
- if (document == null || rootNode == null)
- throw new JsonSerializationException("Unexpected type when converting XML: " + objectType);
-
- if (reader.TokenType != JsonToken.StartObject)
- throw new JsonSerializationException("XmlNodeConverter can only convert JSON that begins with an object.");
-
- if (!string.IsNullOrEmpty(DeserializeRootElementName))
- {
- //rootNode = document.CreateElement(DeserializeRootElementName);
- //document.AppendChild(rootNode);
- ReadElement(reader, document, rootNode, DeserializeRootElementName, manager);
- }
- else
- {
- reader.Read();
- DeserializeNode(reader, document, manager, rootNode);
- }
-
-#if !NET20
- if (objectType == typeof(XElement))
- {
- XElement element = (XElement)document.DocumentElement.WrappedNode;
- element.Remove();
-
- return element;
- }
-#endif
-
- return document.WrappedNode;
- }
-
- private void DeserializeValue(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, string propertyName, IXmlNode currentNode)
- {
- switch (propertyName)
- {
- case TextName:
- currentNode.AppendChild(document.CreateTextNode(reader.Value.ToString()));
- break;
- case CDataName:
- currentNode.AppendChild(document.CreateCDataSection(reader.Value.ToString()));
- break;
- case WhitespaceName:
- currentNode.AppendChild(document.CreateWhitespace(reader.Value.ToString()));
- break;
- case SignificantWhitespaceName:
- currentNode.AppendChild(document.CreateSignificantWhitespace(reader.Value.ToString()));
- break;
- default:
- // processing instructions and the xml declaration start with ?
- if (!string.IsNullOrEmpty(propertyName) && propertyName[0] == '?')
- {
- CreateInstruction(reader, document, currentNode, propertyName);
- }
- else
- {
- if (reader.TokenType == JsonToken.StartArray)
- {
- // handle nested arrays
- ReadArrayElements(reader, document, propertyName, currentNode, manager);
- return;
- }
-
- // have to wait until attributes have been parsed before creating element
- // attributes may contain namespace info used by the element
- ReadElement(reader, document, currentNode, propertyName, manager);
- }
- break;
- }
- }
-
- private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, XmlNamespaceManager manager)
- {
- if (string.IsNullOrEmpty(propertyName))
- throw new JsonSerializationException("XmlNodeConverter cannot convert JSON with an empty property name to XML.");
-
- Dictionary attributeNameValues = ReadAttributeElements(reader, manager);
-
- string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);
-
- IXmlElement element = CreateElement(propertyName, document, elementPrefix, manager);
-
- currentNode.AppendChild(element);
-
- // add attributes to newly created element
- foreach (KeyValuePair nameValue in attributeNameValues)
- {
- string attributePrefix = MiscellaneousUtils.GetPrefix(nameValue.Key);
-
- IXmlNode attribute = (!string.IsNullOrEmpty(attributePrefix))
- ? document.CreateAttribute(nameValue.Key, manager.LookupNamespace(attributePrefix), nameValue.Value)
- : document.CreateAttribute(nameValue.Key, nameValue.Value);
-
- element.SetAttributeNode(attribute);
- }
-
- if (reader.TokenType == JsonToken.String
- || reader.TokenType == JsonToken.Integer
- || reader.TokenType == JsonToken.Float
- || reader.TokenType == JsonToken.Boolean
- || reader.TokenType == JsonToken.Date)
- {
- element.AppendChild(document.CreateTextNode(ConvertTokenToXmlValue(reader)));
- }
- else if (reader.TokenType == JsonToken.Null)
- {
- // empty element. do nothing
- }
- else
- {
- // finished element will have no children to deserialize
- if (reader.TokenType != JsonToken.EndObject)
- {
- manager.PushScope();
-
- DeserializeNode(reader, document, manager, element);
-
- manager.PopScope();
- }
- }
- }
-
- private string ConvertTokenToXmlValue(JsonReader reader)
- {
- if (reader.TokenType == JsonToken.String)
- {
- return reader.Value.ToString();
- }
- else if (reader.TokenType == JsonToken.Integer)
- {
- return XmlConvert.ToString(Convert.ToInt64(reader.Value, CultureInfo.InvariantCulture));
- }
- else if (reader.TokenType == JsonToken.Float)
- {
- return XmlConvert.ToString(Convert.ToDouble(reader.Value, CultureInfo.InvariantCulture));
- }
- else if (reader.TokenType == JsonToken.Boolean)
- {
- return XmlConvert.ToString(Convert.ToBoolean(reader.Value, CultureInfo.InvariantCulture));
- }
- else if (reader.TokenType == JsonToken.Date)
- {
- DateTime d = Convert.ToDateTime(reader.Value, CultureInfo.InvariantCulture);
-#if !NETFX_CORE
- return XmlConvert.ToString(d, DateTimeUtils.ToSerializationMode(d.Kind));
-#else
- return XmlConvert.ToString(d);
-#endif
- }
- else if (reader.TokenType == JsonToken.Null)
- {
- return null;
- }
- else
- {
- throw new Exception("Cannot get an XML string value from token type '{0}'.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
- }
- }
-
- private void ReadArrayElements(JsonReader reader, IXmlDocument document, string propertyName, IXmlNode currentNode, XmlNamespaceManager manager)
- {
- string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);
-
- IXmlElement nestedArrayElement = CreateElement(propertyName, document, elementPrefix, manager);
-
- currentNode.AppendChild(nestedArrayElement);
-
- int count = 0;
- while (reader.Read() && reader.TokenType != JsonToken.EndArray)
- {
- DeserializeValue(reader, document, manager, propertyName, nestedArrayElement);
- count++;
- }
-
- if (WriteArrayAttribute)
- {
- AddJsonArrayAttribute(nestedArrayElement, document);
- }
-
- if (count == 1 && WriteArrayAttribute)
- {
- IXmlElement arrayElement = nestedArrayElement.ChildNodes.CastValid().Single(n => n.LocalName == propertyName);
- AddJsonArrayAttribute(arrayElement, document);
- }
- }
-
- private void AddJsonArrayAttribute(IXmlElement element, IXmlDocument document)
- {
- element.SetAttributeNode(document.CreateAttribute("json:Array", JsonNamespaceUri, "true"));
-
-#if !NET20
- // linq to xml doesn't automatically include prefixes via the namespace manager
- if (element is XElementWrapper)
- {
- if (element.GetPrefixOfNamespace(JsonNamespaceUri) == null)
- {
- element.SetAttributeNode(document.CreateAttribute("xmlns:json", "http://www.w3.org/2000/xmlns/", JsonNamespaceUri));
- }
- }
-#endif
- }
-
- private Dictionary ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager)
- {
- Dictionary attributeNameValues = new Dictionary();
- bool finishedAttributes = false;
- bool finishedElement = false;
-
- // a string token means the element only has a single text child
- if (reader.TokenType != JsonToken.String
- && reader.TokenType != JsonToken.Null
- && reader.TokenType != JsonToken.Boolean
- && reader.TokenType != JsonToken.Integer
- && reader.TokenType != JsonToken.Float
- && reader.TokenType != JsonToken.Date
- && reader.TokenType != JsonToken.StartConstructor)
- {
- // read properties until first non-attribute is encountered
- while (!finishedAttributes && !finishedElement && reader.Read())
- {
- switch (reader.TokenType)
- {
- case JsonToken.PropertyName:
- string attributeName = reader.Value.ToString();
-
- if (!string.IsNullOrEmpty(attributeName))
- {
- char firstChar = attributeName[0];
- string attributeValue;
-
- switch (firstChar)
- {
- case '@':
- attributeName = attributeName.Substring(1);
- reader.Read();
- attributeValue = ConvertTokenToXmlValue(reader);
- attributeNameValues.Add(attributeName, attributeValue);
-
- string namespacePrefix;
- if (IsNamespaceAttribute(attributeName, out namespacePrefix))
- {
- manager.AddNamespace(namespacePrefix, attributeValue);
- }
- break;
- case '$':
- attributeName = attributeName.Substring(1);
- reader.Read();
- attributeValue = reader.Value.ToString();
-
- // check that JsonNamespaceUri is in scope
- // if it isn't then add it to document and namespace manager
- string jsonPrefix = manager.LookupPrefix(JsonNamespaceUri);
- if (jsonPrefix == null)
- {
- // ensure that the prefix used is free
- int? i = null;
- while (manager.LookupNamespace("json" + i) != null)
- {
- i = i.GetValueOrDefault() + 1;
- }
- jsonPrefix = "json" + i;
-
- attributeNameValues.Add("xmlns:" + jsonPrefix, JsonNamespaceUri);
- manager.AddNamespace(jsonPrefix, JsonNamespaceUri);
- }
-
- attributeNameValues.Add(jsonPrefix + ":" + attributeName, attributeValue);
- break;
- default:
- finishedAttributes = true;
- break;
- }
- }
- else
- {
- finishedAttributes = true;
- }
-
- break;
- case JsonToken.EndObject:
- finishedElement = true;
- break;
- default:
- throw new JsonSerializationException("Unexpected JsonToken: " + reader.TokenType);
- }
- }
- }
-
- return attributeNameValues;
- }
-
- private void CreateInstruction(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName)
- {
- if (propertyName == DeclarationName)
- {
- string version = null;
- string encoding = null;
- string standalone = null;
- while (reader.Read() && reader.TokenType != JsonToken.EndObject)
- {
- switch (reader.Value.ToString())
- {
- case "@version":
- reader.Read();
- version = reader.Value.ToString();
- break;
- case "@encoding":
- reader.Read();
- encoding = reader.Value.ToString();
- break;
- case "@standalone":
- reader.Read();
- standalone = reader.Value.ToString();
- break;
- default:
- throw new JsonSerializationException("Unexpected property name encountered while deserializing XmlDeclaration: " + reader.Value);
- }
- }
-
- IXmlNode declaration = document.CreateXmlDeclaration(version, encoding, standalone);
- currentNode.AppendChild(declaration);
- }
- else
- {
- IXmlNode instruction = document.CreateProcessingInstruction(propertyName.Substring(1), reader.Value.ToString());
- currentNode.AppendChild(instruction);
- }
- }
-
- private IXmlElement CreateElement(string elementName, IXmlDocument document, string elementPrefix, XmlNamespaceManager manager)
- {
- string ns = string.IsNullOrEmpty(elementPrefix) ? manager.DefaultNamespace : manager.LookupNamespace(elementPrefix);
-
- IXmlElement element = (!string.IsNullOrEmpty(ns)) ? document.CreateElement(elementName, ns) : document.CreateElement(elementName);
-
- return element;
- }
-
- private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, IXmlNode currentNode)
- {
- do
- {
- switch (reader.TokenType)
- {
- case JsonToken.PropertyName:
- if (currentNode.NodeType == XmlNodeType.Document && document.DocumentElement != null)
- throw new JsonSerializationException("JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifing a DeserializeRootElementName.");
-
- string propertyName = reader.Value.ToString();
- reader.Read();
-
- if (reader.TokenType == JsonToken.StartArray)
- {
- int count = 0;
- while (reader.Read() && reader.TokenType != JsonToken.EndArray)
- {
- DeserializeValue(reader, document, manager, propertyName, currentNode);
- count++;
- }
-
- if (count == 1 && WriteArrayAttribute)
- {
- IXmlElement arrayElement = currentNode.ChildNodes.CastValid().Single(n => n.LocalName == propertyName);
- AddJsonArrayAttribute(arrayElement, document);
- }
- }
- else
- {
- DeserializeValue(reader, document, manager, propertyName, currentNode);
- }
- break;
- case JsonToken.StartConstructor:
- string constructorName = reader.Value.ToString();
-
- while (reader.Read() && reader.TokenType != JsonToken.EndConstructor)
- {
- DeserializeValue(reader, document, manager, constructorName, currentNode);
- }
- break;
- case JsonToken.Comment:
- currentNode.AppendChild(document.CreateComment((string)reader.Value));
- break;
- case JsonToken.EndObject:
- case JsonToken.EndArray:
- return;
- default:
- throw new JsonSerializationException("Unexpected JsonToken when deserializing node: " + reader.TokenType);
- }
- } while (reader.TokenType == JsonToken.PropertyName || reader.Read());
- // don't read if current token is a property. token was already read when parsing element attributes
- }
-
- ///
- /// Checks if the attributeName is a namespace attribute.
- ///
- /// Attribute name to test.
- /// The attribute name prefix if it has one, otherwise an empty string.
- /// True if attribute name is for a namespace attribute, otherwise false.
- private bool IsNamespaceAttribute(string attributeName, out string prefix)
- {
- if (attributeName.StartsWith("xmlns", StringComparison.Ordinal))
- {
- if (attributeName.Length == 5)
- {
- prefix = string.Empty;
- return true;
- }
- else if (attributeName[5] == ':')
- {
- prefix = attributeName.Substring(6, attributeName.Length - 6);
- return true;
- }
- }
- prefix = null;
- return false;
- }
-
- private IEnumerable ValueAttributes(IEnumerable c)
- {
- return c.Where(a => a.NamespaceUri != JsonNamespaceUri);
- }
- #endregion
-
- ///
- /// Determines whether this instance can convert the specified value type.
- ///
- /// Type of the value.
- ///
- /// true if this instance can convert the specified value type; otherwise, false.
- ///
- public override bool CanConvert(Type valueType)
- {
-#if !NET20
- if (typeof(XObject).IsAssignableFrom(valueType))
- return true;
-#endif
-#if !(SILVERLIGHT || NETFX_CORE)
- if (typeof(XmlNode).IsAssignableFrom(valueType))
- return true;
-#endif
-
- return false;
- }
- }
-}
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+#if (!SILVERLIGHT || WINDOWS_PHONE)
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Xml;
+#if !NET20
+using System.Xml.Linq;
+#endif
+using Newtonsoft.Json.Utilities;
+#if NET20
+using Newtonsoft.Json.Utilities.LinqBridge;
+#else
+using System.Linq;
+#endif
+
+namespace Newtonsoft.Json.Converters
+{
+ #region XmlNodeWrappers
+#if !SILVERLIGHT && !NETFX_CORE
+ internal class XmlDocumentWrapper : XmlNodeWrapper, IXmlDocument
+ {
+ private readonly XmlDocument _document;
+
+ public XmlDocumentWrapper(XmlDocument document)
+ : base(document)
+ {
+ _document = document;
+ }
+
+ public IXmlNode CreateComment(string data)
+ {
+ return new XmlNodeWrapper(_document.CreateComment(data));
+ }
+
+ public IXmlNode CreateTextNode(string text)
+ {
+ return new XmlNodeWrapper(_document.CreateTextNode(text));
+ }
+
+ public IXmlNode CreateCDataSection(string data)
+ {
+ return new XmlNodeWrapper(_document.CreateCDataSection(data));
+ }
+
+ public IXmlNode CreateWhitespace(string text)
+ {
+ return new XmlNodeWrapper(_document.CreateWhitespace(text));
+ }
+
+ public IXmlNode CreateSignificantWhitespace(string text)
+ {
+ return new XmlNodeWrapper(_document.CreateSignificantWhitespace(text));
+ }
+
+ public IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone)
+ {
+ return new XmlNodeWrapper(_document.CreateXmlDeclaration(version, encoding, standalone));
+ }
+
+ public IXmlNode CreateProcessingInstruction(string target, string data)
+ {
+ return new XmlNodeWrapper(_document.CreateProcessingInstruction(target, data));
+ }
+
+ public IXmlElement CreateElement(string elementName)
+ {
+ return new XmlElementWrapper(_document.CreateElement(elementName));
+ }
+
+ public IXmlElement CreateElement(string qualifiedName, string namespaceUri)
+ {
+ return new XmlElementWrapper(_document.CreateElement(qualifiedName, namespaceUri));
+ }
+
+ public IXmlNode CreateAttribute(string name, string value)
+ {
+ XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(name));
+ attribute.Value = value;
+
+ return attribute;
+ }
+
+ public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value)
+ {
+ XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(qualifiedName, namespaceUri));
+ attribute.Value = value;
+
+ return attribute;
+ }
+
+ public IXmlElement DocumentElement
+ {
+ get
+ {
+ if (_document.DocumentElement == null)
+ return null;
+
+ return new XmlElementWrapper(_document.DocumentElement);
+ }
+ }
+ }
+
+ internal class XmlElementWrapper : XmlNodeWrapper, IXmlElement
+ {
+ private readonly XmlElement _element;
+
+ public XmlElementWrapper(XmlElement element)
+ : base(element)
+ {
+ _element = element;
+ }
+
+ public void SetAttributeNode(IXmlNode attribute)
+ {
+ XmlNodeWrapper xmlAttributeWrapper = (XmlNodeWrapper)attribute;
+
+ _element.SetAttributeNode((XmlAttribute) xmlAttributeWrapper.WrappedNode);
+ }
+
+ public string GetPrefixOfNamespace(string namespaceUri)
+ {
+ return _element.GetPrefixOfNamespace(namespaceUri);
+ }
+ }
+
+ internal class XmlDeclarationWrapper : XmlNodeWrapper, IXmlDeclaration
+ {
+ private readonly XmlDeclaration _declaration;
+
+ public XmlDeclarationWrapper(XmlDeclaration declaration)
+ : base(declaration)
+ {
+ _declaration = declaration;
+ }
+
+ public string Version
+ {
+ get { return _declaration.Version; }
+ }
+
+ public string Encoding
+ {
+ get { return _declaration.Encoding; }
+ set { _declaration.Encoding = value; }
+ }
+
+ public string Standalone
+ {
+ get { return _declaration.Standalone; }
+ set { _declaration.Standalone = value; }
+ }
+ }
+
+ internal class XmlNodeWrapper : IXmlNode
+ {
+ private readonly XmlNode _node;
+
+ public XmlNodeWrapper(XmlNode node)
+ {
+ _node = node;
+ }
+
+ public object WrappedNode
+ {
+ get { return _node; }
+ }
+
+ public XmlNodeType NodeType
+ {
+ get { return _node.NodeType; }
+ }
+
+ public string Name
+ {
+ get { return _node.Name; }
+ }
+
+ public string LocalName
+ {
+ get { return _node.LocalName; }
+ }
+
+ public IList ChildNodes
+ {
+ get { return _node.ChildNodes.Cast().Select(n => WrapNode(n)).ToList(); }
+ }
+
+ private IXmlNode WrapNode(XmlNode node)
+ {
+ switch (node.NodeType)
+ {
+ case XmlNodeType.Element:
+ return new XmlElementWrapper((XmlElement) node);
+ case XmlNodeType.XmlDeclaration:
+ return new XmlDeclarationWrapper((XmlDeclaration) node);
+ default:
+ return new XmlNodeWrapper(node);
+ }
+ }
+
+ public IList Attributes
+ {
+ get
+ {
+ if (_node.Attributes == null)
+ return null;
+
+ return _node.Attributes.Cast().Select(a => WrapNode(a)).ToList();
+ }
+ }
+
+ public IXmlNode ParentNode
+ {
+ get
+ {
+ XmlNode node = (_node is XmlAttribute)
+ ? ((XmlAttribute) _node).OwnerElement
+ : _node.ParentNode;
+
+ if (node == null)
+ return null;
+
+ return WrapNode(node);
+ }
+ }
+
+ public string Value
+ {
+ get { return _node.Value; }
+ set { _node.Value = value; }
+ }
+
+ public IXmlNode AppendChild(IXmlNode newChild)
+ {
+ XmlNodeWrapper xmlNodeWrapper = (XmlNodeWrapper) newChild;
+ _node.AppendChild(xmlNodeWrapper._node);
+
+ return newChild;
+ }
+
+ public string Prefix
+ {
+ get { return _node.Prefix; }
+ }
+
+ public string NamespaceUri
+ {
+ get { return _node.NamespaceURI; }
+ }
+ }
+#endif
+ #endregion
+
+ #region Interfaces
+ internal interface IXmlDocument : IXmlNode
+ {
+ IXmlNode CreateComment(string text);
+ IXmlNode CreateTextNode(string text);
+ IXmlNode CreateCDataSection(string data);
+ IXmlNode CreateWhitespace(string text);
+ IXmlNode CreateSignificantWhitespace(string text);
+ IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone);
+ IXmlNode CreateProcessingInstruction(string target, string data);
+ IXmlElement CreateElement(string elementName);
+ IXmlElement CreateElement(string qualifiedName, string namespaceUri);
+ IXmlNode CreateAttribute(string name, string value);
+ IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value);
+
+ IXmlElement DocumentElement { get; }
+ }
+
+ internal interface IXmlDeclaration : IXmlNode
+ {
+ string Version { get; }
+ string Encoding { get; set; }
+ string Standalone { get; set; }
+ }
+
+ internal interface IXmlElement : IXmlNode
+ {
+ void SetAttributeNode(IXmlNode attribute);
+ string GetPrefixOfNamespace(string namespaceUri);
+ }
+
+ internal interface IXmlNode
+ {
+ XmlNodeType NodeType { get; }
+ string LocalName { get; }
+ IList ChildNodes { get; }
+ IList Attributes { get; }
+ IXmlNode ParentNode { get; }
+ string Value { get; set; }
+ IXmlNode AppendChild(IXmlNode newChild);
+ string NamespaceUri { get; }
+ object WrappedNode { get; }
+ }
+ #endregion
+
+ #region XNodeWrappers
+#if !NET20
+ internal class XDeclarationWrapper : XObjectWrapper, IXmlDeclaration
+ {
+ internal XDeclaration Declaration { get; private set; }
+
+ public XDeclarationWrapper(XDeclaration declaration)
+ : base(null)
+ {
+ Declaration = declaration;
+ }
+
+ public override XmlNodeType NodeType
+ {
+ get { return XmlNodeType.XmlDeclaration; }
+ }
+
+ public string Version
+ {
+ get { return Declaration.Version; }
+ }
+
+ public string Encoding
+ {
+ get { return Declaration.Encoding; }
+ set { Declaration.Encoding = value; }
+ }
+
+ public string Standalone
+ {
+ get { return Declaration.Standalone; }
+ set { Declaration.Standalone = value; }
+ }
+ }
+
+ internal class XDocumentWrapper : XContainerWrapper, IXmlDocument
+ {
+ private XDocument Document
+ {
+ get { return (XDocument)WrappedNode; }
+ }
+
+ public XDocumentWrapper(XDocument document)
+ : base(document)
+ {
+ }
+
+ public override IList ChildNodes
+ {
+ get
+ {
+ IList childNodes = base.ChildNodes;
+
+ if (Document.Declaration != null)
+ childNodes.Insert(0, new XDeclarationWrapper(Document.Declaration));
+
+ return childNodes;
+ }
+ }
+
+ public IXmlNode CreateComment(string text)
+ {
+ return new XObjectWrapper(new XComment(text));
+ }
+
+ public IXmlNode CreateTextNode(string text)
+ {
+ return new XObjectWrapper(new XText(text));
+ }
+
+ public IXmlNode CreateCDataSection(string data)
+ {
+ return new XObjectWrapper(new XCData(data));
+ }
+
+ public IXmlNode CreateWhitespace(string text)
+ {
+ return new XObjectWrapper(new XText(text));
+ }
+
+ public IXmlNode CreateSignificantWhitespace(string text)
+ {
+ return new XObjectWrapper(new XText(text));
+ }
+
+ public IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone)
+ {
+ return new XDeclarationWrapper(new XDeclaration(version, encoding, standalone));
+ }
+
+ public IXmlNode CreateProcessingInstruction(string target, string data)
+ {
+ return new XProcessingInstructionWrapper(new XProcessingInstruction(target, data));
+ }
+
+ public IXmlElement CreateElement(string elementName)
+ {
+ return new XElementWrapper(new XElement(elementName));
+ }
+
+ public IXmlElement CreateElement(string qualifiedName, string namespaceUri)
+ {
+ string localName = MiscellaneousUtils.GetLocalName(qualifiedName);
+ return new XElementWrapper(new XElement(XName.Get(localName, namespaceUri)));
+ }
+
+ public IXmlNode CreateAttribute(string name, string value)
+ {
+ return new XAttributeWrapper(new XAttribute(name, value));
+ }
+
+ public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value)
+ {
+ string localName = MiscellaneousUtils.GetLocalName(qualifiedName);
+ return new XAttributeWrapper(new XAttribute(XName.Get(localName, namespaceUri), value));
+ }
+
+ public IXmlElement DocumentElement
+ {
+ get
+ {
+ if (Document.Root == null)
+ return null;
+
+ return new XElementWrapper(Document.Root);
+ }
+ }
+
+ public override IXmlNode AppendChild(IXmlNode newChild)
+ {
+ XDeclarationWrapper declarationWrapper = newChild as XDeclarationWrapper;
+ if (declarationWrapper != null)
+ {
+ Document.Declaration = declarationWrapper.Declaration;
+ return declarationWrapper;
+ }
+ else
+ {
+ return base.AppendChild(newChild);
+ }
+ }
+ }
+
+ internal class XTextWrapper : XObjectWrapper
+ {
+ private XText Text
+ {
+ get { return (XText)WrappedNode; }
+ }
+
+ public XTextWrapper(XText text)
+ : base(text)
+ {
+ }
+
+ public override string Value
+ {
+ get { return Text.Value; }
+ set { Text.Value = value; }
+ }
+
+ public override IXmlNode ParentNode
+ {
+ get
+ {
+ if (Text.Parent == null)
+ return null;
+
+ return XContainerWrapper.WrapNode(Text.Parent);
+ }
+ }
+ }
+
+ internal class XCommentWrapper : XObjectWrapper
+ {
+ private XComment Text
+ {
+ get { return (XComment)WrappedNode; }
+ }
+
+ public XCommentWrapper(XComment text)
+ : base(text)
+ {
+ }
+
+ public override string Value
+ {
+ get { return Text.Value; }
+ set { Text.Value = value; }
+ }
+
+ public override IXmlNode ParentNode
+ {
+ get
+ {
+ if (Text.Parent == null)
+ return null;
+
+ return XContainerWrapper.WrapNode(Text.Parent);
+ }
+ }
+ }
+
+ internal class XProcessingInstructionWrapper : XObjectWrapper
+ {
+ private XProcessingInstruction ProcessingInstruction
+ {
+ get { return (XProcessingInstruction)WrappedNode; }
+ }
+
+ public XProcessingInstructionWrapper(XProcessingInstruction processingInstruction)
+ : base(processingInstruction)
+ {
+ }
+
+ public override string LocalName
+ {
+ get { return ProcessingInstruction.Target; }
+ }
+
+ public override string Value
+ {
+ get { return ProcessingInstruction.Data; }
+ set { ProcessingInstruction.Data = value; }
+ }
+ }
+
+ internal class XContainerWrapper : XObjectWrapper
+ {
+ private XContainer Container
+ {
+ get { return (XContainer)WrappedNode; }
+ }
+
+ public XContainerWrapper(XContainer container)
+ : base(container)
+ {
+ }
+
+ public override IList ChildNodes
+ {
+ get { return Container.Nodes().Select(n => WrapNode(n)).ToList(); }
+ }
+
+ public override IXmlNode ParentNode
+ {
+ get
+ {
+ if (Container.Parent == null)
+ return null;
+
+ return WrapNode(Container.Parent);
+ }
+ }
+
+ internal static IXmlNode WrapNode(XObject node)
+ {
+ if (node is XDocument)
+ return new XDocumentWrapper((XDocument)node);
+ else if (node is XElement)
+ return new XElementWrapper((XElement)node);
+ else if (node is XContainer)
+ return new XContainerWrapper((XContainer)node);
+ else if (node is XProcessingInstruction)
+ return new XProcessingInstructionWrapper((XProcessingInstruction)node);
+ else if (node is XText)
+ return new XTextWrapper((XText)node);
+ else if (node is XComment)
+ return new XCommentWrapper((XComment)node);
+ else if (node is XAttribute)
+ return new XAttributeWrapper((XAttribute) node);
+ else
+ return new XObjectWrapper(node);
+ }
+
+ public override IXmlNode AppendChild(IXmlNode newChild)
+ {
+ Container.Add(newChild.WrappedNode);
+ return newChild;
+ }
+ }
+
+ internal class XObjectWrapper : IXmlNode
+ {
+ private readonly XObject _xmlObject;
+
+ public XObjectWrapper(XObject xmlObject)
+ {
+ _xmlObject = xmlObject;
+ }
+
+ public object WrappedNode
+ {
+ get { return _xmlObject; }
+ }
+
+ public virtual XmlNodeType NodeType
+ {
+ get { return _xmlObject.NodeType; }
+ }
+
+ public virtual string LocalName
+ {
+ get { return null; }
+ }
+
+ public virtual IList ChildNodes
+ {
+ get { return new List(); }
+ }
+
+ public virtual IList Attributes
+ {
+ get { return null; }
+ }
+
+ public virtual IXmlNode ParentNode
+ {
+ get { return null; }
+ }
+
+ public virtual string Value
+ {
+ get { return null; }
+ set { throw new InvalidOperationException(); }
+ }
+
+ public virtual IXmlNode AppendChild(IXmlNode newChild)
+ {
+ throw new InvalidOperationException();
+ }
+
+ public virtual string NamespaceUri
+ {
+ get { return null; }
+ }
+ }
+
+ internal class XAttributeWrapper : XObjectWrapper
+ {
+ private XAttribute Attribute
+ {
+ get { return (XAttribute)WrappedNode; }
+ }
+
+ public XAttributeWrapper(XAttribute attribute)
+ : base(attribute)
+ {
+ }
+
+ public override string Value
+ {
+ get { return Attribute.Value; }
+ set { Attribute.Value = value; }
+ }
+
+ public override string LocalName
+ {
+ get { return Attribute.Name.LocalName; }
+ }
+
+ public override string NamespaceUri
+ {
+ get { return Attribute.Name.NamespaceName; }
+ }
+
+ public override IXmlNode ParentNode
+ {
+ get
+ {
+ if (Attribute.Parent == null)
+ return null;
+
+ return XContainerWrapper.WrapNode(Attribute.Parent);
+ }
+ }
+ }
+
+ internal class XElementWrapper : XContainerWrapper, IXmlElement
+ {
+ private XElement Element
+ {
+ get { return (XElement) WrappedNode; }
+ }
+
+ public XElementWrapper(XElement element)
+ : base(element)
+ {
+ }
+
+ public void SetAttributeNode(IXmlNode attribute)
+ {
+ XObjectWrapper wrapper = (XObjectWrapper)attribute;
+ Element.Add(wrapper.WrappedNode);
+ }
+
+ public override IList Attributes
+ {
+ get { return Element.Attributes().Select(a => new XAttributeWrapper(a)).Cast().ToList(); }
+ }
+
+ public override string Value
+ {
+ get { return Element.Value; }
+ set { Element.Value = value; }
+ }
+
+ public override string LocalName
+ {
+ get { return Element.Name.LocalName; }
+ }
+
+ public override string NamespaceUri
+ {
+ get { return Element.Name.NamespaceName; }
+ }
+
+ public string GetPrefixOfNamespace(string namespaceUri)
+ {
+ return Element.GetPrefixOfNamespace(namespaceUri);
+ }
+ }
+#endif
+ #endregion
+
+ ///
+ /// Converts XML to and from JSON.
+ ///
+ public class XmlNodeConverter : JsonConverter
+ {
+ private const string TextName = "#text";
+ private const string CommentName = "#comment";
+ private const string CDataName = "#cdata-section";
+ private const string WhitespaceName = "#whitespace";
+ private const string SignificantWhitespaceName = "#significant-whitespace";
+ private const string DeclarationName = "?xml";
+ private const string JsonNamespaceUri = "http://james.newtonking.com/projects/json";
+
+ ///
+ /// Gets or sets the name of the root element to insert when deserializing to XML if the JSON structure has produces multiple root elements.
+ ///
+ /// The name of the deserialize root element.
+ public string DeserializeRootElementName { get; set; }
+
+ ///
+ /// Gets or sets a flag to indicate whether to write the Json.NET array attribute.
+ /// This attribute helps preserve arrays when converting the written XML back to JSON.
+ ///
+ /// true if the array attibute is written to the XML; otherwise, false.
+ public bool WriteArrayAttribute { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether to write the root JSON object.
+ ///
+ /// true if the JSON root object is omitted; otherwise, false.
+ public bool OmitRootObject { get; set; }
+
+ #region Writing
+ ///
+ /// Writes the JSON representation of the object.
+ ///
+ /// The to write to.
+ /// The calling serializer.
+ /// The value.
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ IXmlNode node = WrapXml(value);
+
+ XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
+ PushParentNamespaces(node, manager);
+
+ if (!OmitRootObject)
+ writer.WriteStartObject();
+
+ SerializeNode(writer, node, manager, !OmitRootObject);
+
+ if (!OmitRootObject)
+ writer.WriteEndObject();
+ }
+
+ private IXmlNode WrapXml(object value)
+ {
+#if !NET20
+ if (value is XObject)
+ return XContainerWrapper.WrapNode((XObject)value);
+#endif
+#if !(SILVERLIGHT || NETFX_CORE)
+ if (value is XmlNode)
+ return new XmlNodeWrapper((XmlNode)value);
+#endif
+
+ throw new ArgumentException("Value must be an XML object.", "value");
+ }
+
+ private void PushParentNamespaces(IXmlNode node, XmlNamespaceManager manager)
+ {
+ List parentElements = null;
+
+ IXmlNode parent = node;
+ while ((parent = parent.ParentNode) != null)
+ {
+ if (parent.NodeType == XmlNodeType.Element)
+ {
+ if (parentElements == null)
+ parentElements = new List();
+
+ parentElements.Add(parent);
+ }
+ }
+
+ if (parentElements != null)
+ {
+ parentElements.Reverse();
+
+ foreach (IXmlNode parentElement in parentElements)
+ {
+ manager.PushScope();
+ foreach (IXmlNode attribute in parentElement.Attributes)
+ {
+ if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/" && attribute.LocalName != "xmlns")
+ manager.AddNamespace(attribute.LocalName, attribute.Value);
+ }
+ }
+ }
+ }
+
+ private string ResolveFullName(IXmlNode node, XmlNamespaceManager manager)
+ {
+ string prefix = (node.NamespaceUri == null || (node.LocalName == "xmlns" && node.NamespaceUri == "http://www.w3.org/2000/xmlns/"))
+ ? null
+ : manager.LookupPrefix(node.NamespaceUri);
+
+ if (!string.IsNullOrEmpty(prefix))
+ return prefix + ":" + node.LocalName;
+ else
+ return node.LocalName;
+ }
+
+ private string GetPropertyName(IXmlNode node, XmlNamespaceManager manager)
+ {
+ switch (node.NodeType)
+ {
+ case XmlNodeType.Attribute:
+ if (node.NamespaceUri == JsonNamespaceUri)
+ return "$" + node.LocalName;
+ else
+ return "@" + ResolveFullName(node, manager);
+ case XmlNodeType.CDATA:
+ return CDataName;
+ case XmlNodeType.Comment:
+ return CommentName;
+ case XmlNodeType.Element:
+ return ResolveFullName(node, manager);
+ case XmlNodeType.ProcessingInstruction:
+ return "?" + ResolveFullName(node, manager);
+ case XmlNodeType.XmlDeclaration:
+ return DeclarationName;
+ case XmlNodeType.SignificantWhitespace:
+ return SignificantWhitespaceName;
+ case XmlNodeType.Text:
+ return TextName;
+ case XmlNodeType.Whitespace:
+ return WhitespaceName;
+ default:
+ throw new JsonSerializationException("Unexpected XmlNodeType when getting node name: " + node.NodeType);
+ }
+ }
+
+ private bool IsArray(IXmlNode node)
+ {
+ IXmlNode jsonArrayAttribute = (node.Attributes != null)
+ ? node.Attributes.SingleOrDefault(a => a.LocalName == "Array" && a.NamespaceUri == JsonNamespaceUri)
+ : null;
+
+ return (jsonArrayAttribute != null && XmlConvert.ToBoolean(jsonArrayAttribute.Value));
+ }
+
+ private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
+ {
+ // group nodes together by name
+ Dictionary> nodesGroupedByName = new Dictionary>();
+
+ for (int i = 0; i < node.ChildNodes.Count; i++)
+ {
+ IXmlNode childNode = node.ChildNodes[i];
+ string nodeName = GetPropertyName(childNode, manager);
+
+ List nodes;
+ if (!nodesGroupedByName.TryGetValue(nodeName, out nodes))
+ {
+ nodes = new List();
+ nodesGroupedByName.Add(nodeName, nodes);
+ }
+
+ nodes.Add(childNode);
+ }
+
+ // loop through grouped nodes. write single name instances as normal,
+ // write multiple names together in an array
+ foreach (KeyValuePair> nodeNameGroup in nodesGroupedByName)
+ {
+ List groupedNodes = nodeNameGroup.Value;
+ bool writeArray;
+
+ if (groupedNodes.Count == 1)
+ {
+ writeArray = IsArray(groupedNodes[0]);
+ }
+ else
+ {
+ writeArray = true;
+ }
+
+ if (!writeArray)
+ {
+ SerializeNode(writer, groupedNodes[0], manager, writePropertyName);
+ }
+ else
+ {
+ string elementNames = nodeNameGroup.Key;
+
+ if (writePropertyName)
+ writer.WritePropertyName(elementNames);
+
+ writer.WriteStartArray();
+
+ for (int i = 0; i < groupedNodes.Count; i++)
+ {
+ SerializeNode(writer, groupedNodes[i], manager, false);
+ }
+
+ writer.WriteEndArray();
+ }
+ }
+ }
+
+ private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
+ {
+ switch (node.NodeType)
+ {
+ case XmlNodeType.Document:
+ case XmlNodeType.DocumentFragment:
+ SerializeGroupedNodes(writer, node, manager, writePropertyName);
+ break;
+ case XmlNodeType.Element:
+ if (IsArray(node) && node.ChildNodes.All(n => n.LocalName == node.LocalName) && node.ChildNodes.Count > 0)
+ {
+ SerializeGroupedNodes(writer, node, manager, false);
+ }
+ else
+ {
+ foreach (IXmlNode attribute in node.Attributes)
+ {
+ if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/")
+ {
+ string prefix = (attribute.LocalName != "xmlns")
+ ? attribute.LocalName
+ : string.Empty;
+
+ manager.AddNamespace(prefix, attribute.Value);
+ }
+ }
+
+ if (writePropertyName)
+ writer.WritePropertyName(GetPropertyName(node, manager));
+
+ if (!ValueAttributes(node.Attributes).Any() && node.ChildNodes.Count == 1
+ && node.ChildNodes[0].NodeType == XmlNodeType.Text)
+ {
+ // write elements with a single text child as a name value pair
+ writer.WriteValue(node.ChildNodes[0].Value);
+ }
+ else if (node.ChildNodes.Count == 0 && CollectionUtils.IsNullOrEmpty(node.Attributes))
+ {
+ // empty element
+ writer.WriteNull();
+ }
+ else
+ {
+ writer.WriteStartObject();
+
+ for (int i = 0; i < node.Attributes.Count; i++)
+ {
+ SerializeNode(writer, node.Attributes[i], manager, true);
+ }
+
+ SerializeGroupedNodes(writer, node, manager, true);
+
+ writer.WriteEndObject();
+ }
+ }
+
+ break;
+ case XmlNodeType.Comment:
+ if (writePropertyName)
+ writer.WriteComment(node.Value);
+ break;
+ case XmlNodeType.Attribute:
+ case XmlNodeType.Text:
+ case XmlNodeType.CDATA:
+ case XmlNodeType.ProcessingInstruction:
+ case XmlNodeType.Whitespace:
+ case XmlNodeType.SignificantWhitespace:
+ if (node.NamespaceUri == "http://www.w3.org/2000/xmlns/" && node.Value == JsonNamespaceUri)
+ return;
+
+ if (node.NamespaceUri == JsonNamespaceUri)
+ {
+ if (node.LocalName == "Array")
+ return;
+ }
+
+ if (writePropertyName)
+ writer.WritePropertyName(GetPropertyName(node, manager));
+ writer.WriteValue(node.Value);
+ break;
+ case XmlNodeType.XmlDeclaration:
+ IXmlDeclaration declaration = (IXmlDeclaration)node;
+ writer.WritePropertyName(GetPropertyName(node, manager));
+ writer.WriteStartObject();
+
+ if (!string.IsNullOrEmpty(declaration.Version))
+ {
+ writer.WritePropertyName("@version");
+ writer.WriteValue(declaration.Version);
+ }
+ if (!string.IsNullOrEmpty(declaration.Encoding))
+ {
+ writer.WritePropertyName("@encoding");
+ writer.WriteValue(declaration.Encoding);
+ }
+ if (!string.IsNullOrEmpty(declaration.Standalone))
+ {
+ writer.WritePropertyName("@standalone");
+ writer.WriteValue(declaration.Standalone);
+ }
+
+ writer.WriteEndObject();
+ break;
+ default:
+ throw new JsonSerializationException("Unexpected XmlNodeType when serializing nodes: " + node.NodeType);
+ }
+ }
+ #endregion
+
+ #region Reading
+ ///
+ /// Reads the JSON representation of the object.
+ ///
+ /// The to read from.
+ /// Type of the object.
+ /// The existing value of object being read.
+ /// The calling serializer.
+ /// The object value.
+ public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ {
+ XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
+ IXmlDocument document = null;
+ IXmlNode rootNode = null;
+
+#if !NET20
+ if (typeof(XObject).IsAssignableFrom(objectType))
+ {
+ if (objectType != typeof (XDocument) && objectType != typeof (XElement))
+ throw new JsonSerializationException("XmlNodeConverter only supports deserializing XDocument or XElement.");
+
+ XDocument d = new XDocument();
+ document = new XDocumentWrapper(d);
+ rootNode = document;
+ }
+#endif
+#if !(SILVERLIGHT || NETFX_CORE)
+ if (typeof(XmlNode).IsAssignableFrom(objectType))
+ {
+ if (objectType != typeof (XmlDocument))
+ throw new JsonSerializationException("XmlNodeConverter only supports deserializing XmlDocuments");
+
+ XmlDocument d = new XmlDocument();
+ document = new XmlDocumentWrapper(d);
+ rootNode = document;
+ }
+#endif
+
+ if (document == null || rootNode == null)
+ throw new JsonSerializationException("Unexpected type when converting XML: " + objectType);
+
+ if (reader.TokenType != JsonToken.StartObject)
+ throw new JsonSerializationException("XmlNodeConverter can only convert JSON that begins with an object.");
+
+ if (!string.IsNullOrEmpty(DeserializeRootElementName))
+ {
+ //rootNode = document.CreateElement(DeserializeRootElementName);
+ //document.AppendChild(rootNode);
+ ReadElement(reader, document, rootNode, DeserializeRootElementName, manager);
+ }
+ else
+ {
+ reader.Read();
+ DeserializeNode(reader, document, manager, rootNode);
+ }
+
+#if !NET20
+ if (objectType == typeof(XElement))
+ {
+ XElement element = (XElement)document.DocumentElement.WrappedNode;
+ element.Remove();
+
+ return element;
+ }
+#endif
+
+ return document.WrappedNode;
+ }
+
+ private void DeserializeValue(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, string propertyName, IXmlNode currentNode)
+ {
+ switch (propertyName)
+ {
+ case TextName:
+ currentNode.AppendChild(document.CreateTextNode(reader.Value.ToString()));
+ break;
+ case CDataName:
+ currentNode.AppendChild(document.CreateCDataSection(reader.Value.ToString()));
+ break;
+ case WhitespaceName:
+ currentNode.AppendChild(document.CreateWhitespace(reader.Value.ToString()));
+ break;
+ case SignificantWhitespaceName:
+ currentNode.AppendChild(document.CreateSignificantWhitespace(reader.Value.ToString()));
+ break;
+ default:
+ // processing instructions and the xml declaration start with ?
+ if (!string.IsNullOrEmpty(propertyName) && propertyName[0] == '?')
+ {
+ CreateInstruction(reader, document, currentNode, propertyName);
+ }
+ else
+ {
+ if (reader.TokenType == JsonToken.StartArray)
+ {
+ // handle nested arrays
+ ReadArrayElements(reader, document, propertyName, currentNode, manager);
+ return;
+ }
+
+ // have to wait until attributes have been parsed before creating element
+ // attributes may contain namespace info used by the element
+ ReadElement(reader, document, currentNode, propertyName, manager);
+ }
+ break;
+ }
+ }
+
+ private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, XmlNamespaceManager manager)
+ {
+ if (string.IsNullOrEmpty(propertyName))
+ throw new JsonSerializationException("XmlNodeConverter cannot convert JSON with an empty property name to XML.");
+
+ Dictionary attributeNameValues = ReadAttributeElements(reader, manager);
+
+ string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);
+
+ if (propertyName.StartsWith("@"))
+ {
+ var attributeName = propertyName.Substring(1);
+ var attributeValue = reader.Value.ToString();
+
+ var attributePrefix = MiscellaneousUtils.GetPrefix(attributeName);
+
+ var attribute = (!string.IsNullOrEmpty(attributePrefix))
+ ? document.CreateAttribute(attributeName, manager.LookupNamespace(attributePrefix), attributeValue)
+ : document.CreateAttribute(attributeName, attributeValue);
+
+ ((IXmlElement)currentNode).SetAttributeNode(attribute);
+ }
+ else
+ {
+ IXmlElement element = CreateElement(propertyName, document, elementPrefix, manager);
+
+ currentNode.AppendChild(element);
+
+ // add attributes to newly created element
+ foreach (KeyValuePair nameValue in attributeNameValues)
+ {
+ string attributePrefix = MiscellaneousUtils.GetPrefix(nameValue.Key);
+
+ IXmlNode attribute = (!string.IsNullOrEmpty(attributePrefix))
+ ? document.CreateAttribute(nameValue.Key, manager.LookupNamespace(attributePrefix), nameValue.Value)
+ : document.CreateAttribute(nameValue.Key, nameValue.Value);
+
+ element.SetAttributeNode(attribute);
+ }
+
+ if (reader.TokenType == JsonToken.String
+ || reader.TokenType == JsonToken.Integer
+ || reader.TokenType == JsonToken.Float
+ || reader.TokenType == JsonToken.Boolean
+ || reader.TokenType == JsonToken.Date)
+ {
+ element.AppendChild(document.CreateTextNode(ConvertTokenToXmlValue(reader)));
+ }
+ else if (reader.TokenType == JsonToken.Null)
+ {
+ // empty element. do nothing
+ }
+ else
+ {
+ // finished element will have no children to deserialize
+ if (reader.TokenType != JsonToken.EndObject)
+ {
+ manager.PushScope();
+
+ DeserializeNode(reader, document, manager, element);
+
+ manager.PopScope();
+ }
+ }
+ }
+ }
+
+ private string ConvertTokenToXmlValue(JsonReader reader)
+ {
+ if (reader.TokenType == JsonToken.String)
+ {
+ return reader.Value.ToString();
+ }
+ else if (reader.TokenType == JsonToken.Integer)
+ {
+ return XmlConvert.ToString(Convert.ToInt64(reader.Value, CultureInfo.InvariantCulture));
+ }
+ else if (reader.TokenType == JsonToken.Float)
+ {
+ return XmlConvert.ToString(Convert.ToDouble(reader.Value, CultureInfo.InvariantCulture));
+ }
+ else if (reader.TokenType == JsonToken.Boolean)
+ {
+ return XmlConvert.ToString(Convert.ToBoolean(reader.Value, CultureInfo.InvariantCulture));
+ }
+ else if (reader.TokenType == JsonToken.Date)
+ {
+ DateTime d = Convert.ToDateTime(reader.Value, CultureInfo.InvariantCulture);
+#if !NETFX_CORE
+ return XmlConvert.ToString(d, DateTimeUtils.ToSerializationMode(d.Kind));
+#else
+ return XmlConvert.ToString(d);
+#endif
+ }
+ else if (reader.TokenType == JsonToken.Null)
+ {
+ return null;
+ }
+ else
+ {
+ throw new Exception("Cannot get an XML string value from token type '{0}'.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
+ }
+ }
+
+ private void ReadArrayElements(JsonReader reader, IXmlDocument document, string propertyName, IXmlNode currentNode, XmlNamespaceManager manager)
+ {
+ string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);
+
+ IXmlElement nestedArrayElement = CreateElement(propertyName, document, elementPrefix, manager);
+
+ currentNode.AppendChild(nestedArrayElement);
+
+ int count = 0;
+ while (reader.Read() && reader.TokenType != JsonToken.EndArray)
+ {
+ DeserializeValue(reader, document, manager, propertyName, nestedArrayElement);
+ count++;
+ }
+
+ if (WriteArrayAttribute)
+ {
+ AddJsonArrayAttribute(nestedArrayElement, document);
+ }
+
+ if (count == 1 && WriteArrayAttribute)
+ {
+ IXmlElement arrayElement = nestedArrayElement.ChildNodes.CastValid().Single(n => n.LocalName == propertyName);
+ AddJsonArrayAttribute(arrayElement, document);
+ }
+ }
+
+ private void AddJsonArrayAttribute(IXmlElement element, IXmlDocument document)
+ {
+ element.SetAttributeNode(document.CreateAttribute("json:Array", JsonNamespaceUri, "true"));
+
+#if !NET20
+ // linq to xml doesn't automatically include prefixes via the namespace manager
+ if (element is XElementWrapper)
+ {
+ if (element.GetPrefixOfNamespace(JsonNamespaceUri) == null)
+ {
+ element.SetAttributeNode(document.CreateAttribute("xmlns:json", "http://www.w3.org/2000/xmlns/", JsonNamespaceUri));
+ }
+ }
+#endif
+ }
+
+ private Dictionary ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager)
+ {
+ Dictionary attributeNameValues = new Dictionary();
+ bool finishedAttributes = false;
+ bool finishedElement = false;
+
+ // a string token means the element only has a single text child
+ if (reader.TokenType != JsonToken.String
+ && reader.TokenType != JsonToken.Null
+ && reader.TokenType != JsonToken.Boolean
+ && reader.TokenType != JsonToken.Integer
+ && reader.TokenType != JsonToken.Float
+ && reader.TokenType != JsonToken.Date
+ && reader.TokenType != JsonToken.StartConstructor)
+ {
+ // read properties until first non-attribute is encountered
+ while (!finishedAttributes && !finishedElement && reader.Read())
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.PropertyName:
+ string attributeName = reader.Value.ToString();
+
+ if (!string.IsNullOrEmpty(attributeName))
+ {
+ char firstChar = attributeName[0];
+ string attributeValue;
+
+ switch (firstChar)
+ {
+ case '@':
+ attributeName = attributeName.Substring(1);
+ reader.Read();
+ attributeValue = ConvertTokenToXmlValue(reader);
+ attributeNameValues.Add(attributeName, attributeValue);
+
+ string namespacePrefix;
+ if (IsNamespaceAttribute(attributeName, out namespacePrefix))
+ {
+ manager.AddNamespace(namespacePrefix, attributeValue);
+ }
+ break;
+ case '$':
+ attributeName = attributeName.Substring(1);
+ reader.Read();
+ attributeValue = reader.Value.ToString();
+
+ // check that JsonNamespaceUri is in scope
+ // if it isn't then add it to document and namespace manager
+ string jsonPrefix = manager.LookupPrefix(JsonNamespaceUri);
+ if (jsonPrefix == null)
+ {
+ // ensure that the prefix used is free
+ int? i = null;
+ while (manager.LookupNamespace("json" + i) != null)
+ {
+ i = i.GetValueOrDefault() + 1;
+ }
+ jsonPrefix = "json" + i;
+
+ attributeNameValues.Add("xmlns:" + jsonPrefix, JsonNamespaceUri);
+ manager.AddNamespace(jsonPrefix, JsonNamespaceUri);
+ }
+
+ attributeNameValues.Add(jsonPrefix + ":" + attributeName, attributeValue);
+ break;
+ default:
+ finishedAttributes = true;
+ break;
+ }
+ }
+ else
+ {
+ finishedAttributes = true;
+ }
+
+ break;
+ case JsonToken.EndObject:
+ finishedElement = true;
+ break;
+ default:
+ throw new JsonSerializationException("Unexpected JsonToken: " + reader.TokenType);
+ }
+ }
+ }
+
+ return attributeNameValues;
+ }
+
+ private void CreateInstruction(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName)
+ {
+ if (propertyName == DeclarationName)
+ {
+ string version = null;
+ string encoding = null;
+ string standalone = null;
+ while (reader.Read() && reader.TokenType != JsonToken.EndObject)
+ {
+ switch (reader.Value.ToString())
+ {
+ case "@version":
+ reader.Read();
+ version = reader.Value.ToString();
+ break;
+ case "@encoding":
+ reader.Read();
+ encoding = reader.Value.ToString();
+ break;
+ case "@standalone":
+ reader.Read();
+ standalone = reader.Value.ToString();
+ break;
+ default:
+ throw new JsonSerializationException("Unexpected property name encountered while deserializing XmlDeclaration: " + reader.Value);
+ }
+ }
+
+ IXmlNode declaration = document.CreateXmlDeclaration(version, encoding, standalone);
+ currentNode.AppendChild(declaration);
+ }
+ else
+ {
+ IXmlNode instruction = document.CreateProcessingInstruction(propertyName.Substring(1), reader.Value.ToString());
+ currentNode.AppendChild(instruction);
+ }
+ }
+
+ private IXmlElement CreateElement(string elementName, IXmlDocument document, string elementPrefix, XmlNamespaceManager manager)
+ {
+ string ns = string.IsNullOrEmpty(elementPrefix) ? manager.DefaultNamespace : manager.LookupNamespace(elementPrefix);
+
+ IXmlElement element = (!string.IsNullOrEmpty(ns)) ? document.CreateElement(elementName, ns) : document.CreateElement(elementName);
+
+ return element;
+ }
+
+ private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, IXmlNode currentNode)
+ {
+ do
+ {
+ switch (reader.TokenType)
+ {
+ case JsonToken.PropertyName:
+ if (currentNode.NodeType == XmlNodeType.Document && document.DocumentElement != null)
+ throw new JsonSerializationException("JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifing a DeserializeRootElementName.");
+
+ string propertyName = reader.Value.ToString();
+ reader.Read();
+
+ if (reader.TokenType == JsonToken.StartArray)
+ {
+ int count = 0;
+ while (reader.Read() && reader.TokenType != JsonToken.EndArray)
+ {
+ DeserializeValue(reader, document, manager, propertyName, currentNode);
+ count++;
+ }
+
+ if (count == 1 && WriteArrayAttribute)
+ {
+ IXmlElement arrayElement = currentNode.ChildNodes.CastValid().Single(n => n.LocalName == propertyName);
+ AddJsonArrayAttribute(arrayElement, document);
+ }
+ }
+ else
+ {
+ DeserializeValue(reader, document, manager, propertyName, currentNode);
+ }
+ break;
+ case JsonToken.StartConstructor:
+ string constructorName = reader.Value.ToString();
+
+ while (reader.Read() && reader.TokenType != JsonToken.EndConstructor)
+ {
+ DeserializeValue(reader, document, manager, constructorName, currentNode);
+ }
+ break;
+ case JsonToken.Comment:
+ currentNode.AppendChild(document.CreateComment((string)reader.Value));
+ break;
+ case JsonToken.EndObject:
+ case JsonToken.EndArray:
+ return;
+ default:
+ throw new JsonSerializationException("Unexpected JsonToken when deserializing node: " + reader.TokenType);
+ }
+ } while (reader.TokenType == JsonToken.PropertyName || reader.Read());
+ // don't read if current token is a property. token was already read when parsing element attributes
+ }
+
+ ///
+ /// Checks if the attributeName is a namespace attribute.
+ ///
+ /// Attribute name to test.
+ /// The attribute name prefix if it has one, otherwise an empty string.
+ /// True if attribute name is for a namespace attribute, otherwise false.
+ private bool IsNamespaceAttribute(string attributeName, out string prefix)
+ {
+ if (attributeName.StartsWith("xmlns", StringComparison.Ordinal))
+ {
+ if (attributeName.Length == 5)
+ {
+ prefix = string.Empty;
+ return true;
+ }
+ else if (attributeName[5] == ':')
+ {
+ prefix = attributeName.Substring(6, attributeName.Length - 6);
+ return true;
+ }
+ }
+ prefix = null;
+ return false;
+ }
+
+ private IEnumerable ValueAttributes(IEnumerable c)
+ {
+ return c.Where(a => a.NamespaceUri != JsonNamespaceUri);
+ }
+ #endregion
+
+ ///
+ /// Determines whether this instance can convert the specified value type.
+ ///
+ /// Type of the value.
+ ///
+ /// true if this instance can convert the specified value type; otherwise, false.
+ ///
+ public override bool CanConvert(Type valueType)
+ {
+#if !NET20
+ if (typeof(XObject).IsAssignableFrom(valueType))
+ return true;
+#endif
+#if !(SILVERLIGHT || NETFX_CORE)
+ if (typeof(XmlNode).IsAssignableFrom(valueType))
+ return true;
+#endif
+
+ return false;
+ }
+ }
+}
#endif
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
index ba840dea..99d1f056 100644
--- a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
+++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
@@ -1,94 +1,94 @@
-#region License
-// Copyright (c) 2007 James Newton-King
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-#endregion
-
-using System;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Security;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-#if WINDOWS_PHONE
-[assembly: AssemblyTitle("Json.NET Windows Phone")]
-#elif SILVERLIGHT
-[assembly: AssemblyTitle("Json.NET Silverlight")]
-#elif PocketPC
-[assembly: AssemblyTitle("Json.NET Compact")]
-#elif NETFX_CORE
-[assembly: AssemblyTitle("Json.NET Metro")]
-[assembly: AllowPartiallyTrustedCallers]
-#elif NET20
-[assembly: AssemblyTitle("Json.NET .NET 2.0")]
-[assembly: AllowPartiallyTrustedCallers]
-#elif NET35
-[assembly: AssemblyTitle("Json.NET .NET 3.5")]
-[assembly: AllowPartiallyTrustedCallers]
-#else
-[assembly: AssemblyTitle("Json.NET")]
-[assembly: AllowPartiallyTrustedCallers]
-#endif
-
-#if !SIGNED
-[assembly: InternalsVisibleTo("Newtonsoft.Json.Tests")]
-#else
-[assembly: InternalsVisibleTo("Newtonsoft.Json.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f561df277c6c0b497d629032b410cdcf286e537c054724f7ffa0164345f62b3e642029d7a80cc351918955328c4adc8a048823ef90b0cf38ea7db0d729caf2b633c3babe08b0310198c1081995c19029bc675193744eab9d7345b8a67258ec17d112cebdbbb2a281487dceeafb9d83aa930f32103fbe1d2911425bc5744002c7")]
-#endif
-
-[assembly: InternalsVisibleTo("Newtonsoft.Json.Dynamic, PublicKey=0024000004800000940000000602000000240000525341310004000001000100cbd8d53b9d7de30f1f1278f636ec462cf9c254991291e66ebb157a885638a517887633b898ccbcf0d5c5ff7be85a6abe9e765d0ac7cd33c68dac67e7e64530e8222101109f154ab14a941c490ac155cd1d4fcba0fabb49016b4ef28593b015cab5937da31172f03f67d09edda404b88a60023f062ae71d0b2e4438b74cc11dc9")]
-
-[assembly: AssemblyDescription("Json.NET is a popular high-performance JSON framework for .NET")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Newtonsoft")]
-[assembly: AssemblyProduct("Json.NET")]
-[assembly: AssemblyCopyright("Copyright © James Newton-King 2008")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM componenets. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("9ca358aa-317b-4925-8ada-4a29e943a363")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Revision and Build Numbers
-// by using the '*' as shown below:
-[assembly: AssemblyVersion("4.5.0.0")]
-#if !PocketPC
-[assembly: AssemblyFileVersion("4.5.1.14719")]
-#endif
-
-[assembly: CLSCompliant(true)]
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+#if WINDOWS_PHONE
+[assembly: AssemblyTitle("Json.NET Windows Phone")]
+#elif SILVERLIGHT
+[assembly: AssemblyTitle("Json.NET Silverlight")]
+#elif PocketPC
+[assembly: AssemblyTitle("Json.NET Compact")]
+#elif NETFX_CORE
+[assembly: AssemblyTitle("Json.NET Metro")]
+[assembly: AllowPartiallyTrustedCallers]
+#elif NET20
+[assembly: AssemblyTitle("Json.NET .NET 2.0")]
+[assembly: AllowPartiallyTrustedCallers]
+#elif NET35
+[assembly: AssemblyTitle("Json.NET .NET 3.5")]
+[assembly: AllowPartiallyTrustedCallers]
+#else
+[assembly: AssemblyTitle("Json.NET")]
+[assembly: AllowPartiallyTrustedCallers]
+#endif
+
+#if !SIGNED
+[assembly: InternalsVisibleTo("Newtonsoft.Json.Tests")]
+#else
+[assembly: InternalsVisibleTo("Newtonsoft.Json.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f561df277c6c0b497d629032b410cdcf286e537c054724f7ffa0164345f62b3e642029d7a80cc351918955328c4adc8a048823ef90b0cf38ea7db0d729caf2b633c3babe08b0310198c1081995c19029bc675193744eab9d7345b8a67258ec17d112cebdbbb2a281487dceeafb9d83aa930f32103fbe1d2911425bc5744002c7")]
+#endif
+
+[assembly: InternalsVisibleTo("Newtonsoft.Json.Dynamic, PublicKey=0024000004800000940000000602000000240000525341310004000001000100cbd8d53b9d7de30f1f1278f636ec462cf9c254991291e66ebb157a885638a517887633b898ccbcf0d5c5ff7be85a6abe9e765d0ac7cd33c68dac67e7e64530e8222101109f154ab14a941c490ac155cd1d4fcba0fabb49016b4ef28593b015cab5937da31172f03f67d09edda404b88a60023f062ae71d0b2e4438b74cc11dc9")]
+
+[assembly: AssemblyDescription("Json.NET is a popular high-performance JSON framework for .NET")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Newtonsoft")]
+[assembly: AssemblyProduct("Json.NET")]
+[assembly: AssemblyCopyright("Copyright © James Newton-King 2008")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM componenets. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("9ca358aa-317b-4925-8ada-4a29e943a363")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("4.5.0.0")]
+#if !PocketPC
+[assembly: AssemblyFileVersion("4.5.1.14719")]
+#endif
+
+[assembly: CLSCompliant(true)]