-Added WriteArrayAttribute to XmlNodeConverter to include an attribute to help round tripping JSON and XML
-Added OmitRootObject to XmlNodeConverter to skip writing the root JSON object when converting XML
This commit is contained in:
@@ -25,7 +25,9 @@
|
||||
|
||||
#if !SILVERLIGHT
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json.Tests.Serialization;
|
||||
using Newtonsoft.Json.Tests.TestObjects;
|
||||
using NUnit.Framework;
|
||||
using Newtonsoft.Json;
|
||||
using System.IO;
|
||||
@@ -423,12 +425,12 @@ namespace Newtonsoft.Json.Tests.Converters
|
||||
string xml = @"<?xml version=""1.0"" standalone=""no""?>
|
||||
<root>
|
||||
<person id=""1"">
|
||||
<name>Alan</name>
|
||||
<url>http://www.google.com</url>
|
||||
<name>Alan</name>
|
||||
<url>http://www.google.com</url>
|
||||
</person>
|
||||
<person id=""2"">
|
||||
<name>Louis</name>
|
||||
<url>http://www.yahoo.com</url>
|
||||
<name>Louis</name>
|
||||
<url>http://www.yahoo.com</url>
|
||||
</person>
|
||||
</root>";
|
||||
|
||||
@@ -651,19 +653,110 @@ namespace Newtonsoft.Json.Tests.Converters
|
||||
[
|
||||
""assets/images/resized/0001/1070/11070v1-max-250x250.jpg"",
|
||||
""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
|
||||
],
|
||||
[
|
||||
""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
|
||||
]
|
||||
]
|
||||
}";
|
||||
|
||||
XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot");
|
||||
|
||||
Assert.AreEqual(@"<myRoot><available_sizes><available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes><available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes></available_sizes><available_sizes><available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes><available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes></available_sizes></myRoot>", newDoc.InnerXml);
|
||||
string xml = IndentXml(newDoc.InnerXml);
|
||||
|
||||
Assert.AreEqual(@"<myRoot>
|
||||
<available_sizes>
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes>
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes>
|
||||
</available_sizes>
|
||||
<available_sizes>
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
|
||||
</available_sizes>
|
||||
<available_sizes>
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
|
||||
</available_sizes>
|
||||
</myRoot>", IndentXml(newDoc.InnerXml));
|
||||
|
||||
#if !NET20
|
||||
XDocument newXDoc = JsonConvert.DeserializeXNode(json, "myRoot");
|
||||
|
||||
Assert.AreEqual(@"<myRoot><available_sizes><available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes><available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes></available_sizes><available_sizes><available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes><available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes></available_sizes></myRoot>", newXDoc.ToString(SaveOptions.DisableFormatting));
|
||||
Assert.AreEqual(@"<myRoot>
|
||||
<available_sizes>
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes>
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes>
|
||||
</available_sizes>
|
||||
<available_sizes>
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
|
||||
</available_sizes>
|
||||
<available_sizes>
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
|
||||
</available_sizes>
|
||||
</myRoot>", IndentXml(newXDoc.ToString(SaveOptions.DisableFormatting)));
|
||||
#endif
|
||||
|
||||
string newJson = JsonConvert.SerializeXmlNode(newDoc, Formatting.Indented);
|
||||
Console.WriteLine(newJson);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RoundTripNestedArrays()
|
||||
{
|
||||
string json = @"{
|
||||
""available_sizes"": [
|
||||
[
|
||||
""assets/images/resized/0001/1070/11070v1-max-150x150.jpg"",
|
||||
""assets/images/resized/0001/1070/11070v1-max-150x150.jpg""
|
||||
],
|
||||
[
|
||||
""assets/images/resized/0001/1070/11070v1-max-250x250.jpg"",
|
||||
""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
|
||||
],
|
||||
[
|
||||
""assets/images/resized/0001/1070/11070v1-max-250x250.jpg""
|
||||
]
|
||||
]
|
||||
}";
|
||||
|
||||
XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot", true);
|
||||
|
||||
Assert.AreEqual(@"<myRoot>
|
||||
<available_sizes json:Array=""true"" xmlns:json=""http://james.newtonking.com/projects/json"">
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes>
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes>
|
||||
</available_sizes>
|
||||
<available_sizes json:Array=""true"" xmlns:json=""http://james.newtonking.com/projects/json"">
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
|
||||
</available_sizes>
|
||||
<available_sizes json:Array=""true"" xmlns:json=""http://james.newtonking.com/projects/json"">
|
||||
<available_sizes json:Array=""true"">assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
|
||||
</available_sizes>
|
||||
</myRoot>", IndentXml(newDoc.InnerXml));
|
||||
|
||||
#if !NET20
|
||||
XDocument newXDoc = JsonConvert.DeserializeXNode(json, "myRoot", true);
|
||||
|
||||
Console.WriteLine(IndentXml(newXDoc.ToString(SaveOptions.DisableFormatting)));
|
||||
|
||||
Assert.AreEqual(@"<myRoot>
|
||||
<available_sizes json:Array=""true"" xmlns:json=""http://james.newtonking.com/projects/json"">
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes>
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-150x150.jpg</available_sizes>
|
||||
</available_sizes>
|
||||
<available_sizes json:Array=""true"" xmlns:json=""http://james.newtonking.com/projects/json"">
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
|
||||
<available_sizes>assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
|
||||
</available_sizes>
|
||||
<available_sizes json:Array=""true"" xmlns:json=""http://james.newtonking.com/projects/json"">
|
||||
<available_sizes json:Array=""true"">assets/images/resized/0001/1070/11070v1-max-250x250.jpg</available_sizes>
|
||||
</available_sizes>
|
||||
</myRoot>", IndentXml(newXDoc.ToString(SaveOptions.DisableFormatting)));
|
||||
#endif
|
||||
|
||||
string newJson = JsonConvert.SerializeXmlNode(newDoc, Formatting.Indented, true);
|
||||
Assert.AreEqual(json, newJson);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -992,6 +1085,140 @@ namespace Newtonsoft.Json.Tests.Converters
|
||||
|
||||
DeserializeXmlNode(json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SingleItemArrayPropertySerialization()
|
||||
{
|
||||
Product product = new Product();
|
||||
|
||||
product.Name = "Apple";
|
||||
product.ExpiryDate = new DateTime(2008, 12, 28, 0, 0, 0, DateTimeKind.Utc);
|
||||
product.Price = 3.99M;
|
||||
product.Sizes = new string[] { "Small" };
|
||||
|
||||
string output = JsonConvert.SerializeObject(product, new IsoDateTimeConverter());
|
||||
|
||||
XmlDocument xmlProduct = JsonConvert.DeserializeXmlNode(output, "product", true);
|
||||
|
||||
Assert.AreEqual(@"<product>
|
||||
<Name>Apple</Name>
|
||||
<ExpiryDate>2008-12-28T00:00:00Z</ExpiryDate>
|
||||
<Price>3.99</Price>
|
||||
<Sizes json:Array=""true"" xmlns:json=""http://james.newtonking.com/projects/json"">Small</Sizes>
|
||||
</product>", IndentXml(xmlProduct.InnerXml));
|
||||
|
||||
string output2 = JsonConvert.SerializeXmlNode(xmlProduct.DocumentElement, Formatting.Indented);
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""product"": {
|
||||
""Name"": ""Apple"",
|
||||
""ExpiryDate"": ""2008-12-28T00:00:00Z"",
|
||||
""Price"": ""3.99"",
|
||||
""Sizes"": [
|
||||
""Small""
|
||||
]
|
||||
}
|
||||
}", output2);
|
||||
}
|
||||
|
||||
public class TestComplexArrayClass
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public IList<Product> Products { get; set; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ComplexSingleItemArrayPropertySerialization()
|
||||
{
|
||||
TestComplexArrayClass o = new TestComplexArrayClass
|
||||
{
|
||||
Name = "Hi",
|
||||
Products = new List<Product>
|
||||
{
|
||||
new Product { Name = "First" }
|
||||
}
|
||||
};
|
||||
|
||||
string output = JsonConvert.SerializeObject(o, new IsoDateTimeConverter());
|
||||
|
||||
XmlDocument xmlProduct = JsonConvert.DeserializeXmlNode(output, "test", true);
|
||||
|
||||
Assert.AreEqual(@"<test>
|
||||
<Name>Hi</Name>
|
||||
<Products json:Array=""true"" xmlns:json=""http://james.newtonking.com/projects/json"">
|
||||
<Name>First</Name>
|
||||
<ExpiryDate>2000-01-01T00:00:00Z</ExpiryDate>
|
||||
<Price>0</Price>
|
||||
<Sizes />
|
||||
</Products>
|
||||
</test>", IndentXml(xmlProduct.InnerXml));
|
||||
|
||||
string output2 = JsonConvert.SerializeXmlNode(xmlProduct.DocumentElement, Formatting.Indented, true);
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""Name"": ""Hi"",
|
||||
""Products"": [
|
||||
{
|
||||
""Name"": ""First"",
|
||||
""ExpiryDate"": ""2000-01-01T00:00:00Z"",
|
||||
""Price"": ""0"",
|
||||
""Sizes"": null
|
||||
}
|
||||
]
|
||||
}", output2);
|
||||
}
|
||||
|
||||
private string IndentXml(string xml)
|
||||
{
|
||||
XmlReader reader = XmlReader.Create(new StringReader(xml));
|
||||
|
||||
StringWriter sw = new StringWriter();
|
||||
XmlWriter writer = XmlWriter.Create(sw, new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true });
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
writer.WriteNode(reader, false);
|
||||
}
|
||||
|
||||
writer.Flush();
|
||||
|
||||
return sw.ToString();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OmitRootObject()
|
||||
{
|
||||
string xml = @"<test>
|
||||
<Name>Hi</Name>
|
||||
<Name>Hi</Name>
|
||||
<Products json:Array=""true"" xmlns:json=""http://james.newtonking.com/projects/json"">
|
||||
<Name>First</Name>
|
||||
<ExpiryDate>2000-01-01T00:00:00Z</ExpiryDate>
|
||||
<Price>0</Price>
|
||||
<Sizes />
|
||||
</Products>
|
||||
</test>";
|
||||
|
||||
XmlDocument d = new XmlDocument();
|
||||
d.LoadXml(xml);
|
||||
|
||||
string output = JsonConvert.SerializeXmlNode(d, Formatting.Indented, true);
|
||||
|
||||
Assert.AreEqual(@"{
|
||||
""Name"": [
|
||||
""Hi"",
|
||||
""Hi""
|
||||
],
|
||||
""Products"": [
|
||||
{
|
||||
""Name"": ""First"",
|
||||
""ExpiryDate"": ""2000-01-01T00:00:00Z"",
|
||||
""Price"": ""0"",
|
||||
""Sizes"": null
|
||||
}
|
||||
]
|
||||
}", output);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -136,6 +136,11 @@ namespace Newtonsoft.Json.Converters
|
||||
|
||||
_element.SetAttributeNode((XmlAttribute) xmlAttributeWrapper.WrappedNode);
|
||||
}
|
||||
|
||||
public string GetPrefixOfNamespace(string namespaceURI)
|
||||
{
|
||||
return _element.GetPrefixOfNamespace(namespaceURI);
|
||||
}
|
||||
}
|
||||
|
||||
internal class XmlDeclarationWrapper : XmlNodeWrapper, IXmlDeclaration
|
||||
@@ -294,6 +299,7 @@ namespace Newtonsoft.Json.Converters
|
||||
internal interface IXmlElement : IXmlNode
|
||||
{
|
||||
void SetAttributeNode(IXmlNode attribute);
|
||||
string GetPrefixOfNamespace(string namespaceURI);
|
||||
}
|
||||
|
||||
internal interface IXmlNode
|
||||
@@ -726,6 +732,11 @@ namespace Newtonsoft.Json.Converters
|
||||
{
|
||||
get { return Element.Name.NamespaceName; }
|
||||
}
|
||||
|
||||
public string GetPrefixOfNamespace(string namespaceURI)
|
||||
{
|
||||
return Element.GetPrefixOfNamespace(namespaceURI);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
@@ -749,6 +760,19 @@ namespace Newtonsoft.Json.Converters
|
||||
/// <value>The name of the deserialize root element.</value>
|
||||
public string DeserializeRootElementName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a flag to indicate whether to write the Json.NET array attribute.
|
||||
/// This attribute helps preserve arrays when converting the written XML back to JSON.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if the array attibute is written to the XML; otherwise, <c>false</c>.</value>
|
||||
public bool WriteArrayAttribute { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to write the root JSON object.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if the JSON root object is omitted; otherwise, <c>false</c>.</value>
|
||||
public bool OmitRootObject { get; set; }
|
||||
|
||||
#region Writing
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
@@ -763,9 +787,13 @@ namespace Newtonsoft.Json.Converters
|
||||
XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
|
||||
PushParentNamespaces(node, manager);
|
||||
|
||||
writer.WriteStartObject();
|
||||
SerializeNode(writer, node, manager, true);
|
||||
writer.WriteEndObject();
|
||||
if (!OmitRootObject)
|
||||
writer.WriteStartObject();
|
||||
|
||||
SerializeNode(writer, node, manager, !OmitRootObject);
|
||||
|
||||
if (!OmitRootObject)
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
private IXmlNode WrapXml(object value)
|
||||
@@ -856,7 +884,16 @@ namespace Newtonsoft.Json.Converters
|
||||
}
|
||||
}
|
||||
|
||||
private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager)
|
||||
private bool IsArray(IXmlNode node)
|
||||
{
|
||||
IXmlNode jsonArrayAttribute = (node.Attributes != null)
|
||||
? node.Attributes.SingleOrDefault(a => a.LocalName == "Array" && a.NamespaceURI == JsonNamespaceUri)
|
||||
: null;
|
||||
|
||||
return (jsonArrayAttribute != null && XmlConvert.ToBoolean(jsonArrayAttribute.Value));
|
||||
}
|
||||
|
||||
private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
|
||||
{
|
||||
// group nodes together by name
|
||||
Dictionary<string, List<IXmlNode>> nodesGroupedByName = new Dictionary<string, List<IXmlNode>>();
|
||||
@@ -885,14 +922,7 @@ namespace Newtonsoft.Json.Converters
|
||||
|
||||
if (groupedNodes.Count == 1)
|
||||
{
|
||||
IXmlNode singleNode = groupedNodes[0];
|
||||
IXmlNode jsonArrayAttribute = (singleNode.Attributes != null)
|
||||
? singleNode.Attributes.SingleOrDefault(a => a.LocalName == "Array" && a.NamespaceURI == JsonNamespaceUri)
|
||||
: null;
|
||||
if (jsonArrayAttribute != null)
|
||||
writeArray = XmlConvert.ToBoolean(jsonArrayAttribute.Value);
|
||||
else
|
||||
writeArray = false;
|
||||
writeArray = IsArray(groupedNodes[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -901,12 +931,15 @@ namespace Newtonsoft.Json.Converters
|
||||
|
||||
if (!writeArray)
|
||||
{
|
||||
SerializeNode(writer, groupedNodes[0], manager, true);
|
||||
SerializeNode(writer, groupedNodes[0], manager, writePropertyName);
|
||||
}
|
||||
else
|
||||
{
|
||||
string elementNames = nodeNameGroup.Key;
|
||||
writer.WritePropertyName(elementNames);
|
||||
|
||||
if (writePropertyName)
|
||||
writer.WritePropertyName(elementNames);
|
||||
|
||||
writer.WriteStartArray();
|
||||
|
||||
for (int i = 0; i < groupedNodes.Count; i++)
|
||||
@@ -925,47 +958,54 @@ namespace Newtonsoft.Json.Converters
|
||||
{
|
||||
case XmlNodeType.Document:
|
||||
case XmlNodeType.DocumentFragment:
|
||||
SerializeGroupedNodes(writer, node, manager);
|
||||
SerializeGroupedNodes(writer, node, manager, writePropertyName);
|
||||
break;
|
||||
case XmlNodeType.Element:
|
||||
foreach (IXmlNode attribute in node.Attributes)
|
||||
if (IsArray(node) && node.ChildNodes.All(n => n.LocalName == node.LocalName))
|
||||
{
|
||||
if (attribute.NamespaceURI == "http://www.w3.org/2000/xmlns/")
|
||||
{
|
||||
string prefix = (attribute.LocalName != "xmlns")
|
||||
? attribute.LocalName
|
||||
: string.Empty;
|
||||
|
||||
manager.AddNamespace(prefix, attribute.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (writePropertyName)
|
||||
writer.WritePropertyName(GetPropertyName(node, manager));
|
||||
|
||||
if (ValueAttributes(node.Attributes).Count() == 0 && node.ChildNodes.Count == 1
|
||||
&& node.ChildNodes[0].NodeType == XmlNodeType.Text)
|
||||
{
|
||||
// write elements with a single text child as a name value pair
|
||||
writer.WriteValue(node.ChildNodes[0].Value);
|
||||
}
|
||||
else if (node.ChildNodes.Count == 0 && CollectionUtils.IsNullOrEmpty(node.Attributes))
|
||||
{
|
||||
// empty element
|
||||
writer.WriteNull();
|
||||
SerializeGroupedNodes(writer, node, manager, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
|
||||
for (int i = 0; i < node.Attributes.Count; i++)
|
||||
foreach (IXmlNode attribute in node.Attributes)
|
||||
{
|
||||
SerializeNode(writer, node.Attributes[i], manager, true);
|
||||
if (attribute.NamespaceURI == "http://www.w3.org/2000/xmlns/")
|
||||
{
|
||||
string prefix = (attribute.LocalName != "xmlns")
|
||||
? attribute.LocalName
|
||||
: string.Empty;
|
||||
|
||||
manager.AddNamespace(prefix, attribute.Value);
|
||||
}
|
||||
}
|
||||
|
||||
SerializeGroupedNodes(writer, node, manager);
|
||||
if (writePropertyName)
|
||||
writer.WritePropertyName(GetPropertyName(node, manager));
|
||||
|
||||
writer.WriteEndObject();
|
||||
if (ValueAttributes(node.Attributes).Count() == 0 && node.ChildNodes.Count == 1
|
||||
&& node.ChildNodes[0].NodeType == XmlNodeType.Text)
|
||||
{
|
||||
// write elements with a single text child as a name value pair
|
||||
writer.WriteValue(node.ChildNodes[0].Value);
|
||||
}
|
||||
else if (node.ChildNodes.Count == 0 && CollectionUtils.IsNullOrEmpty(node.Attributes))
|
||||
{
|
||||
// empty element
|
||||
writer.WriteNull();
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
|
||||
for (int i = 0; i < node.Attributes.Count; i++)
|
||||
{
|
||||
SerializeNode(writer, node.Attributes[i], manager, true);
|
||||
}
|
||||
|
||||
SerializeGroupedNodes(writer, node, manager, true);
|
||||
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1116,6 +1156,7 @@ namespace Newtonsoft.Json.Converters
|
||||
{
|
||||
if (reader.TokenType == JsonToken.StartArray)
|
||||
{
|
||||
// handle nested arrays
|
||||
ReadArrayElements(reader, document, propertyName, currentNode, manager);
|
||||
return;
|
||||
}
|
||||
@@ -1200,10 +1241,39 @@ namespace Newtonsoft.Json.Converters
|
||||
|
||||
currentNode.AppendChild(nestedArrayElement);
|
||||
|
||||
int count = 0;
|
||||
while (reader.Read() && reader.TokenType != JsonToken.EndArray)
|
||||
{
|
||||
DeserializeValue(reader, document, manager, propertyName, nestedArrayElement);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (WriteArrayAttribute)
|
||||
{
|
||||
AddJsonArrayAttribute(nestedArrayElement, document);
|
||||
}
|
||||
|
||||
if (count == 1 && WriteArrayAttribute)
|
||||
{
|
||||
IXmlElement arrayElement = nestedArrayElement.ChildNodes.CastValid<IXmlElement>().Single(n => n.LocalName == propertyName);
|
||||
AddJsonArrayAttribute(arrayElement, document);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddJsonArrayAttribute(IXmlElement element, IXmlDocument document)
|
||||
{
|
||||
element.SetAttributeNode(document.CreateAttribute("json:Array", JsonNamespaceUri, "true"));
|
||||
|
||||
#if !NET20
|
||||
// linq to xml doesn't automatically include prefixes via the namespace manager
|
||||
if (element is XElementWrapper)
|
||||
{
|
||||
if (element.GetPrefixOfNamespace(JsonNamespaceUri) == null)
|
||||
{
|
||||
element.SetAttributeNode(document.CreateAttribute("xmlns:json", "http://www.w3.org/2000/xmlns/", JsonNamespaceUri));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private Dictionary<string, string> ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager)
|
||||
@@ -1355,9 +1425,17 @@ namespace Newtonsoft.Json.Converters
|
||||
|
||||
if (reader.TokenType == JsonToken.StartArray)
|
||||
{
|
||||
int count = 0;
|
||||
while (reader.Read() && reader.TokenType != JsonToken.EndArray)
|
||||
{
|
||||
DeserializeValue(reader, document, manager, propertyName, currentNode);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 1 && WriteArrayAttribute)
|
||||
{
|
||||
IXmlElement arrayElement = currentNode.ChildNodes.CastValid<IXmlElement>().Single(n => n.LocalName == propertyName);
|
||||
AddJsonArrayAttribute(arrayElement, document);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -785,6 +785,20 @@ namespace Newtonsoft.Json
|
||||
return SerializeObject(node, formatting, converter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the XML node to a JSON string.
|
||||
/// </summary>
|
||||
/// <param name="node">The node to serialize.</param>
|
||||
/// <param name="formatting">Indicates how the output is formatted.</param>
|
||||
/// <param name="omitRootObject">Omits writing the root object.</param>
|
||||
/// <returns>A JSON string of the XmlNode.</returns>
|
||||
public static string SerializeXmlNode(XmlNode node, Formatting formatting, bool omitRootObject)
|
||||
{
|
||||
XmlNodeConverter converter = new XmlNodeConverter { OmitRootObject = omitRootObject };
|
||||
|
||||
return SerializeObject(node, formatting, converter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the XmlNode from a JSON string.
|
||||
/// </summary>
|
||||
@@ -802,9 +816,25 @@ namespace Newtonsoft.Json
|
||||
/// <param name="deserializeRootElementName">The name of the root element to append when deserializing.</param>
|
||||
/// <returns>The deserialized XmlNode</returns>
|
||||
public static XmlDocument DeserializeXmlNode(string value, string deserializeRootElementName)
|
||||
{
|
||||
return DeserializeXmlNode(value, deserializeRootElementName, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the XmlNode from a JSON string nested in a root elment.
|
||||
/// </summary>
|
||||
/// <param name="value">The JSON string.</param>
|
||||
/// <param name="deserializeRootElementName">The name of the root element to append when deserializing.</param>
|
||||
/// <param name="writeArrayAttribute">
|
||||
/// A flag to indicate whether to write the Json.NET array attribute.
|
||||
/// This attribute helps preserve arrays when converting the written XML back to JSON.
|
||||
/// </param>
|
||||
/// <returns>The deserialized XmlNode</returns>
|
||||
public static XmlDocument DeserializeXmlNode(string value, string deserializeRootElementName, bool writeArrayAttribute)
|
||||
{
|
||||
XmlNodeConverter converter = new XmlNodeConverter();
|
||||
converter.DeserializeRootElementName = deserializeRootElementName;
|
||||
converter.WriteArrayAttribute = writeArrayAttribute;
|
||||
|
||||
return (XmlDocument)DeserializeObject(value, typeof(XmlDocument), converter);
|
||||
}
|
||||
@@ -829,7 +859,19 @@ namespace Newtonsoft.Json
|
||||
/// <returns>A JSON string of the XNode.</returns>
|
||||
public static string SerializeXNode(XObject node, Formatting formatting)
|
||||
{
|
||||
XmlNodeConverter converter = new XmlNodeConverter();
|
||||
return SerializeXNode(node, formatting, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the <see cref="XNode"/> to a JSON string.
|
||||
/// </summary>
|
||||
/// <param name="node">The node to serialize.</param>
|
||||
/// <param name="formatting">Indicates how the output is formatted.</param>
|
||||
/// <param name="omitRootObject">Omits writing the root object.</param>
|
||||
/// <returns>A JSON string of the XNode.</returns>
|
||||
public static string SerializeXNode(XObject node, Formatting formatting, bool omitRootObject)
|
||||
{
|
||||
XmlNodeConverter converter = new XmlNodeConverter { OmitRootObject = omitRootObject };
|
||||
|
||||
return SerializeObject(node, formatting, converter);
|
||||
}
|
||||
@@ -851,9 +893,25 @@ namespace Newtonsoft.Json
|
||||
/// <param name="deserializeRootElementName">The name of the root element to append when deserializing.</param>
|
||||
/// <returns>The deserialized XNode</returns>
|
||||
public static XDocument DeserializeXNode(string value, string deserializeRootElementName)
|
||||
{
|
||||
return DeserializeXNode(value, deserializeRootElementName, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the <see cref="XNode"/> from a JSON string nested in a root elment.
|
||||
/// </summary>
|
||||
/// <param name="value">The JSON string.</param>
|
||||
/// <param name="deserializeRootElementName">The name of the root element to append when deserializing.</param>
|
||||
/// <param name="writeArrayAttribute">
|
||||
/// A flag to indicate whether to write the Json.NET array attribute.
|
||||
/// This attribute helps preserve arrays when converting the written XML back to JSON.
|
||||
/// </param>
|
||||
/// <returns>The deserialized XNode</returns>
|
||||
public static XDocument DeserializeXNode(string value, string deserializeRootElementName, bool writeArrayAttribute)
|
||||
{
|
||||
XmlNodeConverter converter = new XmlNodeConverter();
|
||||
converter.DeserializeRootElementName = deserializeRootElementName;
|
||||
converter.WriteArrayAttribute = writeArrayAttribute;
|
||||
|
||||
return (XDocument)DeserializeObject(value, typeof(XDocument), converter);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user