using System;
|
using System.Collections.Generic;
|
using System.Globalization;
|
using System.Numerics;
|
using System.Xml;
|
using System.Xml.Linq;
|
using DPumpHydr.WinFrmUI.WenSkin.Json.Utilities;
|
|
namespace DPumpHydr.WinFrmUI.WenSkin.Json.Converters
|
{
|
/// <summary>
|
/// Converts XML to and from JSON.
|
/// </summary>
|
public class XmlNodeConverter : JsonConverter
|
{
|
private const string TextName = "#text";
|
|
private const string CommentName = "#comment";
|
|
private const string CDataName = "#cdata-section";
|
|
private const string WhitespaceName = "#whitespace";
|
|
private const string SignificantWhitespaceName = "#significant-whitespace";
|
|
private const string DeclarationName = "?xml";
|
|
private const string JsonNamespaceUri = "http://james.newtonking.com/projects/json";
|
|
/// <summary>
|
/// Gets or sets the name of the root element to insert when deserializing to XML if the JSON structure has produces multiple root elements.
|
/// </summary>
|
/// <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; }
|
|
/// <summary>
|
/// Writes the JSON representation of the object.
|
/// </summary>
|
/// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter" /> to write to.</param>
|
/// <param name="serializer">The calling serializer.</param>
|
/// <param name="value">The value.</param>
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
{
|
IXmlNode node = WrapXml(value);
|
XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
|
PushParentNamespaces(node, manager);
|
if (!OmitRootObject)
|
{
|
writer.WriteStartObject();
|
}
|
SerializeNode(writer, node, manager, !OmitRootObject);
|
if (!OmitRootObject)
|
{
|
writer.WriteEndObject();
|
}
|
}
|
|
private IXmlNode WrapXml(object value)
|
{
|
if (value is XObject)
|
{
|
return XContainerWrapper.WrapNode((XObject)value);
|
}
|
if (value is XmlNode)
|
{
|
return XmlNodeWrapper.WrapNode((XmlNode)value);
|
}
|
throw new ArgumentException("Value must be an XML object.", "value");
|
}
|
|
private void PushParentNamespaces(IXmlNode node, XmlNamespaceManager manager)
|
{
|
List<IXmlNode> list = null;
|
IXmlNode xmlNode = node;
|
while ((xmlNode = xmlNode.ParentNode) != null)
|
{
|
if (xmlNode.NodeType == XmlNodeType.Element)
|
{
|
if (list == null)
|
{
|
list = new List<IXmlNode>();
|
}
|
list.Add(xmlNode);
|
}
|
}
|
if (list == null)
|
{
|
return;
|
}
|
list.Reverse();
|
foreach (IXmlNode item in list)
|
{
|
manager.PushScope();
|
foreach (IXmlNode attribute in item.Attributes)
|
{
|
if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/" && attribute.LocalName != "xmlns")
|
{
|
manager.AddNamespace(attribute.LocalName, attribute.Value);
|
}
|
}
|
}
|
}
|
|
private string ResolveFullName(IXmlNode node, XmlNamespaceManager manager)
|
{
|
string text = ((node.NamespaceUri == null || (node.LocalName == "xmlns" && node.NamespaceUri == "http://www.w3.org/2000/xmlns/")) ? null : manager.LookupPrefix(node.NamespaceUri));
|
if (!string.IsNullOrEmpty(text))
|
{
|
return text + ":" + XmlConvert.DecodeName(node.LocalName);
|
}
|
return XmlConvert.DecodeName(node.LocalName);
|
}
|
|
private string GetPropertyName(IXmlNode node, XmlNamespaceManager manager)
|
{
|
switch (node.NodeType)
|
{
|
case XmlNodeType.Attribute:
|
if (node.NamespaceUri == "http://james.newtonking.com/projects/json")
|
{
|
return "$" + node.LocalName;
|
}
|
return "@" + ResolveFullName(node, manager);
|
case XmlNodeType.CDATA:
|
return "#cdata-section";
|
case XmlNodeType.Comment:
|
return "#comment";
|
case XmlNodeType.Element:
|
if (node.NamespaceUri == "http://james.newtonking.com/projects/json")
|
{
|
return "$" + node.LocalName;
|
}
|
return ResolveFullName(node, manager);
|
case XmlNodeType.ProcessingInstruction:
|
return "?" + ResolveFullName(node, manager);
|
case XmlNodeType.DocumentType:
|
return "!" + ResolveFullName(node, manager);
|
case XmlNodeType.XmlDeclaration:
|
return "?xml";
|
case XmlNodeType.SignificantWhitespace:
|
return "#significant-whitespace";
|
case XmlNodeType.Text:
|
return "#text";
|
case XmlNodeType.Whitespace:
|
return "#whitespace";
|
default:
|
throw new JsonSerializationException("Unexpected XmlNodeType when getting node name: " + node.NodeType);
|
}
|
}
|
|
private bool IsArray(IXmlNode node)
|
{
|
if (node.Attributes != null)
|
{
|
foreach (IXmlNode attribute in node.Attributes)
|
{
|
if (attribute.LocalName == "Array" && attribute.NamespaceUri == "http://james.newtonking.com/projects/json")
|
{
|
return XmlConvert.ToBoolean(attribute.Value);
|
}
|
}
|
}
|
return false;
|
}
|
|
private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
|
{
|
Dictionary<string, List<IXmlNode>> dictionary = new Dictionary<string, List<IXmlNode>>();
|
for (int i = 0; i < node.ChildNodes.Count; i++)
|
{
|
IXmlNode xmlNode = node.ChildNodes[i];
|
string propertyName = GetPropertyName(xmlNode, manager);
|
if (!dictionary.TryGetValue(propertyName, out var value))
|
{
|
value = new List<IXmlNode>();
|
dictionary.Add(propertyName, value);
|
}
|
value.Add(xmlNode);
|
}
|
foreach (KeyValuePair<string, List<IXmlNode>> item in dictionary)
|
{
|
List<IXmlNode> value2 = item.Value;
|
if (value2.Count == 1 && !IsArray(value2[0]))
|
{
|
SerializeNode(writer, value2[0], manager, writePropertyName);
|
continue;
|
}
|
string key = item.Key;
|
if (writePropertyName)
|
{
|
writer.WritePropertyName(key);
|
}
|
writer.WriteStartArray();
|
for (int j = 0; j < value2.Count; j++)
|
{
|
SerializeNode(writer, value2[j], manager, writePropertyName: false);
|
}
|
writer.WriteEndArray();
|
}
|
}
|
|
private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
|
{
|
switch (node.NodeType)
|
{
|
case XmlNodeType.Document:
|
case XmlNodeType.DocumentFragment:
|
SerializeGroupedNodes(writer, node, manager, writePropertyName);
|
break;
|
case XmlNodeType.Element:
|
if (IsArray(node) && AllSameName(node) && node.ChildNodes.Count > 0)
|
{
|
SerializeGroupedNodes(writer, node, manager, writePropertyName: false);
|
break;
|
}
|
manager.PushScope();
|
foreach (IXmlNode attribute in node.Attributes)
|
{
|
if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/")
|
{
|
string prefix = ((attribute.LocalName != "xmlns") ? XmlConvert.DecodeName(attribute.LocalName) : string.Empty);
|
string value = attribute.Value;
|
manager.AddNamespace(prefix, value);
|
}
|
}
|
if (writePropertyName)
|
{
|
writer.WritePropertyName(GetPropertyName(node, manager));
|
}
|
if (!ValueAttributes(node.Attributes) && node.ChildNodes.Count == 1 && node.ChildNodes[0].NodeType == XmlNodeType.Text)
|
{
|
writer.WriteValue(node.ChildNodes[0].Value);
|
}
|
else if (node.ChildNodes.Count == 0 && CollectionUtils.IsNullOrEmpty(node.Attributes))
|
{
|
if (((IXmlElement)node).IsEmpty)
|
{
|
writer.WriteNull();
|
}
|
else
|
{
|
writer.WriteValue(string.Empty);
|
}
|
}
|
else
|
{
|
writer.WriteStartObject();
|
for (int i = 0; i < node.Attributes.Count; i++)
|
{
|
SerializeNode(writer, node.Attributes[i], manager, writePropertyName: true);
|
}
|
SerializeGroupedNodes(writer, node, manager, writePropertyName: true);
|
writer.WriteEndObject();
|
}
|
manager.PopScope();
|
break;
|
case XmlNodeType.Comment:
|
if (writePropertyName)
|
{
|
writer.WriteComment(node.Value);
|
}
|
break;
|
case XmlNodeType.Attribute:
|
case XmlNodeType.Text:
|
case XmlNodeType.CDATA:
|
case XmlNodeType.ProcessingInstruction:
|
case XmlNodeType.Whitespace:
|
case XmlNodeType.SignificantWhitespace:
|
if ((!(node.NamespaceUri == "http://www.w3.org/2000/xmlns/") || !(node.Value == "http://james.newtonking.com/projects/json")) && (!(node.NamespaceUri == "http://james.newtonking.com/projects/json") || !(node.LocalName == "Array")))
|
{
|
if (writePropertyName)
|
{
|
writer.WritePropertyName(GetPropertyName(node, manager));
|
}
|
writer.WriteValue(node.Value);
|
}
|
break;
|
case XmlNodeType.XmlDeclaration:
|
{
|
IXmlDeclaration xmlDeclaration = (IXmlDeclaration)node;
|
writer.WritePropertyName(GetPropertyName(node, manager));
|
writer.WriteStartObject();
|
if (!string.IsNullOrEmpty(xmlDeclaration.Version))
|
{
|
writer.WritePropertyName("@version");
|
writer.WriteValue(xmlDeclaration.Version);
|
}
|
if (!string.IsNullOrEmpty(xmlDeclaration.Encoding))
|
{
|
writer.WritePropertyName("@encoding");
|
writer.WriteValue(xmlDeclaration.Encoding);
|
}
|
if (!string.IsNullOrEmpty(xmlDeclaration.Standalone))
|
{
|
writer.WritePropertyName("@standalone");
|
writer.WriteValue(xmlDeclaration.Standalone);
|
}
|
writer.WriteEndObject();
|
break;
|
}
|
case XmlNodeType.DocumentType:
|
{
|
IXmlDocumentType xmlDocumentType = (IXmlDocumentType)node;
|
writer.WritePropertyName(GetPropertyName(node, manager));
|
writer.WriteStartObject();
|
if (!string.IsNullOrEmpty(xmlDocumentType.Name))
|
{
|
writer.WritePropertyName("@name");
|
writer.WriteValue(xmlDocumentType.Name);
|
}
|
if (!string.IsNullOrEmpty(xmlDocumentType.Public))
|
{
|
writer.WritePropertyName("@public");
|
writer.WriteValue(xmlDocumentType.Public);
|
}
|
if (!string.IsNullOrEmpty(xmlDocumentType.System))
|
{
|
writer.WritePropertyName("@system");
|
writer.WriteValue(xmlDocumentType.System);
|
}
|
if (!string.IsNullOrEmpty(xmlDocumentType.InternalSubset))
|
{
|
writer.WritePropertyName("@internalSubset");
|
writer.WriteValue(xmlDocumentType.InternalSubset);
|
}
|
writer.WriteEndObject();
|
break;
|
}
|
default:
|
throw new JsonSerializationException("Unexpected XmlNodeType when serializing nodes: " + node.NodeType);
|
}
|
}
|
|
private static bool AllSameName(IXmlNode node)
|
{
|
foreach (IXmlNode childNode in node.ChildNodes)
|
{
|
if (childNode.LocalName != node.LocalName)
|
{
|
return false;
|
}
|
}
|
return true;
|
}
|
|
/// <summary>
|
/// Reads the JSON representation of the object.
|
/// </summary>
|
/// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader" /> to read from.</param>
|
/// <param name="objectType">Type of the object.</param>
|
/// <param name="existingValue">The existing value of object being read.</param>
|
/// <param name="serializer">The calling serializer.</param>
|
/// <returns>The object value.</returns>
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
{
|
if (reader.TokenType == JsonToken.Null)
|
{
|
return null;
|
}
|
XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
|
IXmlDocument xmlDocument = null;
|
IXmlNode xmlNode = null;
|
if (typeof(XObject).IsAssignableFrom(objectType))
|
{
|
if (objectType != typeof(XDocument) && objectType != typeof(XElement))
|
{
|
throw new JsonSerializationException("XmlNodeConverter only supports deserializing XDocument or XElement.");
|
}
|
xmlDocument = new XDocumentWrapper(new XDocument());
|
xmlNode = xmlDocument;
|
}
|
if (typeof(XmlNode).IsAssignableFrom(objectType))
|
{
|
if (objectType != typeof(XmlDocument))
|
{
|
throw new JsonSerializationException("XmlNodeConverter only supports deserializing XmlDocuments");
|
}
|
xmlDocument = new XmlDocumentWrapper(new XmlDocument
|
{
|
XmlResolver = null
|
});
|
xmlNode = xmlDocument;
|
}
|
if (xmlDocument == null || xmlNode == null)
|
{
|
throw new JsonSerializationException("Unexpected type when converting XML: " + objectType);
|
}
|
if (reader.TokenType != JsonToken.StartObject)
|
{
|
throw new JsonSerializationException("XmlNodeConverter can only convert JSON that begins with an object.");
|
}
|
if (!string.IsNullOrEmpty(DeserializeRootElementName))
|
{
|
ReadElement(reader, xmlDocument, xmlNode, DeserializeRootElementName, manager);
|
}
|
else
|
{
|
reader.Read();
|
DeserializeNode(reader, xmlDocument, manager, xmlNode);
|
}
|
if (objectType == typeof(XElement))
|
{
|
XElement obj = (XElement)xmlDocument.DocumentElement.WrappedNode;
|
obj.Remove();
|
return obj;
|
}
|
return xmlDocument.WrappedNode;
|
}
|
|
private void DeserializeValue(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, string propertyName, IXmlNode currentNode)
|
{
|
switch (propertyName)
|
{
|
case "#text":
|
currentNode.AppendChild(document.CreateTextNode(reader.Value.ToString()));
|
return;
|
case "#cdata-section":
|
currentNode.AppendChild(document.CreateCDataSection(reader.Value.ToString()));
|
return;
|
case "#whitespace":
|
currentNode.AppendChild(document.CreateWhitespace(reader.Value.ToString()));
|
return;
|
case "#significant-whitespace":
|
currentNode.AppendChild(document.CreateSignificantWhitespace(reader.Value.ToString()));
|
return;
|
}
|
if (!string.IsNullOrEmpty(propertyName) && propertyName[0] == '?')
|
{
|
CreateInstruction(reader, document, currentNode, propertyName);
|
}
|
else if (string.Equals(propertyName, "!DOCTYPE", StringComparison.OrdinalIgnoreCase))
|
{
|
CreateDocumentType(reader, document, currentNode);
|
}
|
else if (reader.TokenType == JsonToken.StartArray)
|
{
|
ReadArrayElements(reader, document, propertyName, currentNode, manager);
|
}
|
else
|
{
|
ReadElement(reader, document, currentNode, propertyName, manager);
|
}
|
}
|
|
private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, XmlNamespaceManager manager)
|
{
|
if (string.IsNullOrEmpty(propertyName))
|
{
|
throw JsonSerializationException.Create(reader, "XmlNodeConverter cannot convert JSON with an empty property name to XML.");
|
}
|
Dictionary<string, string> attributeNameValues = ReadAttributeElements(reader, manager);
|
string prefix = MiscellaneousUtils.GetPrefix(propertyName);
|
if (propertyName.StartsWith('@'))
|
{
|
string text = propertyName.Substring(1);
|
string prefix2 = MiscellaneousUtils.GetPrefix(text);
|
AddAttribute(reader, document, currentNode, text, manager, prefix2);
|
return;
|
}
|
if (propertyName.StartsWith('$'))
|
{
|
switch (propertyName)
|
{
|
case "$values":
|
propertyName = propertyName.Substring(1);
|
prefix = manager.LookupPrefix("http://james.newtonking.com/projects/json");
|
CreateElement(reader, document, currentNode, propertyName, manager, prefix, attributeNameValues);
|
return;
|
case "$id":
|
case "$ref":
|
case "$type":
|
case "$value":
|
{
|
string attributeName = propertyName.Substring(1);
|
string attributePrefix = manager.LookupPrefix("http://james.newtonking.com/projects/json");
|
AddAttribute(reader, document, currentNode, attributeName, manager, attributePrefix);
|
return;
|
}
|
}
|
}
|
CreateElement(reader, document, currentNode, propertyName, manager, prefix, attributeNameValues);
|
}
|
|
private void CreateElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string elementName, XmlNamespaceManager manager, string elementPrefix, Dictionary<string, string> attributeNameValues)
|
{
|
IXmlElement xmlElement = CreateElement(elementName, document, elementPrefix, manager);
|
currentNode.AppendChild(xmlElement);
|
foreach (KeyValuePair<string, string> attributeNameValue in attributeNameValues)
|
{
|
string text = XmlConvert.EncodeName(attributeNameValue.Key);
|
string prefix = MiscellaneousUtils.GetPrefix(attributeNameValue.Key);
|
IXmlNode attributeNode = ((!string.IsNullOrEmpty(prefix)) ? document.CreateAttribute(text, manager.LookupNamespace(prefix) ?? string.Empty, attributeNameValue.Value) : document.CreateAttribute(text, attributeNameValue.Value));
|
xmlElement.SetAttributeNode(attributeNode);
|
}
|
if (reader.TokenType == JsonToken.String || reader.TokenType == JsonToken.Integer || reader.TokenType == JsonToken.Float || reader.TokenType == JsonToken.Boolean || reader.TokenType == JsonToken.Date)
|
{
|
string text2 = ConvertTokenToXmlValue(reader);
|
if (text2 != null)
|
{
|
xmlElement.AppendChild(document.CreateTextNode(text2));
|
}
|
}
|
else if (reader.TokenType != JsonToken.Null)
|
{
|
if (reader.TokenType != JsonToken.EndObject)
|
{
|
manager.PushScope();
|
DeserializeNode(reader, document, manager, xmlElement);
|
manager.PopScope();
|
}
|
manager.RemoveNamespace(string.Empty, manager.DefaultNamespace);
|
}
|
}
|
|
private static void AddAttribute(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string attributeName, XmlNamespaceManager manager, string attributePrefix)
|
{
|
string text = XmlConvert.EncodeName(attributeName);
|
string value = reader.Value.ToString();
|
IXmlNode attributeNode = ((!string.IsNullOrEmpty(attributePrefix)) ? document.CreateAttribute(text, manager.LookupNamespace(attributePrefix), value) : document.CreateAttribute(text, value));
|
((IXmlElement)currentNode).SetAttributeNode(attributeNode);
|
}
|
|
private string ConvertTokenToXmlValue(JsonReader reader)
|
{
|
if (reader.TokenType == JsonToken.String)
|
{
|
if (reader.Value == null)
|
{
|
return null;
|
}
|
return reader.Value.ToString();
|
}
|
if (reader.TokenType == JsonToken.Integer)
|
{
|
if (reader.Value is BigInteger)
|
{
|
return ((BigInteger)reader.Value).ToString(CultureInfo.InvariantCulture);
|
}
|
return XmlConvert.ToString(Convert.ToInt64(reader.Value, CultureInfo.InvariantCulture));
|
}
|
if (reader.TokenType == JsonToken.Float)
|
{
|
if (reader.Value is decimal)
|
{
|
return XmlConvert.ToString((decimal)reader.Value);
|
}
|
if (reader.Value is float)
|
{
|
return XmlConvert.ToString((float)reader.Value);
|
}
|
return XmlConvert.ToString(Convert.ToDouble(reader.Value, CultureInfo.InvariantCulture));
|
}
|
if (reader.TokenType == JsonToken.Boolean)
|
{
|
return XmlConvert.ToString(Convert.ToBoolean(reader.Value, CultureInfo.InvariantCulture));
|
}
|
if (reader.TokenType == JsonToken.Date)
|
{
|
if (reader.Value is DateTimeOffset)
|
{
|
return XmlConvert.ToString((DateTimeOffset)reader.Value);
|
}
|
DateTime dateTime = Convert.ToDateTime(reader.Value, CultureInfo.InvariantCulture);
|
return XmlConvert.ToString(dateTime, DateTimeUtils.ToSerializationMode(dateTime.Kind));
|
}
|
if (reader.TokenType == JsonToken.Null)
|
{
|
return null;
|
}
|
throw JsonSerializationException.Create(reader, "Cannot get an XML string value from token type '{0}'.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
}
|
|
private void ReadArrayElements(JsonReader reader, IXmlDocument document, string propertyName, IXmlNode currentNode, XmlNamespaceManager manager)
|
{
|
string prefix = MiscellaneousUtils.GetPrefix(propertyName);
|
IXmlElement xmlElement = CreateElement(propertyName, document, prefix, manager);
|
currentNode.AppendChild(xmlElement);
|
int num = 0;
|
while (reader.Read() && reader.TokenType != JsonToken.EndArray)
|
{
|
DeserializeValue(reader, document, manager, propertyName, xmlElement);
|
num++;
|
}
|
if (WriteArrayAttribute)
|
{
|
AddJsonArrayAttribute(xmlElement, document);
|
}
|
if (num != 1 || !WriteArrayAttribute)
|
{
|
return;
|
}
|
foreach (IXmlNode childNode in xmlElement.ChildNodes)
|
{
|
IXmlElement xmlElement2 = childNode as IXmlElement;
|
if (xmlElement2 != null && xmlElement2.LocalName == propertyName)
|
{
|
AddJsonArrayAttribute(xmlElement2, document);
|
break;
|
}
|
}
|
}
|
|
private void AddJsonArrayAttribute(IXmlElement element, IXmlDocument document)
|
{
|
element.SetAttributeNode(document.CreateAttribute("json:Array", "http://james.newtonking.com/projects/json", "true"));
|
if (element is XElementWrapper && element.GetPrefixOfNamespace("http://james.newtonking.com/projects/json") == null)
|
{
|
element.SetAttributeNode(document.CreateAttribute("xmlns:json", "http://www.w3.org/2000/xmlns/", "http://james.newtonking.com/projects/json"));
|
}
|
}
|
|
private Dictionary<string, string> ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager)
|
{
|
Dictionary<string, string> dictionary = new Dictionary<string, string>();
|
bool flag = false;
|
bool flag2 = false;
|
if (reader.TokenType != JsonToken.String && reader.TokenType != JsonToken.Null && reader.TokenType != JsonToken.Boolean && reader.TokenType != JsonToken.Integer && reader.TokenType != JsonToken.Float && reader.TokenType != JsonToken.Date && reader.TokenType != JsonToken.StartConstructor)
|
{
|
while (!flag && !flag2 && reader.Read())
|
{
|
switch (reader.TokenType)
|
{
|
case JsonToken.PropertyName:
|
{
|
string text = reader.Value.ToString();
|
if (!string.IsNullOrEmpty(text))
|
{
|
switch (text[0])
|
{
|
case '@':
|
{
|
text = text.Substring(1);
|
reader.Read();
|
string value = ConvertTokenToXmlValue(reader);
|
dictionary.Add(text, value);
|
if (IsNamespaceAttribute(text, out var prefix))
|
{
|
manager.AddNamespace(prefix, value);
|
}
|
break;
|
}
|
case '$':
|
switch (text)
|
{
|
case "$values":
|
case "$id":
|
case "$ref":
|
case "$type":
|
case "$value":
|
{
|
string text2 = manager.LookupPrefix("http://james.newtonking.com/projects/json");
|
if (text2 == null)
|
{
|
int? num = null;
|
while (manager.LookupNamespace("json" + num) != null)
|
{
|
num = num.GetValueOrDefault() + 1;
|
}
|
text2 = "json" + num;
|
dictionary.Add("xmlns:" + text2, "http://james.newtonking.com/projects/json");
|
manager.AddNamespace(text2, "http://james.newtonking.com/projects/json");
|
}
|
if (text == "$values")
|
{
|
flag = true;
|
break;
|
}
|
text = text.Substring(1);
|
reader.Read();
|
if (!JsonTokenUtils.IsPrimitiveToken(reader.TokenType))
|
{
|
throw JsonSerializationException.Create(reader, "Unexpected JsonToken: " + reader.TokenType);
|
}
|
string value = ((reader.Value != null) ? reader.Value.ToString() : null);
|
dictionary.Add(text2 + ":" + text, value);
|
break;
|
}
|
default:
|
flag = true;
|
break;
|
}
|
break;
|
default:
|
flag = true;
|
break;
|
}
|
}
|
else
|
{
|
flag = true;
|
}
|
break;
|
}
|
case JsonToken.EndObject:
|
flag2 = true;
|
break;
|
case JsonToken.Comment:
|
flag2 = true;
|
break;
|
default:
|
throw JsonSerializationException.Create(reader, "Unexpected JsonToken: " + reader.TokenType);
|
}
|
}
|
}
|
return dictionary;
|
}
|
|
private void CreateInstruction(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName)
|
{
|
if (propertyName == "?xml")
|
{
|
string version = null;
|
string encoding = null;
|
string standalone = null;
|
while (reader.Read() && reader.TokenType != JsonToken.EndObject)
|
{
|
switch (reader.Value.ToString())
|
{
|
case "@version":
|
reader.Read();
|
version = reader.Value.ToString();
|
break;
|
case "@encoding":
|
reader.Read();
|
encoding = reader.Value.ToString();
|
break;
|
case "@standalone":
|
reader.Read();
|
standalone = reader.Value.ToString();
|
break;
|
default:
|
throw JsonSerializationException.Create(reader, "Unexpected property name encountered while deserializing XmlDeclaration: " + reader.Value);
|
}
|
}
|
IXmlNode newChild = document.CreateXmlDeclaration(version, encoding, standalone);
|
currentNode.AppendChild(newChild);
|
}
|
else
|
{
|
IXmlNode newChild2 = document.CreateProcessingInstruction(propertyName.Substring(1), reader.Value.ToString());
|
currentNode.AppendChild(newChild2);
|
}
|
}
|
|
private void CreateDocumentType(JsonReader reader, IXmlDocument document, IXmlNode currentNode)
|
{
|
string name = null;
|
string publicId = null;
|
string systemId = null;
|
string internalSubset = null;
|
while (reader.Read() && reader.TokenType != JsonToken.EndObject)
|
{
|
switch (reader.Value.ToString())
|
{
|
case "@name":
|
reader.Read();
|
name = reader.Value.ToString();
|
break;
|
case "@public":
|
reader.Read();
|
publicId = reader.Value.ToString();
|
break;
|
case "@system":
|
reader.Read();
|
systemId = reader.Value.ToString();
|
break;
|
case "@internalSubset":
|
reader.Read();
|
internalSubset = reader.Value.ToString();
|
break;
|
default:
|
throw JsonSerializationException.Create(reader, "Unexpected property name encountered while deserializing XmlDeclaration: " + reader.Value);
|
}
|
}
|
IXmlNode newChild = document.CreateXmlDocumentType(name, publicId, systemId, internalSubset);
|
currentNode.AppendChild(newChild);
|
}
|
|
private IXmlElement CreateElement(string elementName, IXmlDocument document, string elementPrefix, XmlNamespaceManager manager)
|
{
|
string text = XmlConvert.EncodeName(elementName);
|
string text2 = (string.IsNullOrEmpty(elementPrefix) ? manager.DefaultNamespace : manager.LookupNamespace(elementPrefix));
|
if (string.IsNullOrEmpty(text2))
|
{
|
return document.CreateElement(text);
|
}
|
return document.CreateElement(text, text2);
|
}
|
|
private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, IXmlNode currentNode)
|
{
|
do
|
{
|
switch (reader.TokenType)
|
{
|
case JsonToken.PropertyName:
|
{
|
if (currentNode.NodeType == XmlNodeType.Document && document.DocumentElement != null)
|
{
|
throw JsonSerializationException.Create(reader, "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifing a DeserializeRootElementName.");
|
}
|
string text = reader.Value.ToString();
|
reader.Read();
|
if (reader.TokenType == JsonToken.StartArray)
|
{
|
int num = 0;
|
while (reader.Read() && reader.TokenType != JsonToken.EndArray)
|
{
|
DeserializeValue(reader, document, manager, text, currentNode);
|
num++;
|
}
|
if (num != 1 || !WriteArrayAttribute)
|
{
|
break;
|
}
|
foreach (IXmlNode childNode in currentNode.ChildNodes)
|
{
|
IXmlElement xmlElement = childNode as IXmlElement;
|
if (xmlElement != null && xmlElement.LocalName == text)
|
{
|
AddJsonArrayAttribute(xmlElement, document);
|
break;
|
}
|
}
|
}
|
else
|
{
|
DeserializeValue(reader, document, manager, text, currentNode);
|
}
|
break;
|
}
|
case JsonToken.StartConstructor:
|
{
|
string propertyName = reader.Value.ToString();
|
while (reader.Read() && reader.TokenType != JsonToken.EndConstructor)
|
{
|
DeserializeValue(reader, document, manager, propertyName, currentNode);
|
}
|
break;
|
}
|
case JsonToken.Comment:
|
currentNode.AppendChild(document.CreateComment((string)reader.Value));
|
break;
|
case JsonToken.EndObject:
|
case JsonToken.EndArray:
|
return;
|
default:
|
throw JsonSerializationException.Create(reader, "Unexpected JsonToken when deserializing node: " + reader.TokenType);
|
}
|
}
|
while (reader.TokenType == JsonToken.PropertyName || reader.Read());
|
}
|
|
/// <summary>
|
/// Checks if the attributeName is a namespace attribute.
|
/// </summary>
|
/// <param name="attributeName">Attribute name to test.</param>
|
/// <param name="prefix">The attribute name prefix if it has one, otherwise an empty string.</param>
|
/// <returns><c>true</c> if attribute name is for a namespace attribute, otherwise <c>false</c>.</returns>
|
private bool IsNamespaceAttribute(string attributeName, out string prefix)
|
{
|
if (attributeName.StartsWith("xmlns", StringComparison.Ordinal))
|
{
|
if (attributeName.Length == 5)
|
{
|
prefix = string.Empty;
|
return true;
|
}
|
if (attributeName[5] == ':')
|
{
|
prefix = attributeName.Substring(6, attributeName.Length - 6);
|
return true;
|
}
|
}
|
prefix = null;
|
return false;
|
}
|
|
private bool ValueAttributes(List<IXmlNode> c)
|
{
|
foreach (IXmlNode item in c)
|
{
|
if (item.NamespaceUri != "http://james.newtonking.com/projects/json")
|
{
|
return true;
|
}
|
}
|
return false;
|
}
|
|
/// <summary>
|
/// Determines whether this instance can convert the specified value type.
|
/// </summary>
|
/// <param name="valueType">Type of the value.</param>
|
/// <returns>
|
/// <c>true</c> if this instance can convert the specified value type; otherwise, <c>false</c>.
|
/// </returns>
|
public override bool CanConvert(Type valueType)
|
{
|
if (typeof(XObject).IsAssignableFrom(valueType))
|
{
|
return true;
|
}
|
if (typeof(XmlNode).IsAssignableFrom(valueType))
|
{
|
return true;
|
}
|
return false;
|
}
|
}
|
}
|