#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 !(DNXCORE50 || PORTABLE40) using System.Globalization; #if NET20 using Newtonsoft.Json.Utilities.LinqBridge; #else using System.Linq; #endif using System.Text; using System; using System.Collections.Generic; using Newtonsoft.Json.Tests.Serialization; using Newtonsoft.Json.Tests.TestObjects; #if DNXCORE50 using Xunit; using Test = Xunit.FactAttribute; using Assert = Newtonsoft.Json.Tests.XUnitAssert; #else using NUnit.Framework; #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 { #if !PORTABLE || NETSTANDARD1_3 private string SerializeXmlNode(XmlNode node) { string json = JsonConvert.SerializeXmlNode(node, Formatting.Indented); #if !(NET20) #if !NETSTANDARD1_3 XmlReader reader = new XmlNodeReader(node); #else StringReader sr = new StringReader(node.OuterXml); XmlReader reader = XmlReader.Create(sr); #endif 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; } #endif 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 WriteJsonNull() { StringWriter sw = new StringWriter(); JsonTextWriter jsonWriter = new JsonTextWriter(sw); XmlNodeConverter converter = new XmlNodeConverter(); converter.WriteJson(jsonWriter, null, null); StringAssert.AreEqual(@"null", sw.ToString()); } #if !NET20 [Test] public void SerializeDollarProperty() { string json1 = @"{""$"":""test""}"; var doc = JsonConvert.DeserializeXNode(json1); Assert.AreEqual(@"<_x0024_>test", doc.ToString()); var json2 = JsonConvert.SerializeXNode(doc); Assert.AreEqual(json1, json2); } [Test] public void SerializeNonKnownDollarProperty() { string json1 = @"{""$JELLY"":""test""}"; var doc = JsonConvert.DeserializeXNode(json1); Console.WriteLine(doc.ToString()); Assert.AreEqual(@"<_x0024_JELLY>test", doc.ToString()); var json2 = JsonConvert.SerializeXNode(doc); Assert.AreEqual(json1, json2); } public class MyModel { public string MyProperty { get; set; } } [Test] public void ConvertNullString() { JObject json = new JObject(); json["Prop1"] = (string)null; json["Prop2"] = new MyModel().MyProperty; var xmlNodeConverter = new XmlNodeConverter { DeserializeRootElementName = "object" }; var jsonSerializerSettings = new JsonSerializerSettings { Converters = new JsonConverter[] { xmlNodeConverter } }; var jsonSerializer = JsonSerializer.CreateDefault(jsonSerializerSettings); XDocument d = json.ToObject(jsonSerializer); StringAssert.Equals(@" ", d.ToString()); } public class Foo { public XElement Bar { get; set; } } [Test] public void SerializeAndDeserializeXElement() { Foo foo = new Foo { Bar = null }; string json = JsonConvert.SerializeObject(foo); Assert.AreEqual(@"{""Bar"":null}", json); Foo foo2 = JsonConvert.DeserializeObject(json); Assert.IsNull(foo2.Bar); } [Test] public void MultipleNamespacesXDocument() { string xml = @""; XDocument d = XDocument.Parse(xml); string json = JsonConvert.SerializeObject(d, Formatting.Indented); StringAssert.AreEqual(@"{ ""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"" } }", json); XDocument doc = JsonConvert.DeserializeObject(json); StringAssert.AreEqual(xml, doc.ToString()); } #endif #if !PORTABLE || NETSTANDARD1_3 [Test] public void MultipleNamespacesXmlDocument() { string xml = @""; XmlDocument d = new XmlDocument(); d.LoadXml(xml); string json = JsonConvert.SerializeObject(d, Formatting.Indented); StringAssert.AreEqual(@"{ ""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"" } }", json); XmlDocument doc = JsonConvert.DeserializeObject(json); StringAssert.AreEqual(xml, doc.OuterXml); } [Test] public void SerializeXmlElement() { string xml = @" 6 79 Approved Someone "; var xmlDocument = new XmlDocument(); xmlDocument.LoadXml(xml); var result = xmlDocument.FirstChild.ChildNodes.Cast().ToArray(); var json = JsonConvert.SerializeObject(result, Formatting.Indented); // <--- fails here with the cast message StringAssert.AreEqual(@"[ { ""Country"": ""6"" }, { ""FinancialTransactionApprovalRequestUID"": ""79"" }, { ""TransactionStatus"": ""Approved"" }, { ""StatusChangeComment"": """" }, { ""RequestedBy"": ""Someone"" } ]", json); } #endif #if !NET20 [Test] public void SerializeXElement() { string xml = @" 6 79 Approved Someone "; var xmlDocument = XDocument.Parse(xml); var result = xmlDocument.Root.Nodes().ToArray(); var json = JsonConvert.SerializeObject(result, Formatting.Indented); // <--- fails here with the cast message StringAssert.AreEqual(@"[ { ""Country"": ""6"" }, { ""FinancialTransactionApprovalRequestUID"": ""79"" }, { ""TransactionStatus"": ""Approved"" }, { ""StatusChangeComment"": """" }, { ""RequestedBy"": ""Someone"" } ]", json); } public class DecimalContainer { public decimal Number { get; set; } } [Test] public void FloatParseHandlingDecimal() { decimal d = (decimal)Math.PI + 1000000000m; var x = new DecimalContainer { Number = d }; var json = JsonConvert.SerializeObject(x, Formatting.Indented); XDocument doc1 = JsonConvert.DeserializeObject(json, new JsonSerializerSettings { Converters = { new XmlNodeConverter() }, FloatParseHandling = FloatParseHandling.Decimal }); var xml = doc1.ToString(); Assert.AreEqual("1000000003.14159265358979", xml); string json2 = JsonConvert.SerializeObject(doc1, Formatting.Indented); DecimalContainer x2 = JsonConvert.DeserializeObject(json2); Assert.AreEqual(x.Number, x2.Number); } public class DateTimeOffsetContainer { public DateTimeOffset Date { get; set; } } [Test] public void DateTimeParseHandlingOffset() { DateTimeOffset d = new DateTimeOffset(2012, 12, 12, 12, 44, 1, TimeSpan.FromHours(12).Add(TimeSpan.FromMinutes(34))); var x = new DateTimeOffsetContainer { Date = d }; var json = JsonConvert.SerializeObject(x, Formatting.Indented); XDocument doc1 = JsonConvert.DeserializeObject(json, new JsonSerializerSettings { Converters = { new XmlNodeConverter() }, DateParseHandling = DateParseHandling.DateTimeOffset }); var xml = doc1.ToString(); Assert.AreEqual("2012-12-12T12:44:01+12:34", xml); string json2 = JsonConvert.SerializeObject(doc1, Formatting.Indented); DateTimeOffsetContainer x2 = JsonConvert.DeserializeObject(json2); Assert.AreEqual(x.Date, x2.Date); } [Test] public void GroupElementsOfTheSameName() { string xml = "

Text1Span1 Span2 Text2

"; string json = JsonConvert.SerializeXNode(XElement.Parse(xml)); Assert.AreEqual(@"{""root"":{""p"":{""#text"":[""Text1"","" Text2""],""span"":[""Span1"",""Span2""]}}}", json); XDocument doc = JsonConvert.DeserializeXNode(json); StringAssert.AreEqual(@"

Text1 Text2Span1Span2

", doc.ToString()); } #if !PORTABLE || NETSTANDARD1_3 [Test] public void SerializeEmptyDocument() { XmlDocument doc = new XmlDocument(); doc.LoadXml(""); string json = JsonConvert.SerializeXmlNode(doc, Formatting.Indented, true); Assert.AreEqual("null", json); doc = new XmlDocument(); doc.LoadXml(""); json = JsonConvert.SerializeXmlNode(doc, Formatting.Indented, true); Assert.AreEqual(@"""""", json); XDocument doc1 = XDocument.Parse(""); json = JsonConvert.SerializeXNode(doc1, Formatting.Indented, true); Assert.AreEqual("null", json); doc1 = XDocument.Parse(""); json = JsonConvert.SerializeXNode(doc1, Formatting.Indented, true); Assert.AreEqual(@"""""", json); } #endif [Test] public void SerializeAndDeserializeXmlWithNamespaceInChildrenAndNoValueInChildren() { var xmlString = @" AAA adad "; var xml = XElement.Parse(xmlString); var json1 = JsonConvert.SerializeXNode(xml); var xmlBack = JsonConvert.DeserializeObject(json1); var equals = XElement.DeepEquals(xmlBack, xml); Assert.IsTrue(equals); } #if !PORTABLE || NETSTANDARD1_3 [Test] public void DeserializeUndeclaredNamespacePrefix() { XmlDocument doc = JsonConvert.DeserializeXmlNode("{ A: { '@xsi:nil': true } }"); Assert.AreEqual(@"", doc.OuterXml); XDocument xdoc = JsonConvert.DeserializeXNode("{ A: { '@xsi:nil': true } }"); Assert.AreEqual(doc.OuterXml, xdoc.ToString()); } #endif #endif #if !PORTABLE || NETSTANDARD1_3 [Test] public void DeserializeMultipleRootElements() { string json = @"{ ""Id"": 1, ""Email"": ""james@example.com"", ""Active"": true, ""CreatedDate"": ""2013-01-20T00:00:00Z"", ""Roles"": [ ""User"", ""Admin"" ], ""Team"": { ""Id"": 2, ""Name"": ""Software Developers"", ""Description"": ""Creators of fine software products and services."" } }"; ExceptionAssert.Throws( () => { JsonConvert.DeserializeXmlNode(json); }, "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."); } [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"" } ] } } }"; StringAssert.AreEqual(expected, jsonText); } [Test] public void SerializeNodeTypes() { XmlDocument doc = new XmlDocument(); string jsonText; 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); 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); Assert.AreEqual(@"{""?xml-stylesheet"":""href=\""classic.xsl\"" type=\""text/xml\""""}", jsonText); // XmlProcessingInstruction XmlCDataSection cDataSection = doc.CreateCDataSection("true"); jsonText = JsonConvert.SerializeXmlNode(cDataSection); 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); StringAssert.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 SerializeNodeTypes_Encoding() { XmlNode node = DeserializeXmlNode(@"{ ""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"" } }"); Assert.AreEqual(@"true]]>", node.InnerXml); string json = SerializeXmlNode(node); StringAssert.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"" } }", json); } [Test] public void DocumentFragmentSerialize() { XmlDocument doc = new XmlDocument(); XmlDocumentFragment fragement = doc.CreateDocumentFragment(); fragement.InnerXml = "widgetwidget"; string jsonText = JsonConvert.SerializeXmlNode(fragement); string expected = @"{""Item"":[""widget"",""widget""]}"; Assert.AreEqual(expected, jsonText); } #if !NETSTANDARD1_3 [Test] public void XmlDocumentTypeSerialize() { string xml = @"00-16.310Dow Jones2014-04-17 15:50:370016460.4902014-04-17 15:50:3716408.54016368.14016424.140-0.099016424.8500DJII013618870011309.0009302.2800009.290NASDAQ2014-04-17 15:40:01004110.4602014-04-17 15:40:014095.5204064.7004080.3000.22704086.2300COMP017842101004371.7103154.9600Couldn't find ticker: SPIC?2"; string expected = @"{ ""?xml"": { ""@version"": ""1.0"", ""@encoding"": ""utf-8"" }, ""!DOCTYPE"": { ""@name"": ""STOCKQUOTE"", ""@public"": ""-//W3C//DTD StockQuote 1.5//EN"", ""@system"": ""http://www.idontexistnopenopewhatnope123.org/dtd/stockquote_1.5.dtd"" }, ""STOCKQUOTE"": { ""@ROWCOUNT"": ""2"", ""RESULT"": { ""ROW"": [ { ""ASK"": ""0"", ""BID"": ""0"", ""CHANGE"": ""-16.310"", ""COMPANYNAME"": ""Dow Jones"", ""DATETIME"": ""2014-04-17 15:50:37"", ""DIVIDEND"": ""0"", ""EPS"": ""0"", ""EXCHANGE"": """", ""HIGH"": ""16460.490"", ""LASTDATETIME"": ""2014-04-17 15:50:37"", ""LASTPRICE"": ""16408.540"", ""LOW"": ""16368.140"", ""OPEN"": ""16424.140"", ""PCHANGE"": ""-0.099"", ""PE"": ""0"", ""PREVIOUSCLOSE"": ""16424.850"", ""SHARES"": ""0"", ""TICKER"": ""DJII"", ""TRADES"": ""0"", ""VOLUME"": ""136188700"", ""YEARHIGH"": ""11309.000"", ""YEARLOW"": ""9302.280"", ""YIELD"": ""0"" }, { ""ASK"": ""0"", ""BID"": ""0"", ""CHANGE"": ""9.290"", ""COMPANYNAME"": ""NASDAQ"", ""DATETIME"": ""2014-04-17 15:40:01"", ""DIVIDEND"": ""0"", ""EPS"": ""0"", ""EXCHANGE"": """", ""HIGH"": ""4110.460"", ""LASTDATETIME"": ""2014-04-17 15:40:01"", ""LASTPRICE"": ""4095.520"", ""LOW"": ""4064.700"", ""OPEN"": ""4080.300"", ""PCHANGE"": ""0.227"", ""PE"": ""0"", ""PREVIOUSCLOSE"": ""4086.230"", ""SHARES"": ""0"", ""TICKER"": ""COMP"", ""TRADES"": ""0"", ""VOLUME"": ""1784210100"", ""YEARHIGH"": ""4371.710"", ""YEARLOW"": ""3154.960"", ""YIELD"": ""0"" } ] }, ""STATUS"": ""Couldn't find ticker: SPIC?"", ""STATUSCODE"": ""2"" } }"; XmlDocument doc1 = new XmlDocument(); doc1.XmlResolver = null; doc1.LoadXml(xml); string json1 = JsonConvert.SerializeXmlNode(doc1, Formatting.Indented); StringAssert.AreEqual(expected, json1); XmlDocument doc11 = JsonConvert.DeserializeXmlNode(json1); StringAssert.AreEqual(xml, ToStringWithDeclaration(doc11)); #if !NET20 XDocument doc2 = XDocument.Parse(xml); string json2 = JsonConvert.SerializeXNode(doc2, Formatting.Indented); StringAssert.AreEqual(expected, json2); XDocument doc22 = JsonConvert.DeserializeXNode(json2); StringAssert.AreEqual(xml, ToStringWithDeclaration(doc22)); #endif } #endif public class Utf8StringWriter : StringWriter { public override Encoding Encoding { get { return Encoding.UTF8; } } public Utf8StringWriter(StringBuilder sb) : base(sb) { } } #if !NET20 public static string ToStringWithDeclaration(XDocument doc, bool indent = false) { StringBuilder builder = new StringBuilder(); using (var writer = XmlWriter.Create(new Utf8StringWriter(builder), new XmlWriterSettings { Indent = indent })) { doc.Save(writer); } return builder.ToString(); } #endif public static string ToStringWithDeclaration(XmlDocument doc, bool indent = false) { StringBuilder builder = new StringBuilder(); using (var writer = XmlWriter.Create(new Utf8StringWriter(builder), new XmlWriterSettings { Indent = indent })) { doc.Save(writer); } return builder.ToString(); } [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"" } ] } } } } } } } }"; StringAssert.AreEqual(expected, jsonText); XmlDocument deserializedDoc = (XmlDocument)DeserializeXmlNode(jsonText); Assert.AreEqual(doc.InnerXml, deserializedDoc.InnerXml); } [Test] public void FailOnIncomplete() { string json = @"{'Row' : "; ExceptionAssert.Throws( () => JsonConvert.DeserializeXmlNode(json, "ROOT"), "Unexpected end when reading JSON. Path 'Row', line 1, position 9."); } [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); StringAssert.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(); } public class Foo2 { public XmlElement Bar { get; set; } } [Test] public void SerializeAndDeserializeXmlElement() { Foo2 foo = new Foo2 { Bar = null }; string json = JsonConvert.SerializeObject(foo); Assert.AreEqual(@"{""Bar"":null}", json); Foo2 foo2 = JsonConvert.DeserializeObject(json); Assert.IsNull(foo2.Bar); } [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); StringAssert.AreEqual(@"{ ""?xml"": { ""@version"": ""1.0"", ""@standalone"": ""no"" }, ""root"": { ""person"": [ { ""@id"": ""1"", ""name"": ""Alan"", ""url"": null }, { ""@id"": ""2"", ""name"": ""Louis"", ""url"": ""http://www.yahoo.com"" } ] } }", 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] public void NoRootObject() { ExceptionAssert.Throws(() => { XmlDocument newDoc = (XmlDocument)JsonConvert.DeserializeXmlNode(@"[1]"); }, "XmlNodeConverter can only convert JSON that begins with an object. Path '', line 1, position 1."); } [Test] public void RootObjectMultipleProperties() { ExceptionAssert.Throws( () => { XmlDocument newDoc = (XmlDocument)JsonConvert.DeserializeXmlNode(@"{Prop1:1,Prop2:2}"); }, "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."); } [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"" ] } } }"; StringAssert.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"" ] } } }"; StringAssert.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"" ] } } }"; StringAssert.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"" } } }"; StringAssert.AreEqual(expected, arrayJsonText); arrayXml = @" Alan http://www.google.com Admin "; arrayDoc = new XmlDocument(); arrayDoc.LoadXml(arrayXml); arrayJsonText = SerializeXmlNode(arrayDoc); expected = @"{ ""root"": { ""person"": { ""@id"": ""1"", ""name"": ""Alan"", ""url"": ""http://www.google.com"", ""role"": [ ""Admin"" ] } } }"; StringAssert.AreEqual(expected, arrayJsonText); } [Test] public void MultipleRootPropertiesXmlDocument() { string json = @"{""count"": 773840,""photos"": null}"; ExceptionAssert.Throws( () => { JsonConvert.DeserializeXmlNode(json); }, "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."); } #endif #if !NET20 [Test] public void MultipleRootPropertiesXDocument() { string json = @"{""count"": 773840,""photos"": null}"; ExceptionAssert.Throws( () => { JsonConvert.DeserializeXNode(json); }, "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."); } #endif [Test] public void MultipleRootPropertiesAddRootElement() { string json = @"{""count"": 773840,""photos"": 773840}"; #if !PORTABLE XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot"); Assert.AreEqual(@"773840773840", newDoc.InnerXml); #endif #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"" ] ] }"; #if !PORTABLE || NETSTANDARD1_3 XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot"); string xml = IndentXml(newDoc.InnerXml); StringAssert.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)); #endif #if !NET20 XDocument newXDoc = JsonConvert.DeserializeXNode(json, "myRoot"); StringAssert.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 #if !PORTABLE || NETSTANDARD1_3 string newJson = JsonConvert.SerializeXmlNode(newDoc, Formatting.Indented); Console.WriteLine(newJson); #endif } [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"" ] ] }"; #if !PORTABLE || NETSTANDARD1_3 XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot", true); StringAssert.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)); #endif #if !NET20 XDocument newXDoc = JsonConvert.DeserializeXNode(json, "myRoot", true); StringAssert.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 #if !PORTABLE || NETSTANDARD1_3 string newJson = JsonConvert.SerializeXmlNode(newDoc, Formatting.Indented, true); StringAssert.AreEqual(json, newJson); #endif } [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"" ] ] }"; #if !PORTABLE || NETSTANDARD1_3 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); #endif #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 } #if !PORTABLE || NETSTANDARD1_3 [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); StringAssert.AreEqual(@"{ ""name"": ""O\""Connor"" }", json); } #endif #if !PORTABLE || NETSTANDARD1_3 [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/""/* Hi */, ""span"": ""Text"" }/* Hi! */ } }"; StringAssert.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(); StringAssert.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 // // StringAssert.AreEqual(@"Alanhttp://www.google.comLouishttp://www.yahoo.com", doc.InnerXml); } [Test] public void EscapingNames() { string json = @"{ ""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); Assert.AreEqual(@"Alanhttp://www.google.comLouishttp://www.yahoo.com", doc.InnerXml); string json2 = SerializeXmlNode(doc); StringAssert.AreEqual(@"{ ""root!"": { ""person!"": [ { ""@id!"": ""1"", ""name!"": ""Alan"", ""url!"": ""http://www.google.com"" }, { ""@id!"": ""2"", ""name!"": ""Louis"", ""url!"": ""http://www.yahoo.com"" } ] } }", json2); } [Test] public void SerializeDeserializeMetadataProperties() { 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 }); StringAssert.AreEqual(@"{ ""$id"": ""1"", ""other"": { ""$id"": ""2"", ""blah"": null }, ""self"": { ""$ref"": ""1"" } }", json); XmlNode node = DeserializeXmlNode(json, "root"); string xml = GetIndentedInnerXml(node); string expected = @" "; StringAssert.AreEqual(expected, xml); string xmlJson = SerializeXmlNode(node); string expectedXmlJson = @"{ ""root"": { ""$id"": ""1"", ""other"": { ""$id"": ""2"", ""blah"": null }, ""self"": { ""$ref"": ""1"" } } }"; StringAssert.AreEqual(expectedXmlJson, xmlJson); } [Test] public void SerializeDeserializeMetadataArray() { string json = @"{ ""$id"": ""1"", ""$values"": [ ""1"", ""2"", ""3"", ""4"", ""5"" ] }"; XmlNode node = JsonConvert.DeserializeXmlNode(json, "root"); string xml = GetIndentedInnerXml(node); StringAssert.AreEqual(@" 1 2 3 4 5 ", xml); string newJson = JsonConvert.SerializeXmlNode(node, Formatting.Indented, true); StringAssert.AreEqual(json, newJson); } [Test] public void SerializeDeserializeMetadataArrayNoId() { string json = @"{ ""$values"": [ ""1"", ""2"", ""3"", ""4"", ""5"" ] }"; XmlNode node = JsonConvert.DeserializeXmlNode(json, "root"); string xml = GetIndentedInnerXml(node); StringAssert.AreEqual(@" 1 2 3 4 5 ", xml); string newJson = JsonConvert.SerializeXmlNode(node, Formatting.Indented, true); Console.WriteLine(newJson); StringAssert.AreEqual(json, newJson); } [Test] public void SerializeDeserializeMetadataArrayWithIdLast() { string json = @"{ ""$values"": [ ""1"", ""2"", ""3"", ""4"", ""5"" ], ""$id"": ""1"" }"; XmlNode node = JsonConvert.DeserializeXmlNode(json, "root"); string xml = GetIndentedInnerXml(node); StringAssert.AreEqual(@" 1 2 3 4 5 ", xml); string newJson = JsonConvert.SerializeXmlNode(node, Formatting.Indented, true); StringAssert.AreEqual(@"{ ""$id"": ""1"", ""$values"": [ ""1"", ""2"", ""3"", ""4"", ""5"" ] }", newJson); } [Test] public void SerializeMetadataPropertyWithBadValue() { string json = @"{ ""$id"": [] }"; ExceptionAssert.Throws( () => { JsonConvert.DeserializeXmlNode(json, "root"); }, "Unexpected JsonToken: StartArray. Path '$id', line 2, position 10."); } [Test] public void SerializeDeserializeMetadataWithNullValue() { string json = @"{ ""$id"": null }"; XmlNode node = JsonConvert.DeserializeXmlNode(json, "root"); string xml = GetIndentedInnerXml(node); StringAssert.AreEqual(@" ", xml); string newJson = JsonConvert.SerializeXmlNode(node, Formatting.Indented, true); StringAssert.AreEqual(@"{ ""$id"": """" }", newJson); } [Test] public void SerializeDeserializeMetadataArrayNull() { string json = @"{ ""$id"": ""1"", ""$values"": null }"; XmlNode node = JsonConvert.DeserializeXmlNode(json, "root"); string xml = GetIndentedInnerXml(node); StringAssert.AreEqual(@" ", xml); string newJson = JsonConvert.SerializeXmlNode(node, Formatting.Indented, true); StringAssert.AreEqual(json, newJson); } [Test] 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"" } } } } }"; ExceptionAssert.Throws( () => { DeserializeXmlNode(json); }, "XmlNodeConverter cannot convert JSON with an empty property name to XML. Path '8452309520V2.', line 3, position 9."); } [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); StringAssert.AreEqual(@" Apple 2008-12-28T00:00:00Z 3.99 Small ", IndentXml(xmlProduct.InnerXml)); string output2 = JsonConvert.SerializeXmlNode(xmlProduct.DocumentElement, Formatting.Indented); StringAssert.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); StringAssert.AreEqual(@" Hi First 2000-01-01T00:00:00Z 0 ", IndentXml(xmlProduct.InnerXml)); string output2 = JsonConvert.SerializeXmlNode(xmlProduct.DocumentElement, Formatting.Indented, true); StringAssert.AreEqual(@"{ ""Name"": ""Hi"", ""Products"": [ { ""Name"": ""First"", ""ExpiryDate"": ""2000-01-01T00:00:00Z"", ""Price"": ""0"", ""Sizes"": null } ] }", output2); } [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); StringAssert.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); StringAssert.AreEqual(@"{ ""?xml"": { ""@version"": ""1.0"", ""@encoding"": ""utf-8"" }, ""root"": { ""A"": { ""B"": [ { ""@name"": ""sample"" } ], ""C"": [ """", """" ] } } }", json); XmlDocument d2 = JsonConvert.DeserializeXmlNode(json); StringAssert.AreEqual(@" ", ToStringWithDeclaration(d2, true)); } [Test] public void EmtpyElementWithArrayAttributeShouldWriteElement() { string xml = @" "; XmlDocument d = new XmlDocument(); d.LoadXml(xml); string json = JsonConvert.SerializeXmlNode(d, Formatting.Indented); StringAssert.AreEqual(@"{ ""root"": { ""Reports"": [ {} ] } }", 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); } [Test] public void IgnoreCultureForTypedAttributes() { var originalCulture = System.Threading.Thread.CurrentThread.CurrentCulture; try { System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("ru-RU"); // in russian culture value 12.27 will be written as 12,27 var serializer = JsonSerializer.Create(new JsonSerializerSettings { Converters = { new XmlNodeConverter() }, }); var json = new StringBuilder(@"{ ""metrics"": { ""type"": ""CPULOAD"", ""@value"": 12.27 } }"); using (var stringReader = new StringReader(json.ToString())) using (var jsonReader = new JsonTextReader(stringReader)) { var document = (XmlDocument)serializer.Deserialize(jsonReader, typeof(XmlDocument)); StringAssert.AreEqual(@"CPULOAD", document.OuterXml); } } finally { System.Threading.Thread.CurrentThread.CurrentCulture = originalCulture; } } [Test] public void NullAttributeValue() { var node = JsonConvert.DeserializeXmlNode(@"{ ""metrics"": { ""type"": ""CPULOAD"", ""@value"": null } }"); StringAssert.AreEqual(@"CPULOAD", node.OuterXml); } [Test] public void NonStandardAttributeValues() { JObject o = new JObject { new JProperty("root", new JObject { new JProperty("@uri", new JValue(new Uri("http://localhost/"))), new JProperty("@time_span", new JValue(TimeSpan.FromMinutes(1))), new JProperty("@bytes", new JValue(System.Text.Encoding.UTF8.GetBytes("Hello world"))) }) }; using (var jsonReader = o.CreateReader()) { var serializer = JsonSerializer.Create(new JsonSerializerSettings { Converters = { new XmlNodeConverter() }, }); var document = (XmlDocument)serializer.Deserialize(jsonReader, typeof(XmlDocument)); StringAssert.AreEqual(@"", document.OuterXml); } } [Test] public void NonStandardElementsValues() { JObject o = new JObject { new JProperty("root", new JObject { new JProperty("uri", new JValue(new Uri("http://localhost/"))), new JProperty("time_span", new JValue(TimeSpan.FromMinutes(1))), new JProperty("bytes", new JValue(System.Text.Encoding.UTF8.GetBytes("Hello world"))) }) }; using (var jsonReader = o.CreateReader()) { var serializer = JsonSerializer.Create(new JsonSerializerSettings { Converters = { new XmlNodeConverter() }, }); var document = (XmlDocument)serializer.Deserialize(jsonReader, typeof(XmlDocument)); StringAssert.AreEqual(@"http://localhost/00:01:00SGVsbG8gd29ybGQ=", document.OuterXml); } } 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); } } } #endif #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"": """" } ] } }"; StringAssert.AreEqual(expectedJson, json); XNode node = JsonConvert.DeserializeXNode(json); string xaml2 = node.ToString(); string expectedXaml = @" "; StringAssert.AreEqual(expectedXaml, xaml2); } #endif #if !PORTABLE || NETSTANDARD1_3 [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"": """" } ] } }"; StringAssert.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 = @" "; StringAssert.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 [Test] public void SerializingXmlNamespaceScope() { var xmlString = @" "; #if !NET20 var xml = XElement.Parse(xmlString); var json1 = JsonConvert.SerializeObject(xml); Assert.AreEqual(@"{""root"":{""@xmlns"":""http://www.example.com/ns"",""a"":null,""bns:b"":{""@xmlns:bns"":""http://www.example.com/ns""},""c"":null}}", json1); #endif #if !(PORTABLE) var xml1 = new XmlDocument(); xml1.LoadXml(xmlString); var json2 = JsonConvert.SerializeObject(xml1); Assert.AreEqual(@"{""root"":{""@xmlns"":""http://www.example.com/ns"",""a"":null,""bns:b"":{""@xmlns:bns"":""http://www.example.com/ns""},""c"":null}}", json2); #endif } #if !NET20 public class NullableXml { public string Name; public XElement notNull; public XElement isNull; } [Test] public void SerializeAndDeserializeNullableXml() { var xml = new NullableXml { Name = "test", notNull = XElement.Parse("test") }; var json = JsonConvert.SerializeObject(xml); var w2 = JsonConvert.DeserializeObject(json); Assert.AreEqual(xml.Name, w2.Name); Assert.AreEqual(xml.isNull, w2.isNull); Assert.AreEqual(xml.notNull.ToString(), w2.notNull.ToString()); } #endif #if !NET20 [Test] public void SerializeAndDeserializeXElementWithNamespaceInChildrenRootDontHaveNameSpace() { var xmlString = @" Asd AAA adad "; var xml = XElement.Parse(xmlString); var json1 = JsonConvert.SerializeXNode(xml); var xmlBack = JsonConvert.DeserializeObject(json1); var equals = XElement.DeepEquals(xmlBack, xml); Assert.IsTrue(equals); } #endif #if !PORTABLE || NETSTANDARD1_3 [Test] public void SerializeAndDeserializeXmlElementWithNamespaceInChildrenRootDontHaveNameSpace() { var xmlString = @" Asd AAA adad "; XmlDocument xml = new XmlDocument(); xml.LoadXml(xmlString); var json1 = JsonConvert.SerializeXmlNode(xml); var xmlBack = JsonConvert.DeserializeObject(json1); Assert.AreEqual(@"AsdAAAadad", xmlBack.OuterXml); } #if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 [Test] public void DeserializeBigInteger() { var json = "{\"DocumentId\":13779965364495889899 }"; XmlDocument node = JsonConvert.DeserializeXmlNode(json); Assert.AreEqual("13779965364495889899", node.OuterXml); string json2 = JsonConvert.SerializeXmlNode(node); Assert.AreEqual(@"{""DocumentId"":""13779965364495889899""}", json2); } #endif [Test] public void DeserializeXmlIncompatibleCharsInPropertyName() { var json = "{\"%name\":\"value\"}"; XmlDocument node = JsonConvert.DeserializeXmlNode(json); Assert.AreEqual("<_x0025_name>value", node.OuterXml); string json2 = JsonConvert.SerializeXmlNode(node); Assert.AreEqual(json, json2); } [Test] public void RootPropertyError() { string json = @"{ ""$id"": ""1"", ""AOSLocaleName"": ""en-US"", ""AXLanguage"": ""EN-AU"", ""Company"": ""AURE"", ""CompanyTimeZone"": 8, ""CurrencyInfo"": { ""$id"": ""2"", ""CurrencyCode"": ""AUD"", ""Description"": ""Australian Dollar"", ""ExchangeRate"": 100.0, ""ISOCurrencyCode"": ""AUD"", ""Prefix"": """", ""Suffix"": """" }, ""IsSysAdmin"": true, ""UserId"": ""lamar.miller"", ""UserPreferredCalendar"": 0, ""UserPreferredTimeZone"": 8 }"; ExceptionAssert.Throws( () => JsonConvert.DeserializeXmlNode(json), "JSON root object has property '$id' that will be converted to an attribute. A root object cannot have any attribute properties. Consider specifying a DeserializeRootElementName. Path '$id', line 2, position 12."); } [Test] public void SerializeEmptyNodeAndOmitRoot() { string xmlString = @""; XmlDocument xml = new XmlDocument(); xml.LoadXml(xmlString); string json = JsonConvert.SerializeXmlNode(xml, Formatting.Indented, true); Assert.AreEqual("null", json); } #endif #if !NET20 [Test] public void Serialize_XDocument_NoRoot() { XDocument d = new XDocument(); string json = JsonConvert.SerializeXNode(d); Assert.AreEqual(@"{}", json); } [Test] public void Deserialize_XDocument_NoRoot() { XDocument d = JsonConvert.DeserializeXNode(@"{}"); Assert.AreEqual(null, d.Root); Assert.AreEqual(null, d.Declaration); } [Test] public void Serialize_XDocument_NoRootWithDeclaration() { XDocument d = new XDocument(); d.Declaration = new XDeclaration("Version!", "Encoding!", "Standalone!"); string json = JsonConvert.SerializeXNode(d); Assert.AreEqual(@"{""?xml"":{""@version"":""Version!"",""@encoding"":""Encoding!"",""@standalone"":""Standalone!""}}", json); } [Test] public void Deserialize_XDocument_NoRootWithDeclaration() { XDocument d = JsonConvert.DeserializeXNode(@"{""?xml"":{""@version"":""Version!"",""@encoding"":""Encoding!"",""@standalone"":""Standalone!""}}"); Assert.AreEqual(null, d.Root); Assert.AreEqual("Version!", d.Declaration.Version); Assert.AreEqual("Encoding!", d.Declaration.Encoding); Assert.AreEqual("Standalone!", d.Declaration.Standalone); } [Test] public void DateTimeToXml_Unspecified() { string json = @"{""CreatedDate"": ""2014-01-23T00:00:00""}"; var dxml = JsonConvert.DeserializeXNode(json, "root"); Assert.AreEqual("2014-01-23T00:00:00", dxml.Root.Element("CreatedDate").Value); Console.WriteLine("DateTimeToXml_Unspecified: " + dxml.Root.Element("CreatedDate").Value); } [Test] public void DateTimeToXml_Utc() { string json = @"{""CreatedDate"": ""2014-01-23T00:00:00Z""}"; var dxml = JsonConvert.DeserializeXNode(json, "root"); Assert.AreEqual("2014-01-23T00:00:00Z", dxml.Root.Element("CreatedDate").Value); Console.WriteLine("DateTimeToXml_Utc: " + dxml.Root.Element("CreatedDate").Value); } [Test] public void DateTimeToXml_Local() { DateTime dt = DateTime.Parse("2014-01-23T00:00:00+01:00"); string json = @"{""CreatedDate"": ""2014-01-23T00:00:00+01:00""}"; var dxml = JsonConvert.DeserializeXNode(json, "root"); Assert.AreEqual(dt.ToString("yyyy-MM-ddTHH:mm:sszzzzzzz", CultureInfo.InvariantCulture), dxml.Root.Element("CreatedDate").Value); Console.WriteLine("DateTimeToXml_Local: " + dxml.Root.Element("CreatedDate").Value); } [Test] public void DateTimeToXml_Unspecified_Precision() { string json = @"{""CreatedDate"": ""2014-01-23T00:00:00.1234567""}"; var dxml = JsonConvert.DeserializeXNode(json, "root"); Assert.AreEqual("2014-01-23T00:00:00.1234567", dxml.Root.Element("CreatedDate").Value); Console.WriteLine("DateTimeToXml_Unspecified: " + dxml.Root.Element("CreatedDate").Value); } [Test] public void DateTimeToXml_Utc_Precision() { string json = @"{""CreatedDate"": ""2014-01-23T00:00:00.1234567Z""}"; var dxml = JsonConvert.DeserializeXNode(json, "root"); Assert.AreEqual("2014-01-23T00:00:00.1234567Z", dxml.Root.Element("CreatedDate").Value); Console.WriteLine("DateTimeToXml_Utc: " + dxml.Root.Element("CreatedDate").Value); } [Test] public void DateTimeToXml_Local_Precision() { DateTime dt = DateTime.Parse("2014-01-23T00:00:00.1234567+01:00"); string json = @"{""CreatedDate"": ""2014-01-23T00:00:00.1234567+01:00""}"; var dxml = JsonConvert.DeserializeXNode(json, "root"); Assert.AreEqual(dt.ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK", CultureInfo.InvariantCulture), dxml.Root.Element("CreatedDate").Value); Console.WriteLine("DateTimeToXml_Local: " + dxml.Root.Element("CreatedDate").Value); } [Test] public void SerializeEmptyNodeAndOmitRoot_XElement() { string xmlString = @""; var xml = XElement.Parse(xmlString); string json = JsonConvert.SerializeXNode(xml, Formatting.Indented, true); Assert.AreEqual("null", json); } [Test] public void SerializeElementExplicitAttributeNamespace() { var original = XElement.Parse(""); Assert.AreEqual(@"", original.ToString()); var json = JsonConvert.SerializeObject(original); Assert.AreEqual(@"{""MyElement"":{""@xmlns"":""http://example.com""}}", json); var deserialized = JsonConvert.DeserializeObject(json); Assert.AreEqual(@"", deserialized.ToString()); } [Test] public void SerializeElementImplicitAttributeNamespace() { var original = new XElement("{http://example.com}MyElement"); Assert.AreEqual(@"", original.ToString()); var json = JsonConvert.SerializeObject(original); Assert.AreEqual(@"{""MyElement"":{""@xmlns"":""http://example.com""}}", json); var deserialized = JsonConvert.DeserializeObject(json); Assert.AreEqual(@"", deserialized.ToString()); } [Test] public void SerializeDocumentExplicitAttributeNamespace() { var original = XDocument.Parse(""); Assert.AreEqual(@"", original.ToString()); var json = JsonConvert.SerializeObject(original); Assert.AreEqual(@"{""MyElement"":{""@xmlns"":""http://example.com""}}", json); var deserialized = JsonConvert.DeserializeObject(json); Assert.AreEqual(@"", deserialized.ToString()); } [Test] public void SerializeDocumentImplicitAttributeNamespace() { var original = new XDocument(new XElement("{http://example.com}MyElement")); Assert.AreEqual(@"", original.ToString()); var json = JsonConvert.SerializeObject(original); Assert.AreEqual(@"{""MyElement"":{""@xmlns"":""http://example.com""}}", json); var deserialized = JsonConvert.DeserializeObject(json); Assert.AreEqual(@"", deserialized.ToString()); } public class Model { public XElement Document { get; set; } } [Test] public void DeserializeDateInElementText() { Model model = new Model(); model.Document = new XElement("Value", new XAttribute("foo", "bar")) { Value = "2001-01-01T11:11:11" }; var serializer = JsonSerializer.Create(new JsonSerializerSettings { Converters = new List(new[] { new XmlNodeConverter() }) }); var json = new StringBuilder(1024); using (var stringWriter = new StringWriter(json, CultureInfo.InvariantCulture)) using (var jsonWriter = new JsonTextWriter(stringWriter)) { jsonWriter.Formatting = Formatting.None; serializer.Serialize(jsonWriter, model); Assert.AreEqual(@"{""Document"":{""Value"":{""@foo"":""bar"",""#text"":""2001-01-01T11:11:11""}}}", json.ToString()); } using (var stringReader = new StringReader(json.ToString())) using (var jsonReader = new JsonTextReader(stringReader)) { var document = (XDocument)serializer.Deserialize(jsonReader, typeof(XDocument)); StringAssert.AreEqual(@" 2001-01-01T11:11:11 ", document.ToString()); } } #endif } } #endif