PageRenderTime 10ms CodeModel.GetById 5ms app.highlight 26ms RepoModel.GetById 3ms app.codeStats 2ms

/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs

https://bitbucket.org/Ecarestia/newtonsoft.json
C# | 2987 lines | 2531 code | 399 blank | 57 comment | 16 complexity | 10293e1b597b93bcf08d97affd061578 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1#region License
   2// Copyright (c) 2007 James Newton-King
   3//
   4// Permission is hereby granted, free of charge, to any person
   5// obtaining a copy of this software and associated documentation
   6// files (the "Software"), to deal in the Software without
   7// restriction, including without limitation the rights to use,
   8// copy, modify, merge, publish, distribute, sublicense, and/or sell
   9// copies of the Software, and to permit persons to whom the
  10// Software is furnished to do so, subject to the following
  11// conditions:
  12//
  13// The above copyright notice and this permission notice shall be
  14// included in all copies or substantial portions of the Software.
  15//
  16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  18// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  20// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  21// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23// OTHER DEALINGS IN THE SOFTWARE.
  24#endregion
  25
  26using System.Globalization;
  27#if NET20
  28using Newtonsoft.Json.Utilities.LinqBridge;
  29#else
  30using System.Linq;
  31#endif
  32using System.Text;
  33#if !(DNXCORE50 || PORTABLE40)
  34using System;
  35using System.Collections.Generic;
  36using Newtonsoft.Json.Tests.Serialization;
  37using Newtonsoft.Json.Tests.TestObjects;
  38#if DNXCORE50
  39using Xunit;
  40using Test = Xunit.FactAttribute;
  41using Assert = Newtonsoft.Json.Tests.XUnitAssert;
  42#else
  43using NUnit.Framework;
  44#endif
  45using Newtonsoft.Json;
  46using System.IO;
  47using System.Xml;
  48using Newtonsoft.Json.Converters;
  49using Newtonsoft.Json.Utilities;
  50using Newtonsoft.Json.Linq;
  51#if !NET20
  52using System.Xml.Linq;
  53
  54#endif
  55
  56namespace Newtonsoft.Json.Tests.Converters
  57{
  58    [TestFixture]
  59    public class XmlNodeConverterTest : TestFixtureBase
  60    {
  61#if !PORTABLE
  62        private string SerializeXmlNode(XmlNode node)
  63        {
  64            string json = JsonConvert.SerializeXmlNode(node, Formatting.Indented);
  65            XmlNodeReader reader = new XmlNodeReader(node);
  66
  67#if !NET20
  68            XObject xNode;
  69            if (node is XmlDocument)
  70            {
  71                xNode = XDocument.Load(reader);
  72            }
  73            else if (node is XmlAttribute)
  74            {
  75                XmlAttribute attribute = (XmlAttribute)node;
  76                xNode = new XAttribute(XName.Get(attribute.LocalName, attribute.NamespaceURI), attribute.Value);
  77            }
  78            else
  79            {
  80                reader.MoveToContent();
  81                xNode = XNode.ReadFrom(reader);
  82            }
  83
  84            string linqJson = JsonConvert.SerializeXNode(xNode, Formatting.Indented);
  85
  86            Assert.AreEqual(json, linqJson);
  87#endif
  88
  89            return json;
  90        }
  91
  92        private XmlNode DeserializeXmlNode(string json)
  93        {
  94            return DeserializeXmlNode(json, null);
  95        }
  96
  97        private XmlNode DeserializeXmlNode(string json, string deserializeRootElementName)
  98        {
  99            JsonTextReader reader;
 100
 101            reader = new JsonTextReader(new StringReader(json));
 102            reader.Read();
 103            XmlNodeConverter converter = new XmlNodeConverter();
 104            if (deserializeRootElementName != null)
 105            {
 106                converter.DeserializeRootElementName = deserializeRootElementName;
 107            }
 108
 109            XmlNode node = (XmlNode)converter.ReadJson(reader, typeof(XmlDocument), null, new JsonSerializer());
 110
 111#if !NET20
 112            string xmlText = node.OuterXml;
 113
 114            reader = new JsonTextReader(new StringReader(json));
 115            reader.Read();
 116            XDocument d = (XDocument)converter.ReadJson(reader, typeof(XDocument), null, new JsonSerializer());
 117
 118            string linqXmlText = d.ToString(SaveOptions.DisableFormatting);
 119            if (d.Declaration != null)
 120            {
 121                linqXmlText = d.Declaration + linqXmlText;
 122            }
 123
 124            Assert.AreEqual(xmlText, linqXmlText);
 125#endif
 126
 127            return node;
 128        }
 129#endif
 130
 131        private string IndentXml(string xml)
 132        {
 133            XmlReader reader = XmlReader.Create(new StringReader(xml));
 134
 135            StringWriter sw = new StringWriter();
 136            XmlWriter writer = XmlWriter.Create(sw, new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true });
 137
 138            while (reader.Read())
 139            {
 140                writer.WriteNode(reader, false);
 141            }
 142
 143            writer.Flush();
 144
 145            return sw.ToString();
 146        }
 147
 148#if !NET20
 149        [Test]
 150        public void SerializeDollarProperty()
 151        {
 152            string json1 = @"{""$"":""test""}";
 153
 154            var doc = JsonConvert.DeserializeXNode(json1);
 155
 156            Assert.AreEqual(@"<_x0024_>test</_x0024_>", doc.ToString());
 157
 158            var json2 = JsonConvert.SerializeXNode(doc);
 159            
 160            Assert.AreEqual(json1, json2);
 161        }
 162
 163        [Test]
 164        public void SerializeNonKnownDollarProperty()
 165        {
 166            string json1 = @"{""$JELLY"":""test""}";
 167
 168            var doc = JsonConvert.DeserializeXNode(json1);
 169
 170            Console.WriteLine(doc.ToString());
 171
 172            Assert.AreEqual(@"<_x0024_JELLY>test</_x0024_JELLY>", doc.ToString());
 173
 174            var json2 = JsonConvert.SerializeXNode(doc);
 175
 176            Assert.AreEqual(json1, json2);
 177        }
 178
 179        public class MyModel
 180        {
 181            public string MyProperty { get; set; }
 182        }
 183
 184        [Test]
 185        public void ConvertNullString()
 186        {
 187            JObject json = new JObject();
 188            json["Prop1"] = (string)null;
 189            json["Prop2"] = new MyModel().MyProperty;
 190
 191            var xmlNodeConverter = new XmlNodeConverter { DeserializeRootElementName = "object" };
 192            var jsonSerializerSettings = new JsonSerializerSettings { Converters = new JsonConverter[] { xmlNodeConverter } };
 193            var jsonSerializer = JsonSerializer.CreateDefault(jsonSerializerSettings);
 194            XDocument d = json.ToObject<XDocument>(jsonSerializer);
 195
 196            StringAssert.Equals(@"<object>
 197  <Prop1 />
 198  <Prop2 />
 199</object>", d.ToString());
 200        }
 201
 202        public class Foo
 203        {
 204            public XElement Bar { get; set; }
 205        }
 206
 207        [Test]
 208        public void SerializeAndDeserializeXElement()
 209        {
 210            Foo foo = new Foo { Bar = null };
 211            string json = JsonConvert.SerializeObject(foo);
 212
 213            Assert.AreEqual(@"{""Bar"":null}", json);
 214            Foo foo2 = JsonConvert.DeserializeObject<Foo>(json);
 215
 216            Assert.IsNull(foo2.Bar);
 217        }
 218
 219        [Test]
 220        public void MultipleNamespacesXDocument()
 221        {
 222            string xml = @"<result xp_0:end=""2014-08-15 13:12:11.9184"" xp_0:start=""2014-08-15 13:11:49.3140"" xp_0:time_diff=""22604.3836"" xmlns:xp_0=""Test1"" p2:end=""2014-08-15 13:13:49.5522"" p2:start=""2014-08-15 13:13:49.0268"" p2:time_diff=""525.4646"" xmlns:p2=""Test2"" />";
 223
 224            XDocument d = XDocument.Parse(xml);
 225
 226            string json = JsonConvert.SerializeObject(d, Formatting.Indented);
 227
 228            StringAssert.AreEqual(@"{
 229  ""result"": {
 230    ""@xp_0:end"": ""2014-08-15 13:12:11.9184"",
 231    ""@xp_0:start"": ""2014-08-15 13:11:49.3140"",
 232    ""@xp_0:time_diff"": ""22604.3836"",
 233    ""@xmlns:xp_0"": ""Test1"",
 234    ""@p2:end"": ""2014-08-15 13:13:49.5522"",
 235    ""@p2:start"": ""2014-08-15 13:13:49.0268"",
 236    ""@p2:time_diff"": ""525.4646"",
 237    ""@xmlns:p2"": ""Test2""
 238  }
 239}", json);
 240
 241            XDocument doc = JsonConvert.DeserializeObject<XDocument>(json);
 242
 243            StringAssert.AreEqual(xml, doc.ToString());
 244        }
 245#endif
 246
 247#if !PORTABLE
 248        [Test]
 249        public void MultipleNamespacesXmlDocument()
 250        {
 251            string xml = @"<result xp_0:end=""2014-08-15 13:12:11.9184"" xp_0:start=""2014-08-15 13:11:49.3140"" xp_0:time_diff=""22604.3836"" xmlns:xp_0=""Test1"" p2:end=""2014-08-15 13:13:49.5522"" p2:start=""2014-08-15 13:13:49.0268"" p2:time_diff=""525.4646"" xmlns:p2=""Test2"" />";
 252
 253            XmlDocument d = new XmlDocument();
 254            d.LoadXml(xml);
 255
 256            string json = JsonConvert.SerializeObject(d, Formatting.Indented);
 257
 258            StringAssert.AreEqual(@"{
 259  ""result"": {
 260    ""@xp_0:end"": ""2014-08-15 13:12:11.9184"",
 261    ""@xp_0:start"": ""2014-08-15 13:11:49.3140"",
 262    ""@xp_0:time_diff"": ""22604.3836"",
 263    ""@xmlns:xp_0"": ""Test1"",
 264    ""@p2:end"": ""2014-08-15 13:13:49.5522"",
 265    ""@p2:start"": ""2014-08-15 13:13:49.0268"",
 266    ""@p2:time_diff"": ""525.4646"",
 267    ""@xmlns:p2"": ""Test2""
 268  }
 269}", json);
 270
 271            XmlDocument doc = JsonConvert.DeserializeObject<XmlDocument>(json);
 272
 273            StringAssert.AreEqual(xml, doc.OuterXml);
 274        }
 275
 276        [Test]
 277        public void SerializeXmlElement()
 278        {
 279            string xml = @"<payload>
 280    <Country>6</Country>
 281    <FinancialTransactionApprovalRequestUID>79</FinancialTransactionApprovalRequestUID>
 282    <TransactionStatus>Approved</TransactionStatus>
 283    <StatusChangeComment></StatusChangeComment>
 284    <RequestedBy>Someone</RequestedBy>
 285</payload>";
 286
 287            var xmlDocument = new XmlDocument();
 288
 289            xmlDocument.LoadXml(xml);
 290
 291            var result = xmlDocument.FirstChild.ChildNodes.Cast<XmlNode>().ToArray();
 292
 293            var json = JsonConvert.SerializeObject(result, Formatting.Indented); // <--- fails here with the cast message
 294
 295            StringAssert.AreEqual(@"[
 296  {
 297    ""Country"": ""6""
 298  },
 299  {
 300    ""FinancialTransactionApprovalRequestUID"": ""79""
 301  },
 302  {
 303    ""TransactionStatus"": ""Approved""
 304  },
 305  {
 306    ""StatusChangeComment"": """"
 307  },
 308  {
 309    ""RequestedBy"": ""Someone""
 310  }
 311]", json);
 312        }
 313#endif
 314
 315#if !NET20
 316        [Test]
 317        public void SerializeXElement()
 318        {
 319            string xml = @"<payload>
 320    <Country>6</Country>
 321    <FinancialTransactionApprovalRequestUID>79</FinancialTransactionApprovalRequestUID>
 322    <TransactionStatus>Approved</TransactionStatus>
 323    <StatusChangeComment></StatusChangeComment>
 324    <RequestedBy>Someone</RequestedBy>
 325</payload>";
 326
 327            var xmlDocument = XDocument.Parse(xml);
 328
 329            var result = xmlDocument.Root.Nodes().ToArray();
 330
 331            var json = JsonConvert.SerializeObject(result, Formatting.Indented); // <--- fails here with the cast message
 332
 333            StringAssert.AreEqual(@"[
 334  {
 335    ""Country"": ""6""
 336  },
 337  {
 338    ""FinancialTransactionApprovalRequestUID"": ""79""
 339  },
 340  {
 341    ""TransactionStatus"": ""Approved""
 342  },
 343  {
 344    ""StatusChangeComment"": """"
 345  },
 346  {
 347    ""RequestedBy"": ""Someone""
 348  }
 349]", json);
 350        }
 351
 352        public class DecimalContainer
 353        {
 354            public decimal Number { get; set; }
 355        }
 356
 357        [Test]
 358        public void FloatParseHandlingDecimal()
 359        {
 360            decimal d = (decimal)Math.PI + 1000000000m;
 361            var x = new DecimalContainer { Number = d };
 362
 363            var json = JsonConvert.SerializeObject(x, Formatting.Indented);
 364
 365            XDocument doc1 = JsonConvert.DeserializeObject<XDocument>(json, new JsonSerializerSettings
 366            {
 367                Converters = { new XmlNodeConverter() },
 368                FloatParseHandling = FloatParseHandling.Decimal
 369            });
 370
 371            var xml = doc1.ToString();
 372            Assert.AreEqual("<Number>1000000003.14159265358979</Number>", xml);
 373
 374            string json2 = JsonConvert.SerializeObject(doc1, Formatting.Indented);
 375
 376            DecimalContainer x2 = JsonConvert.DeserializeObject<DecimalContainer>(json2);
 377
 378            Assert.AreEqual(x.Number, x2.Number);
 379        }
 380
 381        public class DateTimeOffsetContainer
 382        {
 383            public DateTimeOffset Date { get; set; }
 384        }
 385
 386        [Test]
 387        public void DateTimeParseHandlingOffset()
 388        {
 389            DateTimeOffset d = new DateTimeOffset(2012, 12, 12, 12, 44, 1, TimeSpan.FromHours(12).Add(TimeSpan.FromMinutes(34)));
 390            var x = new DateTimeOffsetContainer { Date = d };
 391
 392            var json = JsonConvert.SerializeObject(x, Formatting.Indented);
 393
 394            XDocument doc1 = JsonConvert.DeserializeObject<XDocument>(json, new JsonSerializerSettings
 395            {
 396                Converters = { new XmlNodeConverter() },
 397                DateParseHandling = DateParseHandling.DateTimeOffset
 398            });
 399
 400            var xml = doc1.ToString();
 401            Assert.AreEqual("<Date>2012-12-12T12:44:01+12:34</Date>", xml);
 402
 403            string json2 = JsonConvert.SerializeObject(doc1, Formatting.Indented);
 404
 405            DateTimeOffsetContainer x2 = JsonConvert.DeserializeObject<DateTimeOffsetContainer>(json2);
 406
 407            Assert.AreEqual(x.Date, x2.Date);
 408        }
 409
 410        [Test]
 411        public void GroupElementsOfTheSameName()
 412        {
 413            string xml = "<root><p>Text1<span>Span1</span> <span>Span2</span> Text2</p></root>";
 414
 415            string json = JsonConvert.SerializeXNode(XElement.Parse(xml));
 416
 417            Assert.AreEqual(@"{""root"":{""p"":{""#text"":[""Text1"","" Text2""],""span"":[""Span1"",""Span2""]}}}", json);
 418
 419            XDocument doc = JsonConvert.DeserializeXNode(json);
 420
 421            StringAssert.AreEqual(@"<root>
 422  <p>Text1 Text2<span>Span1</span><span>Span2</span></p>
 423</root>", doc.ToString());
 424        }
 425
 426#if !PORTABLE
 427        [Test]
 428        public void SerializeEmptyDocument()
 429        {
 430            XmlDocument doc = new XmlDocument();
 431            doc.LoadXml("<root />");
 432
 433            string json = JsonConvert.SerializeXmlNode(doc, Formatting.Indented, true);
 434            Assert.AreEqual("null", json);
 435
 436            doc = new XmlDocument();
 437            doc.LoadXml("<root></root>");
 438
 439            json = JsonConvert.SerializeXmlNode(doc, Formatting.Indented, true);
 440            Assert.AreEqual(@"""""", json);
 441
 442            XDocument doc1 = XDocument.Parse("<root />");
 443
 444            json = JsonConvert.SerializeXNode(doc1, Formatting.Indented, true);
 445            Assert.AreEqual("null", json);
 446
 447            doc1 = XDocument.Parse("<root></root>");
 448
 449            json = JsonConvert.SerializeXNode(doc1, Formatting.Indented, true);
 450            Assert.AreEqual(@"""""", json);
 451        }
 452#endif
 453
 454        [Test]
 455        public void SerializeAndDeserializeXmlWithNamespaceInChildrenAndNoValueInChildren()
 456        {
 457            var xmlString = @"<root>
 458                              <b xmlns='http://www.example.com/ns'/>
 459                              <c>AAA</c>
 460                              <test>adad</test>
 461                              </root>";
 462
 463            var xml = XElement.Parse(xmlString);
 464
 465            var json1 = JsonConvert.SerializeXNode(xml);
 466            var xmlBack = JsonConvert.DeserializeObject<XElement>(json1);
 467
 468            var equals = XElement.DeepEquals(xmlBack, xml);
 469            Assert.IsTrue(equals);
 470        }
 471
 472#if !PORTABLE
 473        [Test]
 474        public void DeserializeUndeclaredNamespacePrefix()
 475        {
 476            XmlDocument doc = JsonConvert.DeserializeXmlNode("{ A: { '@xsi:nil': true } }");
 477
 478            Assert.AreEqual(@"<A nil=""true"" />", doc.OuterXml);
 479
 480            XDocument xdoc = JsonConvert.DeserializeXNode("{ A: { '@xsi:nil': true } }");
 481
 482            Assert.AreEqual(doc.OuterXml, xdoc.ToString());
 483        }
 484#endif
 485#endif
 486
 487#if !PORTABLE
 488        [Test]
 489        public void DeserializeMultipleRootElements()
 490        {
 491            string json = @"{
 492    ""Id"": 1,
 493     ""Email"": ""james@example.com"",
 494     ""Active"": true,
 495     ""CreatedDate"": ""2013-01-20T00:00:00Z"",
 496     ""Roles"": [
 497       ""User"",
 498       ""Admin""
 499     ],
 500    ""Team"": {
 501        ""Id"": 2,
 502        ""Name"": ""Software Developers"",
 503        ""Description"": ""Creators of fine software products and services.""
 504    }
 505}";
 506            ExceptionAssert.Throws<JsonSerializationException>(
 507                () => { JsonConvert.DeserializeXmlNode(json); },
 508                "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifying a DeserializeRootElementName. Path 'Email', line 3, position 13.");
 509        }
 510
 511        [Test]
 512        public void DocumentSerializeIndented()
 513        {
 514            string xml = @"<?xml version=""1.0"" standalone=""no""?>
 515<?xml-stylesheet href=""classic.xsl"" type=""text/xml""?>
 516<span class=""vevent"">
 517  <a class=""url"" href=""http://www.web2con.com/"">
 518    <span class=""summary"">Web 2.0 Conference<![CDATA[my escaped text]]></span>
 519    <abbr class=""dtstart"" title=""2005-10-05"">October 5</abbr>
 520    <abbr class=""dtend"" title=""2005-10-08"">7</abbr>
 521    <span class=""location"">Argent Hotel, San Francisco, CA</span>
 522  </a>
 523</span>";
 524            XmlDocument doc = new XmlDocument();
 525            doc.LoadXml(xml);
 526
 527            string jsonText = SerializeXmlNode(doc);
 528            string expected = @"{
 529  ""?xml"": {
 530    ""@version"": ""1.0"",
 531    ""@standalone"": ""no""
 532  },
 533  ""?xml-stylesheet"": ""href=\""classic.xsl\"" type=\""text/xml\"""",
 534  ""span"": {
 535    ""@class"": ""vevent"",
 536    ""a"": {
 537      ""@class"": ""url"",
 538      ""@href"": ""http://www.web2con.com/"",
 539      ""span"": [
 540        {
 541          ""@class"": ""summary"",
 542          ""#text"": ""Web 2.0 Conference"",
 543          ""#cdata-section"": ""my escaped text""
 544        },
 545        {
 546          ""@class"": ""location"",
 547          ""#text"": ""Argent Hotel, San Francisco, CA""
 548        }
 549      ],
 550      ""abbr"": [
 551        {
 552          ""@class"": ""dtstart"",
 553          ""@title"": ""2005-10-05"",
 554          ""#text"": ""October 5""
 555        },
 556        {
 557          ""@class"": ""dtend"",
 558          ""@title"": ""2005-10-08"",
 559          ""#text"": ""7""
 560        }
 561      ]
 562    }
 563  }
 564}";
 565
 566            StringAssert.AreEqual(expected, jsonText);
 567        }
 568
 569        [Test]
 570        public void SerializeNodeTypes()
 571        {
 572            XmlDocument doc = new XmlDocument();
 573            string jsonText;
 574
 575            string xml = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
 576<xs:schema xs:id=""SomeID"" 
 577	xmlns="""" 
 578	xmlns:xs=""http://www.w3.org/2001/XMLSchema"" 
 579	xmlns:msdata=""urn:schemas-microsoft-com:xml-msdata"">
 580	<xs:element name=""MyDataSet"" msdata:IsDataSet=""true"">
 581	</xs:element>
 582</xs:schema>";
 583
 584            XmlDocument document = new XmlDocument();
 585            document.LoadXml(xml);
 586
 587            // XmlAttribute
 588            XmlAttribute attribute = document.DocumentElement.ChildNodes[0].Attributes["IsDataSet", "urn:schemas-microsoft-com:xml-msdata"];
 589            attribute.Value = "true";
 590
 591            jsonText = JsonConvert.SerializeXmlNode(attribute);
 592
 593            Assert.AreEqual(@"{""@msdata:IsDataSet"":""true""}", jsonText);
 594
 595#if !NET20
 596            XDocument d = XDocument.Parse(xml);
 597            XAttribute a = d.Root.Element("{http://www.w3.org/2001/XMLSchema}element").Attribute("{urn:schemas-microsoft-com:xml-msdata}IsDataSet");
 598
 599            jsonText = JsonConvert.SerializeXNode(a);
 600
 601            Assert.AreEqual(@"{""@msdata:IsDataSet"":""true""}", jsonText);
 602#endif
 603
 604            // XmlProcessingInstruction
 605            XmlProcessingInstruction instruction = doc.CreateProcessingInstruction("xml-stylesheet", @"href=""classic.xsl"" type=""text/xml""");
 606
 607            jsonText = JsonConvert.SerializeXmlNode(instruction);
 608
 609            Assert.AreEqual(@"{""?xml-stylesheet"":""href=\""classic.xsl\"" type=\""text/xml\""""}", jsonText);
 610
 611            // XmlProcessingInstruction
 612            XmlCDataSection cDataSection = doc.CreateCDataSection("<Kiwi>true</Kiwi>");
 613
 614            jsonText = JsonConvert.SerializeXmlNode(cDataSection);
 615
 616            Assert.AreEqual(@"{""#cdata-section"":""<Kiwi>true</Kiwi>""}", jsonText);
 617
 618            // XmlElement
 619            XmlElement element = doc.CreateElement("xs", "Choice", "http://www.w3.org/2001/XMLSchema");
 620            element.SetAttributeNode(doc.CreateAttribute("msdata", "IsDataSet", "urn:schemas-microsoft-com:xml-msdata"));
 621
 622            XmlAttribute aa = doc.CreateAttribute(@"xmlns", "xs", "http://www.w3.org/2000/xmlns/");
 623            aa.Value = "http://www.w3.org/2001/XMLSchema";
 624            element.SetAttributeNode(aa);
 625
 626            aa = doc.CreateAttribute(@"xmlns", "msdata", "http://www.w3.org/2000/xmlns/");
 627            aa.Value = "urn:schemas-microsoft-com:xml-msdata";
 628            element.SetAttributeNode(aa);
 629
 630            element.AppendChild(instruction);
 631            element.AppendChild(cDataSection);
 632
 633            doc.AppendChild(element);
 634
 635            jsonText = JsonConvert.SerializeXmlNode(element, Formatting.Indented);
 636
 637            StringAssert.AreEqual(@"{
 638  ""xs:Choice"": {
 639    ""@msdata:IsDataSet"": """",
 640    ""@xmlns:xs"": ""http://www.w3.org/2001/XMLSchema"",
 641    ""@xmlns:msdata"": ""urn:schemas-microsoft-com:xml-msdata"",
 642    ""?xml-stylesheet"": ""href=\""classic.xsl\"" type=\""text/xml\"""",
 643    ""#cdata-section"": ""<Kiwi>true</Kiwi>""
 644  }
 645}", jsonText);
 646        }
 647
 648        [Test]
 649        public void SerializeNodeTypes_Encoding()
 650        {
 651            XmlNode node = DeserializeXmlNode(@"{
 652  ""xs!:Choice!"": {
 653    ""@msdata:IsDataSet!"": """",
 654    ""@xmlns:xs!"": ""http://www.w3.org/2001/XMLSchema"",
 655    ""@xmlns:msdata"": ""urn:schemas-microsoft-com:xml-msdata"",
 656    ""?xml-stylesheet"": ""href=\""classic.xsl\"" type=\""text/xml\"""",
 657    ""#cdata-section"": ""<Kiwi>true</Kiwi>""
 658  }
 659}");
 660
 661            Assert.AreEqual(@"<xs_x0021_:Choice_x0021_ msdata:IsDataSet_x0021_="""" xmlns:xs_x0021_=""http://www.w3.org/2001/XMLSchema"" xmlns:msdata=""urn:schemas-microsoft-com:xml-msdata""><?xml-stylesheet href=""classic.xsl"" type=""text/xml""?><![CDATA[<Kiwi>true</Kiwi>]]></xs_x0021_:Choice_x0021_>", node.InnerXml);
 662
 663            string json = SerializeXmlNode(node);
 664
 665            StringAssert.AreEqual(@"{
 666  ""xs!:Choice!"": {
 667    ""@msdata:IsDataSet!"": """",
 668    ""@xmlns:xs!"": ""http://www.w3.org/2001/XMLSchema"",
 669    ""@xmlns:msdata"": ""urn:schemas-microsoft-com:xml-msdata"",
 670    ""?xml-stylesheet"": ""href=\""classic.xsl\"" type=\""text/xml\"""",
 671    ""#cdata-section"": ""<Kiwi>true</Kiwi>""
 672  }
 673}", json);
 674        }
 675
 676        [Test]
 677        public void DocumentFragmentSerialize()
 678        {
 679            XmlDocument doc = new XmlDocument();
 680
 681            XmlDocumentFragment fragement = doc.CreateDocumentFragment();
 682
 683            fragement.InnerXml = "<Item>widget</Item><Item>widget</Item>";
 684
 685            string jsonText = JsonConvert.SerializeXmlNode(fragement);
 686
 687            string expected = @"{""Item"":[""widget"",""widget""]}";
 688
 689            Assert.AreEqual(expected, jsonText);
 690        }
 691
 692        [Test]
 693        public void XmlDocumentTypeSerialize()
 694        {
 695            string xml = @"<?xml version=""1.0"" encoding=""utf-8""?><!DOCTYPE STOCKQUOTE PUBLIC ""-//W3C//DTD StockQuote 1.5//EN"" ""http://www.idontexistnopenopewhatnope123.org/dtd/stockquote_1.5.dtd""><STOCKQUOTE ROWCOUNT=""2""><RESULT><ROW><ASK>0</ASK><BID>0</BID><CHANGE>-16.310</CHANGE><COMPANYNAME>Dow Jones</COMPANYNAME><DATETIME>2014-04-17 15:50:37</DATETIME><DIVIDEND>0</DIVIDEND><EPS>0</EPS><EXCHANGE></EXCHANGE><HIGH>16460.490</HIGH><LASTDATETIME>2014-04-17 15:50:37</LASTDATETIME><LASTPRICE>16408.540</LASTPRICE><LOW>16368.140</LOW><OPEN>16424.140</OPEN><PCHANGE>-0.099</PCHANGE><PE>0</PE><PREVIOUSCLOSE>16424.850</PREVIOUSCLOSE><SHARES>0</SHARES><TICKER>DJII</TICKER><TRADES>0</TRADES><VOLUME>136188700</VOLUME><YEARHIGH>11309.000</YEARHIGH><YEARLOW>9302.280</YEARLOW><YIELD>0</YIELD></ROW><ROW><ASK>0</ASK><BID>0</BID><CHANGE>9.290</CHANGE><COMPANYNAME>NASDAQ</COMPANYNAME><DATETIME>2014-04-17 15:40:01</DATETIME><DIVIDEND>0</DIVIDEND><EPS>0</EPS><EXCHANGE></EXCHANGE><HIGH>4110.460</HIGH><LASTDATETIME>2014-04-17 15:40:01</LASTDATETIME><LASTPRICE>4095.520</LASTPRICE><LOW>4064.700</LOW><OPEN>4080.300</OPEN><PCHANGE>0.227</PCHANGE><PE>0</PE><PREVIOUSCLOSE>4086.230</PREVIOUSCLOSE><SHARES>0</SHARES><TICKER>COMP</TICKER><TRADES>0</TRADES><VOLUME>1784210100</VOLUME><YEARHIGH>4371.710</YEARHIGH><YEARLOW>3154.960</YEARLOW><YIELD>0</YIELD></ROW></RESULT><STATUS>Couldn't find ticker: SPIC?</STATUS><STATUSCODE>2</STATUSCODE></STOCKQUOTE>";
 696
 697            string expected = @"{
 698  ""?xml"": {
 699    ""@version"": ""1.0"",
 700    ""@encoding"": ""utf-8""
 701  },
 702  ""!DOCTYPE"": {
 703    ""@name"": ""STOCKQUOTE"",
 704    ""@public"": ""-//W3C//DTD StockQuote 1.5//EN"",
 705    ""@system"": ""http://www.idontexistnopenopewhatnope123.org/dtd/stockquote_1.5.dtd""
 706  },
 707  ""STOCKQUOTE"": {
 708    ""@ROWCOUNT"": ""2"",
 709    ""RESULT"": {
 710      ""ROW"": [
 711        {
 712          ""ASK"": ""0"",
 713          ""BID"": ""0"",
 714          ""CHANGE"": ""-16.310"",
 715          ""COMPANYNAME"": ""Dow Jones"",
 716          ""DATETIME"": ""2014-04-17 15:50:37"",
 717          ""DIVIDEND"": ""0"",
 718          ""EPS"": ""0"",
 719          ""EXCHANGE"": """",
 720          ""HIGH"": ""16460.490"",
 721          ""LASTDATETIME"": ""2014-04-17 15:50:37"",
 722          ""LASTPRICE"": ""16408.540"",
 723          ""LOW"": ""16368.140"",
 724          ""OPEN"": ""16424.140"",
 725          ""PCHANGE"": ""-0.099"",
 726          ""PE"": ""0"",
 727          ""PREVIOUSCLOSE"": ""16424.850"",
 728          ""SHARES"": ""0"",
 729          ""TICKER"": ""DJII"",
 730          ""TRADES"": ""0"",
 731          ""VOLUME"": ""136188700"",
 732          ""YEARHIGH"": ""11309.000"",
 733          ""YEARLOW"": ""9302.280"",
 734          ""YIELD"": ""0""
 735        },
 736        {
 737          ""ASK"": ""0"",
 738          ""BID"": ""0"",
 739          ""CHANGE"": ""9.290"",
 740          ""COMPANYNAME"": ""NASDAQ"",
 741          ""DATETIME"": ""2014-04-17 15:40:01"",
 742          ""DIVIDEND"": ""0"",
 743          ""EPS"": ""0"",
 744          ""EXCHANGE"": """",
 745          ""HIGH"": ""4110.460"",
 746          ""LASTDATETIME"": ""2014-04-17 15:40:01"",
 747          ""LASTPRICE"": ""4095.520"",
 748          ""LOW"": ""4064.700"",
 749          ""OPEN"": ""4080.300"",
 750          ""PCHANGE"": ""0.227"",
 751          ""PE"": ""0"",
 752          ""PREVIOUSCLOSE"": ""4086.230"",
 753          ""SHARES"": ""0"",
 754          ""TICKER"": ""COMP"",
 755          ""TRADES"": ""0"",
 756          ""VOLUME"": ""1784210100"",
 757          ""YEARHIGH"": ""4371.710"",
 758          ""YEARLOW"": ""3154.960"",
 759          ""YIELD"": ""0""
 760        }
 761      ]
 762    },
 763    ""STATUS"": ""Couldn't find ticker: SPIC?"",
 764    ""STATUSCODE"": ""2""
 765  }
 766}";
 767
 768            XmlDocument doc1 = new XmlDocument();
 769            doc1.XmlResolver = null;
 770            doc1.LoadXml(xml);
 771
 772            string json1 = JsonConvert.SerializeXmlNode(doc1, Formatting.Indented);
 773
 774            StringAssert.AreEqual(expected, json1);
 775
 776            XmlDocument doc11 = JsonConvert.DeserializeXmlNode(json1);
 777
 778            StringAssert.AreEqual(xml, ToStringWithDeclaration(doc11));
 779
 780#if !NET20
 781            XDocument doc2 = XDocument.Parse(xml);
 782
 783            string json2 = JsonConvert.SerializeXNode(doc2, Formatting.Indented);
 784
 785            StringAssert.AreEqual(expected, json2);
 786
 787            XDocument doc22 = JsonConvert.DeserializeXNode(json2);
 788
 789            StringAssert.AreEqual(xml, ToStringWithDeclaration(doc22));
 790#endif
 791        }
 792
 793        public class Utf8StringWriter : StringWriter
 794        {
 795            public override Encoding Encoding
 796            {
 797                get { return Encoding.UTF8; }
 798            }
 799
 800            public Utf8StringWriter(StringBuilder sb) : base(sb)
 801            {
 802            }
 803        }
 804
 805#if !NET20
 806        public static string ToStringWithDeclaration(XDocument doc, bool indent = false)
 807        {
 808            StringBuilder builder = new StringBuilder();
 809            using (var writer = XmlWriter.Create(new Utf8StringWriter(builder), new XmlWriterSettings { Indent = indent }))
 810            {
 811                doc.Save(writer);
 812            }
 813            return builder.ToString();
 814        }
 815#endif
 816
 817        public static string ToStringWithDeclaration(XmlDocument doc, bool indent = false)
 818        {
 819            StringBuilder builder = new StringBuilder();
 820            using (var writer = XmlWriter.Create(new Utf8StringWriter(builder), new XmlWriterSettings { Indent = indent }))
 821            {
 822                doc.Save(writer);
 823            }
 824            return builder.ToString();
 825        }
 826
 827        [Test]
 828        public void NamespaceSerializeDeserialize()
 829        {
 830            string xml = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
 831<xs:schema xs:id=""SomeID"" 
 832	xmlns="""" 
 833	xmlns:xs=""http://www.w3.org/2001/XMLSchema"" 
 834	xmlns:msdata=""urn:schemas-microsoft-com:xml-msdata"">
 835	<xs:element name=""MyDataSet"" msdata:IsDataSet=""true"">
 836		<xs:complexType>
 837			<xs:choice maxOccurs=""unbounded"">
 838				<xs:element name=""customers"" >
 839					<xs:complexType >
 840						<xs:sequence>
 841							<xs:element name=""CustomerID"" type=""xs:integer"" 
 842										 minOccurs=""0"" />
 843							<xs:element name=""CompanyName"" type=""xs:string"" 
 844										 minOccurs=""0"" />
 845							<xs:element name=""Phone"" type=""xs:string"" />
 846						</xs:sequence>
 847					</xs:complexType>
 848				</xs:element>
 849			</xs:choice>
 850		</xs:complexType>
 851	</xs:element>
 852</xs:schema>";
 853
 854            XmlDocument doc = new XmlDocument();
 855            doc.LoadXml(xml);
 856
 857            string jsonText = SerializeXmlNode(doc);
 858
 859            string expected = @"{
 860  ""?xml"": {
 861    ""@version"": ""1.0"",
 862    ""@encoding"": ""utf-8""
 863  },
 864  ""xs:schema"": {
 865    ""@xs:id"": ""SomeID"",
 866    ""@xmlns"": """",
 867    ""@xmlns:xs"": ""http://www.w3.org/2001/XMLSchema"",
 868    ""@xmlns:msdata"": ""urn:schemas-microsoft-com:xml-msdata"",
 869    ""xs:element"": {
 870      ""@name"": ""MyDataSet"",
 871      ""@msdata:IsDataSet"": ""true"",
 872      ""xs:complexType"": {
 873        ""xs:choice"": {
 874          ""@maxOccurs"": ""unbounded"",
 875          ""xs:element"": {
 876            ""@name"": ""customers"",
 877            ""xs:complexType"": {
 878              ""xs:sequence"": {
 879                ""xs:element"": [
 880                  {
 881                    ""@name"": ""CustomerID"",
 882                    ""@type"": ""xs:integer"",
 883                    ""@minOccurs"": ""0""
 884                  },
 885                  {
 886                    ""@name"": ""CompanyName"",
 887                    ""@type"": ""xs:string"",
 888                    ""@minOccurs"": ""0""
 889                  },
 890                  {
 891                    ""@name"": ""Phone"",
 892                    ""@type"": ""xs:string""
 893                  }
 894                ]
 895              }
 896            }
 897          }
 898        }
 899      }
 900    }
 901  }
 902}";
 903
 904            StringAssert.AreEqual(expected, jsonText);
 905
 906            XmlDocument deserializedDoc = (XmlDocument)DeserializeXmlNode(jsonText);
 907
 908            Assert.AreEqual(doc.InnerXml, deserializedDoc.InnerXml);
 909        }
 910
 911        [Test]
 912        public void DocumentDeserialize()
 913        {
 914            string jsonText = @"{
 915  ""?xml"": {
 916    ""@version"": ""1.0"",
 917    ""@standalone"": ""no""
 918  },
 919  ""span"": {
 920    ""@class"": ""vevent"",
 921    ""a"": {
 922      ""@class"": ""url"",
 923      ""span"": {
 924        ""@class"": ""summary"",
 925        ""#text"": ""Web 2.0 Conference"",
 926        ""#cdata-section"": ""my escaped text""
 927      },
 928      ""@href"": ""http://www.web2con.com/""
 929    }
 930  }
 931}";
 932
 933            XmlDocument doc = (XmlDocument)DeserializeXmlNode(jsonText);
 934
 935            string expected = @"<?xml version=""1.0"" standalone=""no""?>
 936<span class=""vevent"">
 937  <a class=""url"" href=""http://www.web2con.com/"">
 938    <span class=""summary"">Web 2.0 Conference<![CDATA[my escaped text]]></span>
 939  </a>
 940</span>";
 941
 942            string formattedXml = GetIndentedInnerXml(doc);
 943
 944            StringAssert.AreEqual(expected, formattedXml);
 945        }
 946
 947        private string GetIndentedInnerXml(XmlNode node)
 948        {
 949            XmlWriterSettings settings = new XmlWriterSettings();
 950            settings.Indent = true;
 951
 952            StringWriter sw = new StringWriter();
 953
 954            using (XmlWriter writer = XmlWriter.Create(sw, settings))
 955            {
 956                node.WriteTo(writer);
 957            }
 958
 959            return sw.ToString();
 960        }
 961
 962        [Test]
 963        public void SingleTextNode()
 964        {
 965            string xml = @"<?xml version=""1.0"" standalone=""no""?>
 966			<root>
 967			  <person id=""1"">
 968	  			<name>Alan</name>
 969		  		<url>http://www.google.com</url>
 970			  </person>
 971			  <person id=""2"">
 972			  	<name>Louis</name>
 973				  <url>http://www.yahoo.com</url>
 974			  </person>
 975			</root>";
 976
 977            XmlDocument doc = new XmlDocument();
 978            doc.LoadXml(xml);
 979
 980            string jsonText = SerializeXmlNode(doc);
 981
 982            XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
 983
 984            Assert.AreEqual(doc.InnerXml, newDoc.InnerXml);
 985        }
 986
 987        [Test]
 988        public void EmptyNode()
 989        {
 990            string xml = @"<?xml version=""1.0"" standalone=""no""?>
 991			<root>
 992			  <person id=""1"">
 993				<name>Alan</name>
 994				<url />
 995			  </person>
 996			  <person id=""2"">
 997				<name>Louis</name>
 998				<url>http://www.yahoo.com</url>
 999			  </person>
1000			</root>";
1001
1002            XmlDocument doc = new XmlDocument();
1003            doc.LoadXml(xml);
1004
1005            string jsonText = SerializeXmlNode(doc);
1006
1007            StringAssert.AreEqual(@"{
1008  ""?xml"": {
1009    ""@version"": ""1.0"",
1010    ""@standalone"": ""no""
1011  },
1012  ""root"": {
1013    ""person"": [
1014      {
1015        ""@id"": ""1"",
1016        ""name"": ""Alan"",
1017        ""url"": null
1018      },
1019      {
1020        ""@id"": ""2"",
1021        ""name"": ""Louis"",
1022        ""url"": ""http://www.yahoo.com""
1023      }
1024    ]
1025  }
1026}", jsonText);
1027
1028            XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
1029
1030            Assert.AreEqual(doc.InnerXml, newDoc.InnerXml);
1031        }
1032
1033        [Test]
1034        public void OtherElementDataTypes()
1035        {
1036            string jsonText = @"{""?xml"":{""@version"":""1.0"",""@standalone"":""no""},""root"":{""person"":[{""@id"":""1"",""Float"":2.5,""Integer"":99},{""Boolean"":true,""@id"":""2"",""date"":""\/Date(954374400000)\/""}]}}";
1037
1038            XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
1039
1040            string expected = @"<?xml version=""1.0"" standalone=""no""?><root><person id=""1""><Float>2.5</Float><Integer>99</Integer></person><person id=""2""><Boolean>true</Boolean><date>2000-03-30T00:00:00Z</date></person></root>";
1041
1042            Assert.AreEqual(expected, newDoc.InnerXml);
1043        }
1044
1045        [Test]
1046        public void NoRootObject()
1047        {
1048            ExceptionAssert.Throws<JsonSerializationException>(() => { XmlDocument newDoc = (XmlDocument)JsonConvert.DeserializeXmlNode(@"[1]"); }, "XmlNodeConverter can only convert JSON that begins with an object.");
1049        }
1050
1051        [Test]
1052        public void RootObjectMultipleProperties()
1053        {
1054            ExceptionAssert.Throws<JsonSerializationException>(
1055                () => { XmlDocument newDoc = (XmlDocument)JsonConvert.DeserializeXmlNode(@"{Prop1:1,Prop2:2}"); },
1056                "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifying a DeserializeRootElementName. Path 'Prop2', line 1, position 15.");
1057        }
1058
1059        [Test]
1060        public void JavaScriptConstructor()
1061        {
1062            string jsonText = @"{root:{r:new Date(34343, 55)}}";
1063
1064            XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
1065
1066            string expected = @"<root><r><Date>34343</Date><Date>55</Date></r></root>";
1067
1068            Assert.AreEqual(expected, newDoc.InnerXml);
1069
1070            string json = SerializeXmlNode(newDoc);
1071            expected = @"{
1072  ""root"": {
1073    ""r"": {
1074      ""Date"": [
1075        ""34343"",
1076        ""55""
1077      ]
1078    }
1079  }
1080}";
1081
1082            StringAssert.AreEqual(expected, json);
1083        }
1084
1085        [Test]
1086        public void ForceJsonArray()
1087        {
1088            string arrayXml = @"<root xmlns:json=""http://james.newtonking.com/projects/json"">
1089			  <person id=""1"">
1090				  <name>Alan</name>
1091				  <url>http://www.google.com</url>
1092				  <role json:Array=""true"">Admin</role>
1093			  </person>
1094			</root>";
1095
1096            XmlDocument arrayDoc = new XmlDocument();
1097            arrayDoc.LoadXml(arrayXml);
1098
1099            string arrayJsonText = SerializeXmlNode(arrayDoc);
1100            string expected = @"{
1101  ""root"": {
1102    ""person"": {
1103      ""@id"": ""1"",
1104      ""name"": ""Alan"",
1105      ""url"": ""http://www.google.com"",
1106      ""role"": [
1107        ""Admin""
1108      ]
1109    }
1110  }
1111}";
1112            StringAssert.AreEqual(expected, arrayJsonText);
1113
1114            arrayXml = @"<root xmlns:json=""http://james.newtonking.com/projects/json"">
1115			  <person id=""1"">
1116				  <name>Alan</name>
1117				  <url>http://www.google.com</url>
1118				  <role json:Array=""true"">Admin1</role>
1119				  <role json:Array=""true"">Admin2</role>
1120			  </person>
1121			</root>";
1122
1123            arrayDoc = new XmlDocument();
1124            arrayDoc.LoadXml(arrayXml);
1125
1126            arrayJsonText = SerializeXmlNode(arrayDoc);
1127            expected = @"{
1128  ""root"": {
1129    ""person"": {
1130      ""@id"": ""1"",
1131      ""name"": ""Alan"",
1132      ""url"": ""http://www.google.com"",
1133      ""role"": [
1134        ""Admin1"",
1135        ""Admin2""
1136      ]
1137    }
1138  }
1139}";
1140            StringAssert.AreEqual(expected, arrayJsonText);
1141
1142            arrayXml = @"<root xmlns:json=""http://james.newtonking.com/projects/json"">
1143			  <person id=""1"">
1144				  <name>Alan</name>
1145				  <url>http://www.google.com</url>
1146				  <role json:Array=""false"">Admin1</role>
1147			  </person>
1148			</root>";
1149
1150            arrayDoc = new XmlDocument();
1151            arrayDoc.LoadXml(arrayXml);
1152
1153            arrayJsonText = SerializeXmlNode(arrayDoc);
1154            expected = @"{
1155  ""root"": {
1156    ""person"": {
1157      ""@id"": ""1"",
1158      ""name"": ""Alan"",
1159      ""url"": ""http://www.google.com"",
1160      ""role"": ""Admin1""
1161    }
1162  }
1163}";
1164            StringAssert.AreEqual(expected, arrayJsonText);
1165
1166            arrayXml = @"<root>
1167			  <person id=""1"">
1168				  <name>Alan</name>
1169				  <url>http://www.google.com</url>
1170				  <role json:Array=""true"" xmlns:json=""http://james.newtonking.com/projects/json"">Admin</role>
1171			  </person>
1172			</root>";
1173
1174            arrayDoc = new XmlDocument();
1175            arrayDoc.LoadXml(arrayXml);
1176
1177            arrayJsonText = SerializeXmlNode(arrayDoc);
1178            expected = @"{
1179  ""root"": {
1180    ""person"": {
1181      ""@id"": ""1"",
1182      ""name"": ""Alan"",
1183      ""url"": ""http://www.google.com"",
1184      ""role"": [
1185        ""Admin""
1186      ]
1187    }
1188  }
1189}";
1190            StringAssert.AreEqual(expected, arrayJsonText);
1191        }
1192
1193        [Test]
1194        public void MultipleRootPropertiesXmlDocument()
1195        {
1196            string json = @"{""count"": 773840,""photos"": null}";
1197
1198            ExceptionAssert.Throws<JsonSerializationException>(
1199                () => { JsonConvert.DeserializeXmlNode(json); },
1200                "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifying a DeserializeRootElementName. Path 'photos', line 1, position 26.");
1201        }
1202#endif
1203
1204#if !NET20
1205        [Test]
1206        public void MultipleRootPropertiesXDocument()
1207        {
1208            string json = @"{""count"": 773840,""photos"": null}";
1209
1210            ExceptionAssert.Throws<JsonSerializationException>(
1211                () => { JsonConvert.DeserializeXNode(json); },
1212                "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifying a DeserializeRootElementName. Path 'photos', line 1, position 26.");
1213        }
1214#endif
1215
1216        [Test]
1217        public void MultipleRootPropertiesAddRootElement()
1218        {
1219            string json = @"{""count"": 773840,""photos"": 773840}";
1220
1221#if !PORTABLE
1222            XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot");
1223
1224            Assert.AreEqual(@"<myRoot><count>773840</count><photos>773840</photos></myRoot>", newDoc.InnerXml);
1225#endif
1226
1227#if !NET20
1228            XDocument newXDoc = JsonConvert.DeserializeXNode(json, "myRoot");
1229
1230            Assert.AreEqual(@"<myRoot><count>773840</count><photos>773840</photos></myRoot>", newXDoc.ToString(SaveOptions.DisableFormatting));
1231#endif
1232        }
1233
1234        [Test]
1235        public void NestedArrays()
1236        {
1237            string json = @"{
1238  ""available_sizes"": [
1239    [
1240      ""assets/images/resized/0001/1070/11070v1-max-150x150.jpg"",
1241      ""assets/images/resized/0001/1070/11070v1-max-150x150.jpg""
1242    ],
1243    [
1244      ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg"",
1245      ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
1246    ],
1247    [
1248      ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
1249    ]
1250  ]
1251}";
1252
1253 #if !PORTABLE
1254           XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot");
1255
1256            string xml = IndentXml(newDoc.InnerXml);
1257
1258            StringAssert.AreEqual(@"<myRoot>
1259  <available_sizes>
1260    <available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes>
1261    <available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes>
1262  </available_sizes>
1263  <available_sizes>
1264    <available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
1265    <available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
1266  </available_sizes>
1267  <available_sizes>
1268    <available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
1269  </available_sizes>
1270</myRoot>", IndentXml(newDoc.InnerXml));
1271#endif
1272
1273#if !NET20
1274            XDocument newXDoc = JsonConvert.DeserializeXNode(json, "myRoot");
1275
1276            StringAssert.AreEqual(@"<myRoot>
1277  <available_sizes>
1278    <available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes>
1279    <available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes>
1280  </available_sizes>
1281  <available_sizes>
1282    <available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
1283    <available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
1284  </available_sizes>
1285  <available_sizes>
1286    <available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
1287  </available_sizes>
1288</myRoot>", IndentXml(newXDoc.ToString(SaveOptions.DisableFormatting)));
1289#endif
1290
1291#if !PORTABLE
1292            string newJson = JsonConvert.SerializeXmlNode(newDoc, Formatting.Indented);
1293            Console.WriteLine(newJson);
1294#endif
1295        }
1296
1297        [Test]
1298        public void RoundTripNestedArrays()
1299        {
1300            string json = @"{
1301  ""available_sizes"": [
1302    [
1303      ""assets/images/resized/0001/1070/11070v1-max-150x150.jpg"",
1304      ""assets/images/resized/0001/1070/11070v1-max-150x150.jpg""
1305    ],
1306    [
1307      ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg"",
1308      ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
1309    ],
1310    [
1311      ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
1312    ]
1313  ]
1314}";
1315
1316#if !PORTABLE
1317            XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot", true);
1318
1319            StringAssert.AreEqual(@"<myRoot>
1320  <available_sizes json:Array=""true"" xmlns:json=""http://james.newtonking.com/projects/json"">
1321    <available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes>
1322    <available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes>
1323  </available_sizes>
1324  <available_sizes json:Array=""true"" xmlns:json=""http://james.newtonking.com/projects/json"">
1325    <available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
1326    <available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
1327  </available_sizes>
1328  <available_sizes json:Array=""true"" xmlns:json=""http://james.newtonking.com/projects/json"">
1329    <available_sizes json:Array=""true"">assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
1330  </available_sizes>
1331</myRoot>", IndentXml(newDoc.InnerXml));
1332#endif
1333
1334#if !NET20
1335            XDocument newXDoc = JsonConvert.DeserializeXNode(json, "myRoot", true);
1336
1337            StringAssert.AreEqual(@"<myRoot>
1338  <available_sizes json:Array=""true"" xmlns:json=""http://james.newtonking.com/projects/json"">
1339    <available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes>
1340    <available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes>
1341  </available_sizes>
1342  <available_sizes json:Array=""true"" xmlns:json=""http://james.newtonking.com/projects/json"">
1343    <available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
1344    <available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
1345  </available_sizes>
1346  <available_sizes json:Array=""true"" xmlns:json=""http://james.newtonking.com/projects/json"">
1347    <available_sizes json:Array=""true"">assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
1348  </available_sizes>
1349</myRoot>", IndentXml(newXDoc.ToString(SaveOptions.DisableFormatting)));
1350#endif
1351
1352#if !PORTABLE
1353            string newJson = JsonConvert.SerializeXmlNode(newDoc, Formatting.Indented, true);
1354            StringAssert.AreEqual(json, newJson);
1355#endif
1356        }
1357
1358        [Test]
1359        public void MultipleNestedArraysToXml()
1360        {
1361            string json = @"{
1362  ""available_sizes"": [
1363    [
1364      [113, 150],
1365      ""assets/images/resized/0001/1070/11070v1-max-150x150.jpg""
1366    ],
1367    [
1368      [189, 250],
1369      ""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
1370    ],
1371    [
1372      [341, 450],
1373      ""assets/images/resized/0001/1070/11070v1-max-450x450.jpg""
1374    ]
1375  ]
1376}";
1377
1378#if !PORTABLE
1379            XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot");
1380
1381            Assert.AreEqual(@"<myRoot><available_sizes><available_sizes><available_sizes>113</available_sizes><available_sizes>150</available_sizes></available_sizes><available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes></available_sizes><available_sizes><available_sizes><available_sizes>189</available_sizes><available_sizes>250</available_sizes></available_sizes><available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes></available_sizes><available_sizes><available_sizes><available_sizes>341</available_sizes><available_sizes>450</available_sizes></available_sizes><available_sizes>assets/images/resized/0001/1070/11070v1-max-450x450.jpg</available_sizes></available_sizes></myRoot>", newDoc.InnerXml);
1382#endif
1383
1384#if !NET20
1385            XDocument newXDoc = JsonConvert.DeserializeXNode(json, "myRoot");
1386
1387            Assert.AreEqual(@"<myRoot><available_sizes><available_sizes><available_sizes>113</available_sizes><available_sizes>150</available_sizes></available_sizes><available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes></available_sizes><available_sizes><available_sizes><available_sizes>189</available_sizes><available_sizes>250</available_sizes></available_sizes><available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes></available_sizes><available_sizes><available_sizes><available_sizes>341</available_sizes><available_sizes>450</available_sizes></available_sizes><available_sizes>assets/images/resized/0001/1070/11070v1-max-450x450.jpg</available_sizes></available_sizes></myRoot>", newXDoc.ToString(SaveOptions.DisableFormatting));
1388#endif
1389        }
1390
1391#if !PORTABLE
1392        [Test]
1393        public void Encoding()
1394        {
1395            XmlDocument doc = new XmlDocument();
1396
1397            doc.LoadXml(@"<name>O""Connor</name>"); // i use "" so it will be easier to see the  problem
1398
1399            string json = SerializeXmlNode(doc);
1400            StringAssert.AreEqual(@"{
1401  ""name"": ""O\""Connor""
1402}", json);
1403        }
1404#endif
1405
1406#if !PORTABLE
1407        [Test]
1408        public void SerializeComment()
1409        {
1410            string xml = @"<span class=""vevent"">
1411  <a class=""url"" href=""http://www.web2con.com/""><!-- Hi --><span>Text</span></a><!-- Hi! -->
1412</span>";
1413            XmlDocument doc = new XmlDocument();
1414            doc.LoadXml(xml);
1415
1416            string jsonText = SerializeXmlNode(doc);
1417
1418            string expected = @"{
1419  ""span"": {
1420    ""@class"": ""vevent"",
1421    ""a"": {
1422      ""@class"": ""url"",
1423      ""@href"": ""http://www.web2con.com/""/* Hi */,
1424      ""span"": ""Text""
1425    }/* Hi! */
1426  }
1427}";
1428
1429            StringAssert.AreEqual(expected, jsonText);
1430
1431            XmlDocument newDoc = (XmlDocument)DeserializeXmlNode(jsonText);
1432            Assert.AreEqual(@"<span class=""vevent""><a class=""url"" href=""http://www.web2con.com/""><!-- Hi --><span>Text</span></a><!-- Hi! --></span>", newDoc.InnerXml);
1433        }
1434
1435        [Test]
1436        public void SerializeExample()
1437        {
1438            string xml = @"<?xml version=""1.0"" standalone=""no""?>
1439			<root>
1440			  <person id=""1"">
1441				<name>Alan</name>
1442				<url>http://www.google.com</url>
1443			  </person>
1444			  <person id=""2"">
1445				<name>Louis</name>
1446				<url>http://www.yahoo.com</url>
1447			  </person>
1448			</root>";
1449
1450            XmlDocument doc = new XmlDocument();
1451            doc.LoadXml(xml);
1452
1453            string jsonText = SerializeXmlNode(doc);
1454            // {
1455            //   "?xml": {
1456            //     "@version": "1.0",
1457            //     "@standalone": "no"
1458            //   },
1459            //   "root": {
1460            //     "person": [
1461            //       {
1462            //         "@id": "1",
1463            //         "name": "Alan",
1464            //         "url": "http://www.google.com"
1465            //       },
1466            //       {
1467            //         "@id": "2",
1468            //         "name": "Louis",
1469            //         "url": "http://www.yahoo.com"
1470            //       }
1471            //     ]
1472            //   }
1473            // }
1474
1475            // format
1476            jsonText = JObject.Parse(jsonText).ToString();
1477
1478            StringAssert.AreEqual(@"{
1479  ""?xml"": {
1480    ""@version"": ""1.0"",
1481    ""@standalone"": ""no""
1482  },
1483  ""root"": {
1484    ""person"": [
1485      {
1486        ""@id"": ""1"",
1487        ""name"": ""Alan"",
1488        ""url"": ""http://www.google.com""
1489      },
1490      {
1491        ""@id"": ""2"",…

Large files files are truncated, but you can click here to view the full file