XmlNodeConverter
Converts XML to and from JSON.
using Newtonsoft.Json.Utilities;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Xml;
namespace Newtonsoft.Json.Converters
{
public class XmlNodeConverter : JsonConverter
{
internal static readonly List<IXmlNode> EmptyChildNodes = new List<IXmlNode>();
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";
public string DeserializeRootElementName { get; set; }
public bool WriteArrayAttribute { get; set; }
public bool OmitRootObject { get; set; }
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)
{
XmlNode xmlNode = value as XmlNode;
if (xmlNode != null)
return XmlNodeWrapper.WrapNode(xmlNode);
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) {
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)
{
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)
{
switch (node.ChildNodes.Count) {
case 0:
break;
case 1: {
string propertyName2 = GetPropertyName(node.ChildNodes[0], manager);
WriteGroupedNodes(writer, manager, writePropertyName, node.ChildNodes, propertyName2);
break;
}
default: {
Dictionary<string, object> dictionary = null;
string text = null;
for (int i = 0; i < node.ChildNodes.Count; i++) {
IXmlNode xmlNode = node.ChildNodes[i];
string propertyName = GetPropertyName(xmlNode, manager);
object value;
if (dictionary == null) {
if (text == null)
text = propertyName;
else if (!(propertyName == text)) {
dictionary = new Dictionary<string, object>();
if (i > 1) {
List<IXmlNode> list = new List<IXmlNode>(i);
for (int j = 0; j < i; j++) {
list.Add(node.ChildNodes[j]);
}
dictionary.Add(text, list);
} else
dictionary.Add(text, node.ChildNodes[0]);
dictionary.Add(propertyName, xmlNode);
}
} else if (!dictionary.TryGetValue(propertyName, out value)) {
dictionary.Add(propertyName, xmlNode);
} else {
List<IXmlNode> list2 = value as List<IXmlNode>;
if (list2 == null)
list2 = (List<IXmlNode>)(dictionary[propertyName] = new List<IXmlNode> {
(IXmlNode)value
});
list2.Add(xmlNode);
}
}
if (dictionary == null)
WriteGroupedNodes(writer, manager, writePropertyName, node.ChildNodes, text);
else {
foreach (KeyValuePair<string, object> item in dictionary) {
List<IXmlNode> list3 = item.Value as List<IXmlNode>;
if (list3 != null)
WriteGroupedNodes(writer, manager, writePropertyName, list3, item.Key);
else
WriteGroupedNodes(writer, manager, writePropertyName, (IXmlNode)item.Value, item.Key);
}
}
break;
}
}
}
private void WriteGroupedNodes(JsonWriter writer, XmlNamespaceManager manager, bool writePropertyName, List<IXmlNode> groupedNodes, string elementNames)
{
if (groupedNodes.Count == 1 && !IsArray(groupedNodes[0]))
SerializeNode(writer, groupedNodes[0], manager, writePropertyName);
else {
if (writePropertyName)
writer.WritePropertyName(elementNames);
writer.WriteStartArray();
for (int i = 0; i < groupedNodes.Count; i++) {
SerializeNode(writer, groupedNodes[i], manager, false);
}
writer.WriteEndArray();
}
}
private void WriteGroupedNodes(JsonWriter writer, XmlNamespaceManager manager, bool writePropertyName, IXmlNode node, string elementNames)
{
if (!IsArray(node))
SerializeNode(writer, node, manager, writePropertyName);
else {
if (writePropertyName)
writer.WritePropertyName(elementNames);
writer.WriteStartArray();
SerializeNode(writer, node, manager, false);
writer.WriteEndArray();
}
}
private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
{
switch (node.NodeType) {
case XmlNodeType.Document:
case XmlNodeType.DocumentFragment:
SerializeGroupedNodes(writer, node, manager, writePropertyName);
break;
case XmlNodeType.Element:
if (IsArray(node) && AllSameName(node) && node.ChildNodes.Count > 0)
SerializeGroupedNodes(writer, node, manager, false);
else {
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 && node.Attributes.Count == 0) {
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, true);
}
SerializeGroupedNodes(writer, node, manager, 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;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType) {
case JsonToken.Null:
return null;
default:
throw JsonSerializationException.Create(reader, "XmlNodeConverter can only convert JSON that begins with an object.");
case JsonToken.StartObject: {
XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
IXmlDocument xmlDocument = null;
IXmlNode xmlNode = null;
if (typeof(XmlNode).IsAssignableFrom(objectType)) {
if ((object)objectType != typeof(XmlDocument) && (object)objectType != typeof(XmlElement) && (object)objectType != typeof(XmlNode))
throw JsonSerializationException.Create(reader, "XmlNodeConverter only supports deserializing XmlDocument, XmlElement or XmlNode.");
xmlDocument = new XmlDocumentWrapper(new XmlDocument {
XmlResolver = null
});
xmlNode = xmlDocument;
}
if (xmlDocument == null || xmlNode == null)
throw JsonSerializationException.Create(reader, "Unexpected type when converting XML: " + objectType);
if (!string.IsNullOrEmpty(DeserializeRootElementName))
ReadElement(reader, xmlDocument, xmlNode, DeserializeRootElementName, manager);
else {
reader.ReadAndAssert();
DeserializeNode(reader, xmlDocument, manager, xmlNode);
}
if ((object)objectType == typeof(XmlElement))
return xmlDocument.DocumentElement.WrappedNode;
return xmlDocument.WrappedNode;
}
}
}
private void DeserializeValue(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, string propertyName, IXmlNode currentNode)
{
if (!(propertyName == "#text")) {
if (!(propertyName == "#cdata-section")) {
if (!(propertyName == "#whitespace")) {
if (propertyName == "#significant-whitespace")
currentNode.AppendChild(document.CreateSignificantWhitespace(ConvertTokenToXmlValue(reader)));
else 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);
}
} else
currentNode.AppendChild(document.CreateWhitespace(ConvertTokenToXmlValue(reader)));
} else
currentNode.AppendChild(document.CreateCDataSection(ConvertTokenToXmlValue(reader)));
} else
currentNode.AppendChild(document.CreateTextNode(ConvertTokenToXmlValue(reader)));
}
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 (StringUtils.StartsWith(propertyName, '@')) {
string text = propertyName.Substring(1);
string prefix2 = MiscellaneousUtils.GetPrefix(text);
AddAttribute(reader, document, currentNode, propertyName, text, manager, prefix2);
} else {
if (StringUtils.StartsWith(propertyName, '$')) {
if (propertyName == "$values") {
propertyName = propertyName.Substring(1);
prefix = manager.LookupPrefix("http://james.newtonking.com/projects/json");
CreateElement(reader, document, currentNode, propertyName, manager, prefix, attributeNameValues);
return;
}
if (propertyName == "$id" || propertyName == "$ref" || propertyName == "$type" || propertyName == "$value") {
string attributeName = propertyName.Substring(1);
string attributePrefix = manager.LookupPrefix("http://james.newtonking.com/projects/json");
AddAttribute(reader, document, currentNode, propertyName, 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);
if (attributeNameValues != null) {
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);
}
}
switch (reader.TokenType) {
case JsonToken.Null:
break;
case JsonToken.Integer:
case JsonToken.Float:
case JsonToken.String:
case JsonToken.Boolean:
case JsonToken.Date:
case JsonToken.Bytes: {
string text2 = ConvertTokenToXmlValue(reader);
if (text2 != null)
xmlElement.AppendChild(document.CreateTextNode(text2));
break;
}
case JsonToken.EndObject:
manager.RemoveNamespace(string.Empty, manager.DefaultNamespace);
break;
default:
manager.PushScope();
DeserializeNode(reader, document, manager, xmlElement);
manager.PopScope();
manager.RemoveNamespace(string.Empty, manager.DefaultNamespace);
break;
}
}
private static void AddAttribute(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, string attributeName, XmlNamespaceManager manager, string attributePrefix)
{
if (currentNode.NodeType == XmlNodeType.Document)
throw JsonSerializationException.Create(reader, "JSON root object has property '{0}' that will be converted to an attribute. A root object cannot have any attribute properties. Consider specifying a DeserializeRootElementName.".FormatWith(CultureInfo.InvariantCulture, propertyName));
string text = XmlConvert.EncodeName(attributeName);
string value = ConvertTokenToXmlValue(reader);
IXmlNode attributeNode = (!string.IsNullOrEmpty(attributePrefix)) ? document.CreateAttribute(text, manager.LookupNamespace(attributePrefix), value) : document.CreateAttribute(text, value);
((IXmlElement)currentNode).SetAttributeNode(attributeNode);
}
private static string ConvertTokenToXmlValue(JsonReader reader)
{
switch (reader.TokenType) {
case JsonToken.String:
return reader.Value?.ToString();
case JsonToken.Integer:
return XmlConvert.ToString(Convert.ToInt64(reader.Value, CultureInfo.InvariantCulture));
case 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));
case JsonToken.Boolean:
return XmlConvert.ToString(Convert.ToBoolean(reader.Value, CultureInfo.InvariantCulture));
case JsonToken.Date: {
DateTime value = Convert.ToDateTime(reader.Value, CultureInfo.InvariantCulture);
return XmlConvert.ToString(value, DateTimeUtils.ToSerializationMode(value.Kind));
}
case JsonToken.Bytes:
return Convert.ToBase64String((byte[])reader.Value);
case JsonToken.Null:
return null;
default:
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) {
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"));
}
private Dictionary<string, string> ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager)
{
switch (reader.TokenType) {
case JsonToken.StartConstructor:
case JsonToken.Integer:
case JsonToken.Float:
case JsonToken.String:
case JsonToken.Boolean:
case JsonToken.Null:
case JsonToken.Date:
case JsonToken.Bytes:
return null;
default: {
Dictionary<string, string> dictionary = null;
bool flag = false;
while (!flag && reader.Read()) {
switch (reader.TokenType) {
case JsonToken.PropertyName: {
string text = reader.Value.ToString();
if (!string.IsNullOrEmpty(text)) {
switch (text[0]) {
case '@': {
if (dictionary == null)
dictionary = new Dictionary<string, string>();
text = text.Substring(1);
reader.ReadAndAssert();
string value = ConvertTokenToXmlValue(reader);
dictionary.Add(text, value);
if (IsNamespaceAttribute(text, out string prefix))
manager.AddNamespace(prefix, value);
break;
}
case '$':
if (text == "$values" || text == "$id" || text == "$ref" || text == "$type" || text == "$value") {
string text2 = manager.LookupPrefix("http://james.newtonking.com/projects/json");
if (text2 == null) {
if (dictionary == null)
dictionary = new Dictionary<string, string>();
int? nullable = null;
while (manager.LookupNamespace("json" + nullable) != null) {
nullable = nullable.GetValueOrDefault() + 1;
}
text2 = "json" + nullable;
dictionary.Add("xmlns:" + text2, "http://james.newtonking.com/projects/json");
manager.AddNamespace(text2, "http://james.newtonking.com/projects/json");
}
if (text == "$values")
flag = true;
else {
text = text.Substring(1);
reader.ReadAndAssert();
if (!JsonTokenUtils.IsPrimitiveToken(reader.TokenType))
throw JsonSerializationException.Create(reader, "Unexpected JsonToken: " + reader.TokenType);
if (dictionary == null)
dictionary = new Dictionary<string, string>();
string value = reader.Value?.ToString();
dictionary.Add(text2 + ":" + text, value);
}
} else
flag = true;
break;
default:
flag = true;
break;
}
} else
flag = true;
break;
}
case JsonToken.Comment:
case JsonToken.EndObject:
flag = 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.ReadAndAssert();
version = ConvertTokenToXmlValue(reader);
break;
case "@encoding":
reader.ReadAndAssert();
encoding = ConvertTokenToXmlValue(reader);
break;
case "@standalone":
reader.ReadAndAssert();
standalone = ConvertTokenToXmlValue(reader);
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), ConvertTokenToXmlValue(reader));
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.ReadAndAssert();
name = ConvertTokenToXmlValue(reader);
break;
case "@public":
reader.ReadAndAssert();
publicId = ConvertTokenToXmlValue(reader);
break;
case "@system":
reader.ReadAndAssert();
systemId = ConvertTokenToXmlValue(reader);
break;
case "@internalSubset":
reader.ReadAndAssert();
internalSubset = ConvertTokenToXmlValue(reader);
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 {
JsonToken tokenType = reader.TokenType;
switch (tokenType) {
default:
if ((uint)(tokenType - 13) <= 1)
return;
throw JsonSerializationException.Create(reader, "Unexpected JsonToken when deserializing node: " + 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 specifying a DeserializeRootElementName.");
string text = reader.Value.ToString();
reader.ReadAndAssert();
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) {
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;
}
} while (reader.Read());
}
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") && (!(item.NamespaceUri == "http://www.w3.org/2000/xmlns/") || !(item.Value == "http://james.newtonking.com/projects/json")))
return true;
}
return false;
}
public override bool CanConvert(Type valueType)
{
if (valueType.AssignableToTypeName("System.Xml.XmlNode", false))
return IsXmlNode(valueType);
return false;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private bool IsXmlNode(Type valueType)
{
return typeof(XmlNode).IsAssignableFrom(valueType);
}
}
}