2
// Copyright (c) 2007 James Newton-King
4
// Permission is hereby granted, free of charge, to any person
5
// obtaining a copy of this software and associated documentation
6
// files (the "Software"), to deal in the Software without
7
// restriction, including without limitation the rights to use,
8
// copy, modify, merge, publish, distribute, sublicense, and/or sell
9
// copies of the Software, and to permit persons to whom the
10
// Software is furnished to do so, subject to the following
13
// The above copyright notice and this permission notice shall be
14
// included in all copies or substantial portions of the Software.
16
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
// OTHER DEALINGS IN THE SOFTWARE.
26
#if (!(SILVERLIGHT || PORTABLE) || WINDOWS_PHONE)
28
using System.Collections.Generic;
29
using System.Globalization;
32
using System.Xml.Linq;
34
using Newtonsoft.Json.Utilities;
36
using Newtonsoft.Json.Utilities.LinqBridge;
41
namespace Newtonsoft.Json.Converters
43
#region XmlNodeWrappers
44
#if !SILVERLIGHT && !NETFX_CORE
45
internal class XmlDocumentWrapper : XmlNodeWrapper, IXmlDocument
47
private readonly XmlDocument _document;
49
public XmlDocumentWrapper(XmlDocument document)
55
public IXmlNode CreateComment(string data)
57
return new XmlNodeWrapper(_document.CreateComment(data));
60
public IXmlNode CreateTextNode(string text)
62
return new XmlNodeWrapper(_document.CreateTextNode(text));
65
public IXmlNode CreateCDataSection(string data)
67
return new XmlNodeWrapper(_document.CreateCDataSection(data));
70
public IXmlNode CreateWhitespace(string text)
72
return new XmlNodeWrapper(_document.CreateWhitespace(text));
75
public IXmlNode CreateSignificantWhitespace(string text)
77
return new XmlNodeWrapper(_document.CreateSignificantWhitespace(text));
80
public IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone)
82
return new XmlNodeWrapper(_document.CreateXmlDeclaration(version, encoding, standalone));
85
public IXmlNode CreateProcessingInstruction(string target, string data)
87
return new XmlNodeWrapper(_document.CreateProcessingInstruction(target, data));
90
public IXmlElement CreateElement(string elementName)
92
return new XmlElementWrapper(_document.CreateElement(elementName));
95
public IXmlElement CreateElement(string qualifiedName, string namespaceUri)
97
return new XmlElementWrapper(_document.CreateElement(qualifiedName, namespaceUri));
100
public IXmlNode CreateAttribute(string name, string value)
102
XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(name));
103
attribute.Value = value;
108
public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value)
110
XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(qualifiedName, namespaceUri));
111
attribute.Value = value;
116
public IXmlElement DocumentElement
120
if (_document.DocumentElement == null)
123
return new XmlElementWrapper(_document.DocumentElement);
128
internal class XmlElementWrapper : XmlNodeWrapper, IXmlElement
130
private readonly XmlElement _element;
132
public XmlElementWrapper(XmlElement element)
138
public void SetAttributeNode(IXmlNode attribute)
140
XmlNodeWrapper xmlAttributeWrapper = (XmlNodeWrapper)attribute;
142
_element.SetAttributeNode((XmlAttribute) xmlAttributeWrapper.WrappedNode);
145
public string GetPrefixOfNamespace(string namespaceUri)
147
return _element.GetPrefixOfNamespace(namespaceUri);
151
internal class XmlDeclarationWrapper : XmlNodeWrapper, IXmlDeclaration
153
private readonly XmlDeclaration _declaration;
155
public XmlDeclarationWrapper(XmlDeclaration declaration)
158
_declaration = declaration;
161
public string Version
163
get { return _declaration.Version; }
166
public string Encoding
168
get { return _declaration.Encoding; }
169
set { _declaration.Encoding = value; }
172
public string Standalone
174
get { return _declaration.Standalone; }
175
set { _declaration.Standalone = value; }
179
internal class XmlNodeWrapper : IXmlNode
181
private readonly XmlNode _node;
183
public XmlNodeWrapper(XmlNode node)
188
public object WrappedNode
190
get { return _node; }
193
public XmlNodeType NodeType
195
get { return _node.NodeType; }
200
get { return _node.Name; }
203
public string LocalName
205
get { return _node.LocalName; }
208
public IList<IXmlNode> ChildNodes
210
get { return _node.ChildNodes.Cast<XmlNode>().Select(n => WrapNode(n)).ToList(); }
213
private IXmlNode WrapNode(XmlNode node)
215
switch (node.NodeType)
217
case XmlNodeType.Element:
218
return new XmlElementWrapper((XmlElement) node);
219
case XmlNodeType.XmlDeclaration:
220
return new XmlDeclarationWrapper((XmlDeclaration) node);
222
return new XmlNodeWrapper(node);
226
public IList<IXmlNode> Attributes
230
if (_node.Attributes == null)
233
return _node.Attributes.Cast<XmlAttribute>().Select(a => WrapNode(a)).ToList();
237
public IXmlNode ParentNode
241
XmlNode node = (_node is XmlAttribute)
242
? ((XmlAttribute) _node).OwnerElement
248
return WrapNode(node);
254
get { return _node.Value; }
255
set { _node.Value = value; }
258
public IXmlNode AppendChild(IXmlNode newChild)
260
XmlNodeWrapper xmlNodeWrapper = (XmlNodeWrapper) newChild;
261
_node.AppendChild(xmlNodeWrapper._node);
268
get { return _node.Prefix; }
271
public string NamespaceUri
273
get { return _node.NamespaceURI; }
280
internal interface IXmlDocument : IXmlNode
282
IXmlNode CreateComment(string text);
283
IXmlNode CreateTextNode(string text);
284
IXmlNode CreateCDataSection(string data);
285
IXmlNode CreateWhitespace(string text);
286
IXmlNode CreateSignificantWhitespace(string text);
287
IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone);
288
IXmlNode CreateProcessingInstruction(string target, string data);
289
IXmlElement CreateElement(string elementName);
290
IXmlElement CreateElement(string qualifiedName, string namespaceUri);
291
IXmlNode CreateAttribute(string name, string value);
292
IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value);
294
IXmlElement DocumentElement { get; }
297
internal interface IXmlDeclaration : IXmlNode
299
string Version { get; }
300
string Encoding { get; set; }
301
string Standalone { get; set; }
304
internal interface IXmlElement : IXmlNode
306
void SetAttributeNode(IXmlNode attribute);
307
string GetPrefixOfNamespace(string namespaceUri);
310
internal interface IXmlNode
312
XmlNodeType NodeType { get; }
313
string LocalName { get; }
314
IList<IXmlNode> ChildNodes { get; }
315
IList<IXmlNode> Attributes { get; }
316
IXmlNode ParentNode { get; }
317
string Value { get; set; }
318
IXmlNode AppendChild(IXmlNode newChild);
319
string NamespaceUri { get; }
320
object WrappedNode { get; }
324
#region XNodeWrappers
326
internal class XDeclarationWrapper : XObjectWrapper, IXmlDeclaration
328
internal XDeclaration Declaration { get; private set; }
330
public XDeclarationWrapper(XDeclaration declaration)
333
Declaration = declaration;
336
public override XmlNodeType NodeType
338
get { return XmlNodeType.XmlDeclaration; }
341
public string Version
343
get { return Declaration.Version; }
346
public string Encoding
348
get { return Declaration.Encoding; }
349
set { Declaration.Encoding = value; }
352
public string Standalone
354
get { return Declaration.Standalone; }
355
set { Declaration.Standalone = value; }
359
internal class XDocumentWrapper : XContainerWrapper, IXmlDocument
361
private XDocument Document
363
get { return (XDocument)WrappedNode; }
366
public XDocumentWrapper(XDocument document)
371
public override IList<IXmlNode> ChildNodes
375
IList<IXmlNode> childNodes = base.ChildNodes;
377
if (Document.Declaration != null)
378
childNodes.Insert(0, new XDeclarationWrapper(Document.Declaration));
384
public IXmlNode CreateComment(string text)
386
return new XObjectWrapper(new XComment(text));
389
public IXmlNode CreateTextNode(string text)
391
return new XObjectWrapper(new XText(text));
394
public IXmlNode CreateCDataSection(string data)
396
return new XObjectWrapper(new XCData(data));
399
public IXmlNode CreateWhitespace(string text)
401
return new XObjectWrapper(new XText(text));
404
public IXmlNode CreateSignificantWhitespace(string text)
406
return new XObjectWrapper(new XText(text));
409
public IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone)
411
return new XDeclarationWrapper(new XDeclaration(version, encoding, standalone));
414
public IXmlNode CreateProcessingInstruction(string target, string data)
416
return new XProcessingInstructionWrapper(new XProcessingInstruction(target, data));
419
public IXmlElement CreateElement(string elementName)
421
return new XElementWrapper(new XElement(elementName));
424
public IXmlElement CreateElement(string qualifiedName, string namespaceUri)
426
string localName = MiscellaneousUtils.GetLocalName(qualifiedName);
427
return new XElementWrapper(new XElement(XName.Get(localName, namespaceUri)));
430
public IXmlNode CreateAttribute(string name, string value)
432
return new XAttributeWrapper(new XAttribute(name, value));
435
public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value)
437
string localName = MiscellaneousUtils.GetLocalName(qualifiedName);
438
return new XAttributeWrapper(new XAttribute(XName.Get(localName, namespaceUri), value));
441
public IXmlElement DocumentElement
445
if (Document.Root == null)
448
return new XElementWrapper(Document.Root);
452
public override IXmlNode AppendChild(IXmlNode newChild)
454
XDeclarationWrapper declarationWrapper = newChild as XDeclarationWrapper;
455
if (declarationWrapper != null)
457
Document.Declaration = declarationWrapper.Declaration;
458
return declarationWrapper;
462
return base.AppendChild(newChild);
467
internal class XTextWrapper : XObjectWrapper
471
get { return (XText)WrappedNode; }
474
public XTextWrapper(XText text)
479
public override string Value
481
get { return Text.Value; }
482
set { Text.Value = value; }
485
public override IXmlNode ParentNode
489
if (Text.Parent == null)
492
return XContainerWrapper.WrapNode(Text.Parent);
497
internal class XCommentWrapper : XObjectWrapper
499
private XComment Text
501
get { return (XComment)WrappedNode; }
504
public XCommentWrapper(XComment text)
509
public override string Value
511
get { return Text.Value; }
512
set { Text.Value = value; }
515
public override IXmlNode ParentNode
519
if (Text.Parent == null)
522
return XContainerWrapper.WrapNode(Text.Parent);
527
internal class XProcessingInstructionWrapper : XObjectWrapper
529
private XProcessingInstruction ProcessingInstruction
531
get { return (XProcessingInstruction)WrappedNode; }
534
public XProcessingInstructionWrapper(XProcessingInstruction processingInstruction)
535
: base(processingInstruction)
539
public override string LocalName
541
get { return ProcessingInstruction.Target; }
544
public override string Value
546
get { return ProcessingInstruction.Data; }
547
set { ProcessingInstruction.Data = value; }
551
internal class XContainerWrapper : XObjectWrapper
553
private XContainer Container
555
get { return (XContainer)WrappedNode; }
558
public XContainerWrapper(XContainer container)
563
public override IList<IXmlNode> ChildNodes
565
get { return Container.Nodes().Select(n => WrapNode(n)).ToList(); }
568
public override IXmlNode ParentNode
572
if (Container.Parent == null)
575
return WrapNode(Container.Parent);
579
internal static IXmlNode WrapNode(XObject node)
581
if (node is XDocument)
582
return new XDocumentWrapper((XDocument)node);
583
else if (node is XElement)
584
return new XElementWrapper((XElement)node);
585
else if (node is XContainer)
586
return new XContainerWrapper((XContainer)node);
587
else if (node is XProcessingInstruction)
588
return new XProcessingInstructionWrapper((XProcessingInstruction)node);
589
else if (node is XText)
590
return new XTextWrapper((XText)node);
591
else if (node is XComment)
592
return new XCommentWrapper((XComment)node);
593
else if (node is XAttribute)
594
return new XAttributeWrapper((XAttribute) node);
596
return new XObjectWrapper(node);
599
public override IXmlNode AppendChild(IXmlNode newChild)
601
Container.Add(newChild.WrappedNode);
606
internal class XObjectWrapper : IXmlNode
608
private readonly XObject _xmlObject;
610
public XObjectWrapper(XObject xmlObject)
612
_xmlObject = xmlObject;
615
public object WrappedNode
617
get { return _xmlObject; }
620
public virtual XmlNodeType NodeType
622
get { return _xmlObject.NodeType; }
625
public virtual string LocalName
630
public virtual IList<IXmlNode> ChildNodes
632
get { return new List<IXmlNode>(); }
635
public virtual IList<IXmlNode> Attributes
640
public virtual IXmlNode ParentNode
645
public virtual string Value
648
set { throw new InvalidOperationException(); }
651
public virtual IXmlNode AppendChild(IXmlNode newChild)
653
throw new InvalidOperationException();
656
public virtual string NamespaceUri
662
internal class XAttributeWrapper : XObjectWrapper
664
private XAttribute Attribute
666
get { return (XAttribute)WrappedNode; }
669
public XAttributeWrapper(XAttribute attribute)
674
public override string Value
676
get { return Attribute.Value; }
677
set { Attribute.Value = value; }
680
public override string LocalName
682
get { return Attribute.Name.LocalName; }
685
public override string NamespaceUri
687
get { return Attribute.Name.NamespaceName; }
690
public override IXmlNode ParentNode
694
if (Attribute.Parent == null)
697
return XContainerWrapper.WrapNode(Attribute.Parent);
702
internal class XElementWrapper : XContainerWrapper, IXmlElement
704
private XElement Element
706
get { return (XElement) WrappedNode; }
709
public XElementWrapper(XElement element)
714
public void SetAttributeNode(IXmlNode attribute)
716
XObjectWrapper wrapper = (XObjectWrapper)attribute;
717
Element.Add(wrapper.WrappedNode);
720
public override IList<IXmlNode> Attributes
722
get { return Element.Attributes().Select(a => new XAttributeWrapper(a)).Cast<IXmlNode>().ToList(); }
725
public override string Value
727
get { return Element.Value; }
728
set { Element.Value = value; }
731
public override string LocalName
733
get { return Element.Name.LocalName; }
736
public override string NamespaceUri
738
get { return Element.Name.NamespaceName; }
741
public string GetPrefixOfNamespace(string namespaceUri)
743
return Element.GetPrefixOfNamespace(namespaceUri);
750
/// Converts XML to and from JSON.
752
public class XmlNodeConverter : JsonConverter
754
private const string TextName = "#text";
755
private const string CommentName = "#comment";
756
private const string CDataName = "#cdata-section";
757
private const string WhitespaceName = "#whitespace";
758
private const string SignificantWhitespaceName = "#significant-whitespace";
759
private const string DeclarationName = "?xml";
760
private const string JsonNamespaceUri = "http://james.newtonking.com/projects/json";
763
/// Gets or sets the name of the root element to insert when deserializing to XML if the JSON structure has produces multiple root elements.
765
/// <value>The name of the deserialize root element.</value>
766
public string DeserializeRootElementName { get; set; }
769
/// Gets or sets a flag to indicate whether to write the Json.NET array attribute.
770
/// This attribute helps preserve arrays when converting the written XML back to JSON.
772
/// <value><c>true</c> if the array attibute is written to the XML; otherwise, <c>false</c>.</value>
773
public bool WriteArrayAttribute { get; set; }
776
/// Gets or sets a value indicating whether to write the root JSON object.
778
/// <value><c>true</c> if the JSON root object is omitted; otherwise, <c>false</c>.</value>
779
public bool OmitRootObject { get; set; }
783
/// Writes the JSON representation of the object.
785
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
786
/// <param name="serializer">The calling serializer.</param>
787
/// <param name="value">The value.</param>
788
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
790
IXmlNode node = WrapXml(value);
792
XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
793
PushParentNamespaces(node, manager);
796
writer.WriteStartObject();
798
SerializeNode(writer, node, manager, !OmitRootObject);
801
writer.WriteEndObject();
804
private IXmlNode WrapXml(object value)
807
if (value is XObject)
808
return XContainerWrapper.WrapNode((XObject)value);
810
#if !(SILVERLIGHT || NETFX_CORE)
811
if (value is XmlNode)
812
return new XmlNodeWrapper((XmlNode)value);
815
throw new ArgumentException("Value must be an XML object.", "value");
818
private void PushParentNamespaces(IXmlNode node, XmlNamespaceManager manager)
820
List<IXmlNode> parentElements = null;
822
IXmlNode parent = node;
823
while ((parent = parent.ParentNode) != null)
825
if (parent.NodeType == XmlNodeType.Element)
827
if (parentElements == null)
828
parentElements = new List<IXmlNode>();
830
parentElements.Add(parent);
834
if (parentElements != null)
836
parentElements.Reverse();
838
foreach (IXmlNode parentElement in parentElements)
841
foreach (IXmlNode attribute in parentElement.Attributes)
843
if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/" && attribute.LocalName != "xmlns")
844
manager.AddNamespace(attribute.LocalName, attribute.Value);
850
private string ResolveFullName(IXmlNode node, XmlNamespaceManager manager)
852
string prefix = (node.NamespaceUri == null || (node.LocalName == "xmlns" && node.NamespaceUri == "http://www.w3.org/2000/xmlns/"))
854
: manager.LookupPrefix(node.NamespaceUri);
856
if (!string.IsNullOrEmpty(prefix))
857
return prefix + ":" + node.LocalName;
859
return node.LocalName;
862
private string GetPropertyName(IXmlNode node, XmlNamespaceManager manager)
864
switch (node.NodeType)
866
case XmlNodeType.Attribute:
867
if (node.NamespaceUri == JsonNamespaceUri)
868
return "$" + node.LocalName;
870
return "@" + ResolveFullName(node, manager);
871
case XmlNodeType.CDATA:
873
case XmlNodeType.Comment:
875
case XmlNodeType.Element:
876
return ResolveFullName(node, manager);
877
case XmlNodeType.ProcessingInstruction:
878
return "?" + ResolveFullName(node, manager);
879
case XmlNodeType.XmlDeclaration:
880
return DeclarationName;
881
case XmlNodeType.SignificantWhitespace:
882
return SignificantWhitespaceName;
883
case XmlNodeType.Text:
885
case XmlNodeType.Whitespace:
886
return WhitespaceName;
888
throw new JsonSerializationException("Unexpected XmlNodeType when getting node name: " + node.NodeType);
892
private bool IsArray(IXmlNode node)
894
IXmlNode jsonArrayAttribute = (node.Attributes != null)
895
? node.Attributes.SingleOrDefault(a => a.LocalName == "Array" && a.NamespaceUri == JsonNamespaceUri)
898
return (jsonArrayAttribute != null && XmlConvert.ToBoolean(jsonArrayAttribute.Value));
901
private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
903
// group nodes together by name
904
Dictionary<string, List<IXmlNode>> nodesGroupedByName = new Dictionary<string, List<IXmlNode>>();
906
for (int i = 0; i < node.ChildNodes.Count; i++)
908
IXmlNode childNode = node.ChildNodes[i];
909
string nodeName = GetPropertyName(childNode, manager);
911
List<IXmlNode> nodes;
912
if (!nodesGroupedByName.TryGetValue(nodeName, out nodes))
914
nodes = new List<IXmlNode>();
915
nodesGroupedByName.Add(nodeName, nodes);
918
nodes.Add(childNode);
921
// loop through grouped nodes. write single name instances as normal,
922
// write multiple names together in an array
923
foreach (KeyValuePair<string, List<IXmlNode>> nodeNameGroup in nodesGroupedByName)
925
List<IXmlNode> groupedNodes = nodeNameGroup.Value;
928
if (groupedNodes.Count == 1)
930
writeArray = IsArray(groupedNodes[0]);
939
SerializeNode(writer, groupedNodes[0], manager, writePropertyName);
943
string elementNames = nodeNameGroup.Key;
945
if (writePropertyName)
946
writer.WritePropertyName(elementNames);
948
writer.WriteStartArray();
950
for (int i = 0; i < groupedNodes.Count; i++)
952
SerializeNode(writer, groupedNodes[i], manager, false);
955
writer.WriteEndArray();
960
private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
962
switch (node.NodeType)
964
case XmlNodeType.Document:
965
case XmlNodeType.DocumentFragment:
966
SerializeGroupedNodes(writer, node, manager, writePropertyName);
968
case XmlNodeType.Element:
969
if (IsArray(node) && node.ChildNodes.All(n => n.LocalName == node.LocalName) && node.ChildNodes.Count > 0)
971
SerializeGroupedNodes(writer, node, manager, false);
975
foreach (IXmlNode attribute in node.Attributes)
977
if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/")
979
string prefix = (attribute.LocalName != "xmlns")
980
? attribute.LocalName
983
manager.AddNamespace(prefix, attribute.Value);
987
if (writePropertyName)
988
writer.WritePropertyName(GetPropertyName(node, manager));
990
if (!ValueAttributes(node.Attributes).Any() && node.ChildNodes.Count == 1
991
&& node.ChildNodes[0].NodeType == XmlNodeType.Text)
993
// write elements with a single text child as a name value pair
994
writer.WriteValue(node.ChildNodes[0].Value);
996
else if (node.ChildNodes.Count == 0 && CollectionUtils.IsNullOrEmpty(node.Attributes))
1003
writer.WriteStartObject();
1005
for (int i = 0; i < node.Attributes.Count; i++)
1007
SerializeNode(writer, node.Attributes[i], manager, true);
1010
SerializeGroupedNodes(writer, node, manager, true);
1012
writer.WriteEndObject();
1017
case XmlNodeType.Comment:
1018
if (writePropertyName)
1019
writer.WriteComment(node.Value);
1021
case XmlNodeType.Attribute:
1022
case XmlNodeType.Text:
1023
case XmlNodeType.CDATA:
1024
case XmlNodeType.ProcessingInstruction:
1025
case XmlNodeType.Whitespace:
1026
case XmlNodeType.SignificantWhitespace:
1027
if (node.NamespaceUri == "http://www.w3.org/2000/xmlns/" && node.Value == JsonNamespaceUri)
1030
if (node.NamespaceUri == JsonNamespaceUri)
1032
if (node.LocalName == "Array")
1036
if (writePropertyName)
1037
writer.WritePropertyName(GetPropertyName(node, manager));
1038
writer.WriteValue(node.Value);
1040
case XmlNodeType.XmlDeclaration:
1041
IXmlDeclaration declaration = (IXmlDeclaration)node;
1042
writer.WritePropertyName(GetPropertyName(node, manager));
1043
writer.WriteStartObject();
1045
if (!string.IsNullOrEmpty(declaration.Version))
1047
writer.WritePropertyName("@version");
1048
writer.WriteValue(declaration.Version);
1050
if (!string.IsNullOrEmpty(declaration.Encoding))
1052
writer.WritePropertyName("@encoding");
1053
writer.WriteValue(declaration.Encoding);
1055
if (!string.IsNullOrEmpty(declaration.Standalone))
1057
writer.WritePropertyName("@standalone");
1058
writer.WriteValue(declaration.Standalone);
1061
writer.WriteEndObject();
1064
throw new JsonSerializationException("Unexpected XmlNodeType when serializing nodes: " + node.NodeType);
1071
/// Reads the JSON representation of the object.
1073
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
1074
/// <param name="objectType">Type of the object.</param>
1075
/// <param name="existingValue">The existing value of object being read.</param>
1076
/// <param name="serializer">The calling serializer.</param>
1077
/// <returns>The object value.</returns>
1078
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
1080
XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
1081
IXmlDocument document = null;
1082
IXmlNode rootNode = null;
1085
if (typeof(XObject).IsAssignableFrom(objectType))
1087
if (objectType != typeof (XDocument) && objectType != typeof (XElement))
1088
throw new JsonSerializationException("XmlNodeConverter only supports deserializing XDocument or XElement.");
1090
XDocument d = new XDocument();
1091
document = new XDocumentWrapper(d);
1092
rootNode = document;
1095
#if !(SILVERLIGHT || NETFX_CORE)
1096
if (typeof(XmlNode).IsAssignableFrom(objectType))
1098
if (objectType != typeof (XmlDocument))
1099
throw new JsonSerializationException("XmlNodeConverter only supports deserializing XmlDocuments");
1101
XmlDocument d = new XmlDocument();
1102
document = new XmlDocumentWrapper(d);
1103
rootNode = document;
1107
if (document == null || rootNode == null)
1108
throw new JsonSerializationException("Unexpected type when converting XML: " + objectType);
1110
if (reader.TokenType != JsonToken.StartObject)
1111
throw new JsonSerializationException("XmlNodeConverter can only convert JSON that begins with an object.");
1113
if (!string.IsNullOrEmpty(DeserializeRootElementName))
1115
//rootNode = document.CreateElement(DeserializeRootElementName);
1116
//document.AppendChild(rootNode);
1117
ReadElement(reader, document, rootNode, DeserializeRootElementName, manager);
1122
DeserializeNode(reader, document, manager, rootNode);
1126
if (objectType == typeof(XElement))
1128
XElement element = (XElement)document.DocumentElement.WrappedNode;
1135
return document.WrappedNode;
1138
private void DeserializeValue(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, string propertyName, IXmlNode currentNode)
1140
switch (propertyName)
1143
currentNode.AppendChild(document.CreateTextNode(reader.Value.ToString()));
1146
currentNode.AppendChild(document.CreateCDataSection(reader.Value.ToString()));
1148
case WhitespaceName:
1149
currentNode.AppendChild(document.CreateWhitespace(reader.Value.ToString()));
1151
case SignificantWhitespaceName:
1152
currentNode.AppendChild(document.CreateSignificantWhitespace(reader.Value.ToString()));
1155
// processing instructions and the xml declaration start with ?
1156
if (!string.IsNullOrEmpty(propertyName) && propertyName[0] == '?')
1158
CreateInstruction(reader, document, currentNode, propertyName);
1162
if (reader.TokenType == JsonToken.StartArray)
1164
// handle nested arrays
1165
ReadArrayElements(reader, document, propertyName, currentNode, manager);
1169
// have to wait until attributes have been parsed before creating element
1170
// attributes may contain namespace info used by the element
1171
ReadElement(reader, document, currentNode, propertyName, manager);
1177
private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, XmlNamespaceManager manager)
1179
if (string.IsNullOrEmpty(propertyName))
1180
throw new JsonSerializationException("XmlNodeConverter cannot convert JSON with an empty property name to XML.");
1182
Dictionary<string, string> attributeNameValues = ReadAttributeElements(reader, manager);
1184
string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);
1186
if (propertyName.StartsWith("@"))
1188
var attributeName = propertyName.Substring(1);
1189
var attributeValue = reader.Value.ToString();
1191
var attributePrefix = MiscellaneousUtils.GetPrefix(attributeName);
1193
var attribute = (!string.IsNullOrEmpty(attributePrefix))
1194
? document.CreateAttribute(attributeName, manager.LookupNamespace(attributePrefix), attributeValue)
1195
: document.CreateAttribute(attributeName, attributeValue);
1197
((IXmlElement)currentNode).SetAttributeNode(attribute);
1201
IXmlElement element = CreateElement(propertyName, document, elementPrefix, manager);
1203
currentNode.AppendChild(element);
1205
// add attributes to newly created element
1206
foreach (KeyValuePair<string, string> nameValue in attributeNameValues)
1208
string attributePrefix = MiscellaneousUtils.GetPrefix(nameValue.Key);
1210
IXmlNode attribute = (!string.IsNullOrEmpty(attributePrefix))
1211
? document.CreateAttribute(nameValue.Key, manager.LookupNamespace(attributePrefix), nameValue.Value)
1212
: document.CreateAttribute(nameValue.Key, nameValue.Value);
1214
element.SetAttributeNode(attribute);
1217
if (reader.TokenType == JsonToken.String
1218
|| reader.TokenType == JsonToken.Integer
1219
|| reader.TokenType == JsonToken.Float
1220
|| reader.TokenType == JsonToken.Boolean
1221
|| reader.TokenType == JsonToken.Date)
1223
element.AppendChild(document.CreateTextNode(ConvertTokenToXmlValue(reader)));
1225
else if (reader.TokenType == JsonToken.Null)
1227
// empty element. do nothing
1231
// finished element will have no children to deserialize
1232
if (reader.TokenType != JsonToken.EndObject)
1234
manager.PushScope();
1236
DeserializeNode(reader, document, manager, element);
1244
private string ConvertTokenToXmlValue(JsonReader reader)
1246
if (reader.TokenType == JsonToken.String)
1248
return reader.Value.ToString();
1250
else if (reader.TokenType == JsonToken.Integer)
1252
return XmlConvert.ToString(Convert.ToInt64(reader.Value, CultureInfo.InvariantCulture));
1254
else if (reader.TokenType == JsonToken.Float)
1256
return XmlConvert.ToString(Convert.ToDouble(reader.Value, CultureInfo.InvariantCulture));
1258
else if (reader.TokenType == JsonToken.Boolean)
1260
return XmlConvert.ToString(Convert.ToBoolean(reader.Value, CultureInfo.InvariantCulture));
1262
else if (reader.TokenType == JsonToken.Date)
1264
DateTime d = Convert.ToDateTime(reader.Value, CultureInfo.InvariantCulture);
1266
return XmlConvert.ToString(d, DateTimeUtils.ToSerializationMode(d.Kind));
1268
return XmlConvert.ToString(d);
1271
else if (reader.TokenType == JsonToken.Null)
1277
throw JsonSerializationException.Create(reader, "Cannot get an XML string value from token type '{0}'.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
1281
private void ReadArrayElements(JsonReader reader, IXmlDocument document, string propertyName, IXmlNode currentNode, XmlNamespaceManager manager)
1283
string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);
1285
IXmlElement nestedArrayElement = CreateElement(propertyName, document, elementPrefix, manager);
1287
currentNode.AppendChild(nestedArrayElement);
1290
while (reader.Read() && reader.TokenType != JsonToken.EndArray)
1292
DeserializeValue(reader, document, manager, propertyName, nestedArrayElement);
1296
if (WriteArrayAttribute)
1298
AddJsonArrayAttribute(nestedArrayElement, document);
1301
if (count == 1 && WriteArrayAttribute)
1303
IXmlElement arrayElement = nestedArrayElement.ChildNodes.CastValid<IXmlElement>().Single(n => n.LocalName == propertyName);
1304
AddJsonArrayAttribute(arrayElement, document);
1308
private void AddJsonArrayAttribute(IXmlElement element, IXmlDocument document)
1310
element.SetAttributeNode(document.CreateAttribute("json:Array", JsonNamespaceUri, "true"));
1313
// linq to xml doesn't automatically include prefixes via the namespace manager
1314
if (element is XElementWrapper)
1316
if (element.GetPrefixOfNamespace(JsonNamespaceUri) == null)
1318
element.SetAttributeNode(document.CreateAttribute("xmlns:json", "http://www.w3.org/2000/xmlns/", JsonNamespaceUri));
1324
private Dictionary<string, string> ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager)
1326
Dictionary<string, string> attributeNameValues = new Dictionary<string, string>();
1327
bool finishedAttributes = false;
1328
bool finishedElement = false;
1330
// a string token means the element only has a single text child
1331
if (reader.TokenType != JsonToken.String
1332
&& reader.TokenType != JsonToken.Null
1333
&& reader.TokenType != JsonToken.Boolean
1334
&& reader.TokenType != JsonToken.Integer
1335
&& reader.TokenType != JsonToken.Float
1336
&& reader.TokenType != JsonToken.Date
1337
&& reader.TokenType != JsonToken.StartConstructor)
1339
// read properties until first non-attribute is encountered
1340
while (!finishedAttributes && !finishedElement && reader.Read())
1342
switch (reader.TokenType)
1344
case JsonToken.PropertyName:
1345
string attributeName = reader.Value.ToString();
1347
if (!string.IsNullOrEmpty(attributeName))
1349
char firstChar = attributeName[0];
1350
string attributeValue;
1355
attributeName = attributeName.Substring(1);
1357
attributeValue = ConvertTokenToXmlValue(reader);
1358
attributeNameValues.Add(attributeName, attributeValue);
1360
string namespacePrefix;
1361
if (IsNamespaceAttribute(attributeName, out namespacePrefix))
1363
manager.AddNamespace(namespacePrefix, attributeValue);
1367
attributeName = attributeName.Substring(1);
1369
attributeValue = reader.Value.ToString();
1371
// check that JsonNamespaceUri is in scope
1372
// if it isn't then add it to document and namespace manager
1373
string jsonPrefix = manager.LookupPrefix(JsonNamespaceUri);
1374
if (jsonPrefix == null)
1376
// ensure that the prefix used is free
1378
while (manager.LookupNamespace("json" + i) != null)
1380
i = i.GetValueOrDefault() + 1;
1382
jsonPrefix = "json" + i;
1384
attributeNameValues.Add("xmlns:" + jsonPrefix, JsonNamespaceUri);
1385
manager.AddNamespace(jsonPrefix, JsonNamespaceUri);
1388
attributeNameValues.Add(jsonPrefix + ":" + attributeName, attributeValue);
1391
finishedAttributes = true;
1397
finishedAttributes = true;
1401
case JsonToken.EndObject:
1402
finishedElement = true;
1405
throw new JsonSerializationException("Unexpected JsonToken: " + reader.TokenType);
1410
return attributeNameValues;
1413
private void CreateInstruction(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName)
1415
if (propertyName == DeclarationName)
1417
string version = null;
1418
string encoding = null;
1419
string standalone = null;
1420
while (reader.Read() && reader.TokenType != JsonToken.EndObject)
1422
switch (reader.Value.ToString())
1426
version = reader.Value.ToString();
1430
encoding = reader.Value.ToString();
1434
standalone = reader.Value.ToString();
1437
throw new JsonSerializationException("Unexpected property name encountered while deserializing XmlDeclaration: " + reader.Value);
1441
IXmlNode declaration = document.CreateXmlDeclaration(version, encoding, standalone);
1442
currentNode.AppendChild(declaration);
1446
IXmlNode instruction = document.CreateProcessingInstruction(propertyName.Substring(1), reader.Value.ToString());
1447
currentNode.AppendChild(instruction);
1451
private IXmlElement CreateElement(string elementName, IXmlDocument document, string elementPrefix, XmlNamespaceManager manager)
1453
string ns = string.IsNullOrEmpty(elementPrefix) ? manager.DefaultNamespace : manager.LookupNamespace(elementPrefix);
1455
IXmlElement element = (!string.IsNullOrEmpty(ns)) ? document.CreateElement(elementName, ns) : document.CreateElement(elementName);
1460
private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, IXmlNode currentNode)
1464
switch (reader.TokenType)
1466
case JsonToken.PropertyName:
1467
if (currentNode.NodeType == XmlNodeType.Document && document.DocumentElement != null)
1468
throw new JsonSerializationException("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.");
1470
string propertyName = reader.Value.ToString();
1473
if (reader.TokenType == JsonToken.StartArray)
1476
while (reader.Read() && reader.TokenType != JsonToken.EndArray)
1478
DeserializeValue(reader, document, manager, propertyName, currentNode);
1482
if (count == 1 && WriteArrayAttribute)
1484
IXmlElement arrayElement = currentNode.ChildNodes.CastValid<IXmlElement>().Single(n => n.LocalName == propertyName);
1485
AddJsonArrayAttribute(arrayElement, document);
1490
DeserializeValue(reader, document, manager, propertyName, currentNode);
1493
case JsonToken.StartConstructor:
1494
string constructorName = reader.Value.ToString();
1496
while (reader.Read() && reader.TokenType != JsonToken.EndConstructor)
1498
DeserializeValue(reader, document, manager, constructorName, currentNode);
1501
case JsonToken.Comment:
1502
currentNode.AppendChild(document.CreateComment((string)reader.Value));
1504
case JsonToken.EndObject:
1505
case JsonToken.EndArray:
1508
throw new JsonSerializationException("Unexpected JsonToken when deserializing node: " + reader.TokenType);
1510
} while (reader.TokenType == JsonToken.PropertyName || reader.Read());
1511
// don't read if current token is a property. token was already read when parsing element attributes
1515
/// Checks if the attributeName is a namespace attribute.
1517
/// <param name="attributeName">Attribute name to test.</param>
1518
/// <param name="prefix">The attribute name prefix if it has one, otherwise an empty string.</param>
1519
/// <returns>True if attribute name is for a namespace attribute, otherwise false.</returns>
1520
private bool IsNamespaceAttribute(string attributeName, out string prefix)
1522
if (attributeName.StartsWith("xmlns", StringComparison.Ordinal))
1524
if (attributeName.Length == 5)
1526
prefix = string.Empty;
1529
else if (attributeName[5] == ':')
1531
prefix = attributeName.Substring(6, attributeName.Length - 6);
1539
private IEnumerable<IXmlNode> ValueAttributes(IEnumerable<IXmlNode> c)
1541
return c.Where(a => a.NamespaceUri != JsonNamespaceUri);
1546
/// Determines whether this instance can convert the specified value type.
1548
/// <param name="valueType">Type of the value.</param>
1550
/// <c>true</c> if this instance can convert the specified value type; otherwise, <c>false</c>.
1552
public override bool CanConvert(Type valueType)
1555
if (typeof(XObject).IsAssignableFrom(valueType))
1558
#if !(SILVERLIGHT || NETFX_CORE)
1559
if (typeof(XmlNode).IsAssignableFrom(valueType))
b'\\ No newline at end of file'