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 || WINDOWS_PHONE
28 using System.Collections.Generic;
31 using System.Xml.Linq;
33 using Newtonsoft.Json.Utilities;
36 namespace Newtonsoft.Json.Converters
38 #region XmlNodeWrappers
40 internal class XmlDocumentWrapper : XmlNodeWrapper, IXmlDocument
42 private XmlDocument _document;
44 public XmlDocumentWrapper(XmlDocument document)
50 public IXmlNode CreateComment(string data)
52 return new XmlNodeWrapper(_document.CreateComment(data));
55 public IXmlNode CreateTextNode(string text)
57 return new XmlNodeWrapper(_document.CreateTextNode(text));
60 public IXmlNode CreateCDataSection(string data)
62 return new XmlNodeWrapper(_document.CreateCDataSection(data));
65 public IXmlNode CreateWhitespace(string text)
67 return new XmlNodeWrapper(_document.CreateWhitespace(text));
70 public IXmlNode CreateSignificantWhitespace(string text)
72 return new XmlNodeWrapper(_document.CreateSignificantWhitespace(text));
75 public IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone)
77 return new XmlNodeWrapper(_document.CreateXmlDeclaration(version, encoding, standalone));
80 public IXmlNode CreateProcessingInstruction(string target, string data)
82 return new XmlNodeWrapper(_document.CreateProcessingInstruction(target, data));
85 public IXmlElement CreateElement(string elementName)
87 return new XmlElementWrapper(_document.CreateElement(elementName));
90 public IXmlElement CreateElement(string qualifiedName, string namespaceURI)
92 return new XmlElementWrapper(_document.CreateElement(qualifiedName, namespaceURI));
95 public IXmlNode CreateAttribute(string name, string value)
97 XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(name));
98 attribute.Value = value;
103 public IXmlNode CreateAttribute(string qualifiedName, string namespaceURI, string value)
105 XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(qualifiedName, namespaceURI));
106 attribute.Value = value;
111 public IXmlElement DocumentElement
115 if (_document.DocumentElement == null)
118 return new XmlElementWrapper(_document.DocumentElement);
123 internal class XmlElementWrapper : XmlNodeWrapper, IXmlElement
125 private XmlElement _element;
127 public XmlElementWrapper(XmlElement element)
133 public void SetAttributeNode(IXmlNode attribute)
135 XmlNodeWrapper xmlAttributeWrapper = (XmlNodeWrapper)attribute;
137 _element.SetAttributeNode((XmlAttribute) xmlAttributeWrapper.WrappedNode);
140 public string GetPrefixOfNamespace(string namespaceURI)
142 return _element.GetPrefixOfNamespace(namespaceURI);
146 internal class XmlDeclarationWrapper : XmlNodeWrapper, IXmlDeclaration
148 private XmlDeclaration _declaration;
150 public XmlDeclarationWrapper(XmlDeclaration declaration)
153 _declaration = declaration;
156 public string Version
158 get { return _declaration.Version; }
161 public string Encoding
163 get { return _declaration.Encoding; }
164 set { _declaration.Encoding = value; }
167 public string Standalone
169 get { return _declaration.Standalone; }
170 set { _declaration.Standalone = value; }
174 internal class XmlNodeWrapper : IXmlNode
176 private readonly XmlNode _node;
178 public XmlNodeWrapper(XmlNode node)
183 public object WrappedNode
185 get { return _node; }
188 public XmlNodeType NodeType
190 get { return _node.NodeType; }
195 get { return _node.Name; }
198 public string LocalName
200 get { return _node.LocalName; }
203 public IList<IXmlNode> ChildNodes
205 get { return _node.ChildNodes.Cast<XmlNode>().Select(n => WrapNode(n)).ToList(); }
208 private IXmlNode WrapNode(XmlNode node)
210 switch (node.NodeType)
212 case XmlNodeType.Element:
213 return new XmlElementWrapper((XmlElement) node);
214 case XmlNodeType.XmlDeclaration:
215 return new XmlDeclarationWrapper((XmlDeclaration) node);
217 return new XmlNodeWrapper(node);
221 public IList<IXmlNode> Attributes
225 if (_node.Attributes == null)
228 return _node.Attributes.Cast<XmlAttribute>().Select(a => WrapNode(a)).ToList();
232 public IXmlNode ParentNode
236 XmlNode node = (_node is XmlAttribute)
237 ? ((XmlAttribute) _node).OwnerElement
243 return WrapNode(node);
249 get { return _node.Value; }
250 set { _node.Value = value; }
253 public IXmlNode AppendChild(IXmlNode newChild)
255 XmlNodeWrapper xmlNodeWrapper = (XmlNodeWrapper) newChild;
256 _node.AppendChild(xmlNodeWrapper._node);
263 get { return _node.Prefix; }
266 public string NamespaceURI
268 get { return _node.NamespaceURI; }
275 internal interface IXmlDocument : IXmlNode
277 IXmlNode CreateComment(string text);
278 IXmlNode CreateTextNode(string text);
279 IXmlNode CreateCDataSection(string data);
280 IXmlNode CreateWhitespace(string text);
281 IXmlNode CreateSignificantWhitespace(string text);
282 IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone);
283 IXmlNode CreateProcessingInstruction(string target, string data);
284 IXmlElement CreateElement(string elementName);
285 IXmlElement CreateElement(string qualifiedName, string namespaceURI);
286 IXmlNode CreateAttribute(string name, string value);
287 IXmlNode CreateAttribute(string qualifiedName, string namespaceURI, string value);
289 IXmlElement DocumentElement { get; }
292 internal interface IXmlDeclaration : IXmlNode
294 string Version { get; }
295 string Encoding { get; set; }
296 string Standalone { get; set; }
299 internal interface IXmlElement : IXmlNode
301 void SetAttributeNode(IXmlNode attribute);
302 string GetPrefixOfNamespace(string namespaceURI);
305 internal interface IXmlNode
307 XmlNodeType NodeType { get; }
308 string LocalName { get; }
309 IList<IXmlNode> ChildNodes { get; }
310 IList<IXmlNode> Attributes { get; }
311 IXmlNode ParentNode { get; }
312 string Value { get; set; }
313 IXmlNode AppendChild(IXmlNode newChild);
314 string NamespaceURI { get; }
315 object WrappedNode { get; }
319 #region XNodeWrappers
321 internal class XDeclarationWrapper : XObjectWrapper, IXmlDeclaration
323 internal readonly XDeclaration _declaration;
325 public XDeclarationWrapper(XDeclaration declaration)
328 _declaration = declaration;
331 public override XmlNodeType NodeType
333 get { return XmlNodeType.XmlDeclaration; }
336 public string Version
338 get { return _declaration.Version; }
341 public string Encoding
343 get { return _declaration.Encoding; }
344 set { _declaration.Encoding = value; }
347 public string Standalone
349 get { return _declaration.Standalone; }
350 set { _declaration.Standalone = value; }
354 internal class XDocumentWrapper : XContainerWrapper, IXmlDocument
356 private XDocument Document
358 get { return (XDocument)WrappedNode; }
361 public XDocumentWrapper(XDocument document)
366 public override IList<IXmlNode> ChildNodes
370 IList<IXmlNode> childNodes = base.ChildNodes;
372 if (Document.Declaration != null)
373 childNodes.Insert(0, new XDeclarationWrapper(Document.Declaration));
379 public IXmlNode CreateComment(string text)
381 return new XObjectWrapper(new XComment(text));
384 public IXmlNode CreateTextNode(string text)
386 return new XObjectWrapper(new XText(text));
389 public IXmlNode CreateCDataSection(string data)
391 return new XObjectWrapper(new XCData(data));
394 public IXmlNode CreateWhitespace(string text)
396 return new XObjectWrapper(new XText(text));
399 public IXmlNode CreateSignificantWhitespace(string text)
401 return new XObjectWrapper(new XText(text));
404 public IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone)
406 return new XDeclarationWrapper(new XDeclaration(version, encoding, standalone));
409 public IXmlNode CreateProcessingInstruction(string target, string data)
411 return new XProcessingInstructionWrapper(new XProcessingInstruction(target, data));
414 public IXmlElement CreateElement(string elementName)
416 return new XElementWrapper(new XElement(elementName));
419 public IXmlElement CreateElement(string qualifiedName, string namespaceURI)
421 string localName = MiscellaneousUtils.GetLocalName(qualifiedName);
422 return new XElementWrapper(new XElement(XName.Get(localName, namespaceURI)));
425 public IXmlNode CreateAttribute(string name, string value)
427 return new XAttributeWrapper(new XAttribute(name, value));
430 public IXmlNode CreateAttribute(string qualifiedName, string namespaceURI, string value)
432 string localName = MiscellaneousUtils.GetLocalName(qualifiedName);
433 return new XAttributeWrapper(new XAttribute(XName.Get(localName, namespaceURI), value));
436 public IXmlElement DocumentElement
440 if (Document.Root == null)
443 return new XElementWrapper(Document.Root);
447 public override IXmlNode AppendChild(IXmlNode newChild)
449 XDeclarationWrapper declarationWrapper = newChild as XDeclarationWrapper;
450 if (declarationWrapper != null)
452 Document.Declaration = declarationWrapper._declaration;
453 return declarationWrapper;
457 return base.AppendChild(newChild);
462 internal class XTextWrapper : XObjectWrapper
466 get { return (XText)WrappedNode; }
469 public XTextWrapper(XText text)
474 public override string Value
476 get { return Text.Value; }
477 set { Text.Value = value; }
480 public override IXmlNode ParentNode
484 if (Text.Parent == null)
487 return XContainerWrapper.WrapNode(Text.Parent);
492 internal class XCommentWrapper : XObjectWrapper
494 private XComment Text
496 get { return (XComment)WrappedNode; }
499 public XCommentWrapper(XComment text)
504 public override string Value
506 get { return Text.Value; }
507 set { Text.Value = value; }
510 public override IXmlNode ParentNode
514 if (Text.Parent == null)
517 return XContainerWrapper.WrapNode(Text.Parent);
522 internal class XProcessingInstructionWrapper : XObjectWrapper
524 private XProcessingInstruction ProcessingInstruction
526 get { return (XProcessingInstruction)WrappedNode; }
529 public XProcessingInstructionWrapper(XProcessingInstruction processingInstruction)
530 : base(processingInstruction)
534 public override string LocalName
536 get { return ProcessingInstruction.Target; }
539 public override string Value
541 get { return ProcessingInstruction.Data; }
542 set { ProcessingInstruction.Data = value; }
546 internal class XContainerWrapper : XObjectWrapper
548 private XContainer Container
550 get { return (XContainer)WrappedNode; }
553 public XContainerWrapper(XContainer container)
558 public override IList<IXmlNode> ChildNodes
560 get { return Container.Nodes().Select(n => WrapNode(n)).ToList(); }
563 public override IXmlNode ParentNode
567 if (Container.Parent == null)
570 return WrapNode(Container.Parent);
574 internal static IXmlNode WrapNode(XObject node)
576 if (node is XDocument)
577 return new XDocumentWrapper((XDocument)node);
578 else if (node is XElement)
579 return new XElementWrapper((XElement)node);
580 else if (node is XContainer)
581 return new XContainerWrapper((XContainer)node);
582 else if (node is XProcessingInstruction)
583 return new XProcessingInstructionWrapper((XProcessingInstruction)node);
584 else if (node is XText)
585 return new XTextWrapper((XText)node);
586 else if (node is XComment)
587 return new XCommentWrapper((XComment)node);
588 else if (node is XAttribute)
589 return new XAttributeWrapper((XAttribute) node);
591 return new XObjectWrapper(node);
594 public override IXmlNode AppendChild(IXmlNode newChild)
596 Container.Add(newChild.WrappedNode);
601 internal class XObjectWrapper : IXmlNode
603 private readonly XObject _xmlObject;
605 public XObjectWrapper(XObject xmlObject)
607 _xmlObject = xmlObject;
610 public object WrappedNode
612 get { return _xmlObject; }
615 public virtual XmlNodeType NodeType
617 get { return _xmlObject.NodeType; }
620 public virtual string LocalName
625 public virtual IList<IXmlNode> ChildNodes
627 get { return new List<IXmlNode>(); }
630 public virtual IList<IXmlNode> Attributes
635 public virtual IXmlNode ParentNode
640 public virtual string Value
643 set { throw new InvalidOperationException(); }
646 public virtual IXmlNode AppendChild(IXmlNode newChild)
648 throw new InvalidOperationException();
651 public virtual string NamespaceURI
657 internal class XAttributeWrapper : XObjectWrapper
659 private XAttribute Attribute
661 get { return (XAttribute)WrappedNode; }
664 public XAttributeWrapper(XAttribute attribute)
669 public override string Value
671 get { return Attribute.Value; }
672 set { Attribute.Value = value; }
675 public override string LocalName
677 get { return Attribute.Name.LocalName; }
680 public override string NamespaceURI
682 get { return Attribute.Name.NamespaceName; }
685 public override IXmlNode ParentNode
689 if (Attribute.Parent == null)
692 return XContainerWrapper.WrapNode(Attribute.Parent);
697 internal class XElementWrapper : XContainerWrapper, IXmlElement
699 private XElement Element
701 get { return (XElement) WrappedNode; }
704 public XElementWrapper(XElement element)
709 public void SetAttributeNode(IXmlNode attribute)
711 XObjectWrapper wrapper = (XObjectWrapper)attribute;
712 Element.Add(wrapper.WrappedNode);
715 public override IList<IXmlNode> Attributes
717 get { return Element.Attributes().Select(a => new XAttributeWrapper(a)).Cast<IXmlNode>().ToList(); }
720 public override string Value
722 get { return Element.Value; }
723 set { Element.Value = value; }
726 public override string LocalName
728 get { return Element.Name.LocalName; }
731 public override string NamespaceURI
733 get { return Element.Name.NamespaceName; }
736 public string GetPrefixOfNamespace(string namespaceURI)
738 return Element.GetPrefixOfNamespace(namespaceURI);
745 /// Converts XML to and from JSON.
747 public class XmlNodeConverter : JsonConverter
749 private const string TextName = "#text";
750 private const string CommentName = "#comment";
751 private const string CDataName = "#cdata-section";
752 private const string WhitespaceName = "#whitespace";
753 private const string SignificantWhitespaceName = "#significant-whitespace";
754 private const string DeclarationName = "?xml";
755 private const string JsonNamespaceUri = "http://james.newtonking.com/projects/json";
758 /// Gets or sets the name of the root element to insert when deserializing to XML if the JSON structure has produces multiple root elements.
760 /// <value>The name of the deserialize root element.</value>
761 public string DeserializeRootElementName { get; set; }
764 /// Gets or sets a flag to indicate whether to write the Json.NET array attribute.
765 /// This attribute helps preserve arrays when converting the written XML back to JSON.
767 /// <value><c>true</c> if the array attibute is written to the XML; otherwise, <c>false</c>.</value>
768 public bool WriteArrayAttribute { get; set; }
771 /// Gets or sets a value indicating whether to write the root JSON object.
773 /// <value><c>true</c> if the JSON root object is omitted; otherwise, <c>false</c>.</value>
774 public bool OmitRootObject { get; set; }
778 /// Writes the JSON representation of the object.
780 /// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
781 /// <param name="serializer">The calling serializer.</param>
782 /// <param name="value">The value.</param>
783 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
785 IXmlNode node = WrapXml(value);
787 XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
788 PushParentNamespaces(node, manager);
791 writer.WriteStartObject();
793 SerializeNode(writer, node, manager, !OmitRootObject);
796 writer.WriteEndObject();
799 private IXmlNode WrapXml(object value)
802 if (value is XObject)
803 return XContainerWrapper.WrapNode((XObject)value);
806 if (value is XmlNode)
807 return new XmlNodeWrapper((XmlNode)value);
810 throw new ArgumentException("Value must be an XML object.", "value");
813 private void PushParentNamespaces(IXmlNode node, XmlNamespaceManager manager)
815 List<IXmlNode> parentElements = null;
817 IXmlNode parent = node;
818 while ((parent = parent.ParentNode) != null)
820 if (parent.NodeType == XmlNodeType.Element)
822 if (parentElements == null)
823 parentElements = new List<IXmlNode>();
825 parentElements.Add(parent);
829 if (parentElements != null)
831 parentElements.Reverse();
833 foreach (IXmlNode parentElement in parentElements)
836 foreach (IXmlNode attribute in parentElement.Attributes)
838 if (attribute.NamespaceURI == "http://www.w3.org/2000/xmlns/" && attribute.LocalName != "xmlns")
839 manager.AddNamespace(attribute.LocalName, attribute.Value);
845 private string ResolveFullName(IXmlNode node, XmlNamespaceManager manager)
847 string prefix = (node.NamespaceURI == null || (node.LocalName == "xmlns" && node.NamespaceURI == "http://www.w3.org/2000/xmlns/"))
849 : manager.LookupPrefix(node.NamespaceURI);
851 if (!string.IsNullOrEmpty(prefix))
852 return prefix + ":" + node.LocalName;
854 return node.LocalName;
857 private string GetPropertyName(IXmlNode node, XmlNamespaceManager manager)
859 switch (node.NodeType)
861 case XmlNodeType.Attribute:
862 if (node.NamespaceURI == JsonNamespaceUri)
863 return "$" + node.LocalName;
865 return "@" + ResolveFullName(node, manager);
866 case XmlNodeType.CDATA:
868 case XmlNodeType.Comment:
870 case XmlNodeType.Element:
871 return ResolveFullName(node, manager);
872 case XmlNodeType.ProcessingInstruction:
873 return "?" + ResolveFullName(node, manager);
874 case XmlNodeType.XmlDeclaration:
875 return DeclarationName;
876 case XmlNodeType.SignificantWhitespace:
877 return SignificantWhitespaceName;
878 case XmlNodeType.Text:
880 case XmlNodeType.Whitespace:
881 return WhitespaceName;
883 throw new JsonSerializationException("Unexpected XmlNodeType when getting node name: " + node.NodeType);
887 private bool IsArray(IXmlNode node)
889 IXmlNode jsonArrayAttribute = (node.Attributes != null)
890 ? node.Attributes.SingleOrDefault(a => a.LocalName == "Array" && a.NamespaceURI == JsonNamespaceUri)
893 return (jsonArrayAttribute != null && XmlConvert.ToBoolean(jsonArrayAttribute.Value));
896 private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
898 // group nodes together by name
899 Dictionary<string, List<IXmlNode>> nodesGroupedByName = new Dictionary<string, List<IXmlNode>>();
901 for (int i = 0; i < node.ChildNodes.Count; i++)
903 IXmlNode childNode = node.ChildNodes[i];
904 string nodeName = GetPropertyName(childNode, manager);
906 List<IXmlNode> nodes;
907 if (!nodesGroupedByName.TryGetValue(nodeName, out nodes))
909 nodes = new List<IXmlNode>();
910 nodesGroupedByName.Add(nodeName, nodes);
913 nodes.Add(childNode);
916 // loop through grouped nodes. write single name instances as normal,
917 // write multiple names together in an array
918 foreach (KeyValuePair<string, List<IXmlNode>> nodeNameGroup in nodesGroupedByName)
920 List<IXmlNode> groupedNodes = nodeNameGroup.Value;
923 if (groupedNodes.Count == 1)
925 writeArray = IsArray(groupedNodes[0]);
934 SerializeNode(writer, groupedNodes[0], manager, writePropertyName);
938 string elementNames = nodeNameGroup.Key;
940 if (writePropertyName)
941 writer.WritePropertyName(elementNames);
943 writer.WriteStartArray();
945 for (int i = 0; i < groupedNodes.Count; i++)
947 SerializeNode(writer, groupedNodes[i], manager, false);
950 writer.WriteEndArray();
955 private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
957 switch (node.NodeType)
959 case XmlNodeType.Document:
960 case XmlNodeType.DocumentFragment:
961 SerializeGroupedNodes(writer, node, manager, writePropertyName);
963 case XmlNodeType.Element:
964 if (IsArray(node) && node.ChildNodes.All(n => n.LocalName == node.LocalName))
966 SerializeGroupedNodes(writer, node, manager, false);
970 foreach (IXmlNode attribute in node.Attributes)
972 if (attribute.NamespaceURI == "http://www.w3.org/2000/xmlns/")
974 string prefix = (attribute.LocalName != "xmlns")
975 ? attribute.LocalName
978 manager.AddNamespace(prefix, attribute.Value);
982 if (writePropertyName)
983 writer.WritePropertyName(GetPropertyName(node, manager));
985 if (ValueAttributes(node.Attributes).Count() == 0 && node.ChildNodes.Count == 1
986 && node.ChildNodes[0].NodeType == XmlNodeType.Text)
988 // write elements with a single text child as a name value pair
989 writer.WriteValue(node.ChildNodes[0].Value);
991 else if (node.ChildNodes.Count == 0 && CollectionUtils.IsNullOrEmpty(node.Attributes))
998 writer.WriteStartObject();
1000 for (int i = 0; i < node.Attributes.Count; i++)
1002 SerializeNode(writer, node.Attributes[i], manager, true);
1005 SerializeGroupedNodes(writer, node, manager, true);
1007 writer.WriteEndObject();
1012 case XmlNodeType.Comment:
1013 if (writePropertyName)
1014 writer.WriteComment(node.Value);
1016 case XmlNodeType.Attribute:
1017 case XmlNodeType.Text:
1018 case XmlNodeType.CDATA:
1019 case XmlNodeType.ProcessingInstruction:
1020 case XmlNodeType.Whitespace:
1021 case XmlNodeType.SignificantWhitespace:
1022 if (node.NamespaceURI == "http://www.w3.org/2000/xmlns/" && node.Value == JsonNamespaceUri)
1025 if (node.NamespaceURI == JsonNamespaceUri)
1027 if (node.LocalName == "Array")
1031 if (writePropertyName)
1032 writer.WritePropertyName(GetPropertyName(node, manager));
1033 writer.WriteValue(node.Value);
1035 case XmlNodeType.XmlDeclaration:
1036 IXmlDeclaration declaration = (IXmlDeclaration)node;
1037 writer.WritePropertyName(GetPropertyName(node, manager));
1038 writer.WriteStartObject();
1040 if (!string.IsNullOrEmpty(declaration.Version))
1042 writer.WritePropertyName("@version");
1043 writer.WriteValue(declaration.Version);
1045 if (!string.IsNullOrEmpty(declaration.Encoding))
1047 writer.WritePropertyName("@encoding");
1048 writer.WriteValue(declaration.Encoding);
1050 if (!string.IsNullOrEmpty(declaration.Standalone))
1052 writer.WritePropertyName("@standalone");
1053 writer.WriteValue(declaration.Standalone);
1056 writer.WriteEndObject();
1059 throw new JsonSerializationException("Unexpected XmlNodeType when serializing nodes: " + node.NodeType);
1066 /// Reads the JSON representation of the object.
1068 /// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
1069 /// <param name="objectType">Type of the object.</param>
1070 /// <param name="existingValue">The existing value of object being read.</param>
1071 /// <param name="serializer">The calling serializer.</param>
1072 /// <returns>The object value.</returns>
1073 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
1075 XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
1076 IXmlDocument document = null;
1077 IXmlNode rootNode = null;
1080 if (typeof(XObject).IsAssignableFrom(objectType))
1082 if (objectType != typeof (XDocument) && objectType != typeof (XElement))
1083 throw new JsonSerializationException("XmlNodeConverter only supports deserializing XDocument or XElement.");
1085 XDocument d = new XDocument();
1086 document = new XDocumentWrapper(d);
1087 rootNode = document;
1091 if (typeof(XmlNode).IsAssignableFrom(objectType))
1093 if (objectType != typeof (XmlDocument))
1094 throw new JsonSerializationException("XmlNodeConverter only supports deserializing XmlDocuments");
1096 XmlDocument d = new XmlDocument();
1097 document = new XmlDocumentWrapper(d);
1098 rootNode = document;
1102 if (document == null || rootNode == null)
1103 throw new JsonSerializationException("Unexpected type when converting XML: " + objectType);
1105 if (reader.TokenType != JsonToken.StartObject)
1106 throw new JsonSerializationException("XmlNodeConverter can only convert JSON that begins with an object.");
1108 if (!string.IsNullOrEmpty(DeserializeRootElementName))
1110 //rootNode = document.CreateElement(DeserializeRootElementName);
1111 //document.AppendChild(rootNode);
1112 ReadElement(reader, document, rootNode, DeserializeRootElementName, manager);
1117 DeserializeNode(reader, document, manager, rootNode);
1121 if (objectType == typeof(XElement))
1123 XElement element = (XElement)document.DocumentElement.WrappedNode;
1130 return document.WrappedNode;
1133 private void DeserializeValue(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, string propertyName, IXmlNode currentNode)
1135 switch (propertyName)
1138 currentNode.AppendChild(document.CreateTextNode(reader.Value.ToString()));
1141 currentNode.AppendChild(document.CreateCDataSection(reader.Value.ToString()));
1143 case WhitespaceName:
1144 currentNode.AppendChild(document.CreateWhitespace(reader.Value.ToString()));
1146 case SignificantWhitespaceName:
1147 currentNode.AppendChild(document.CreateSignificantWhitespace(reader.Value.ToString()));
1150 // processing instructions and the xml declaration start with ?
1151 if (!string.IsNullOrEmpty(propertyName) && propertyName[0] == '?')
1153 CreateInstruction(reader, document, currentNode, propertyName);
1157 if (reader.TokenType == JsonToken.StartArray)
1159 // handle nested arrays
1160 ReadArrayElements(reader, document, propertyName, currentNode, manager);
1164 // have to wait until attributes have been parsed before creating element
1165 // attributes may contain namespace info used by the element
1166 ReadElement(reader, document, currentNode, propertyName, manager);
1172 private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, XmlNamespaceManager manager)
1174 if (string.IsNullOrEmpty(propertyName))
1175 throw new JsonSerializationException("XmlNodeConverter cannot convert JSON with an empty property name to XML.");
1177 Dictionary<string, string> attributeNameValues = ReadAttributeElements(reader, manager);
1179 string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);
1181 IXmlElement element = CreateElement(propertyName, document, elementPrefix, manager);
1183 currentNode.AppendChild(element);
1185 // add attributes to newly created element
1186 foreach (KeyValuePair<string, string> nameValue in attributeNameValues)
1188 string attributePrefix = MiscellaneousUtils.GetPrefix(nameValue.Key);
1190 IXmlNode attribute = (!string.IsNullOrEmpty(attributePrefix))
1191 ? document.CreateAttribute(nameValue.Key, manager.LookupNamespace(attributePrefix), nameValue.Value)
1192 : document.CreateAttribute(nameValue.Key, nameValue.Value);
1194 element.SetAttributeNode(attribute);
1197 if (reader.TokenType == JsonToken.String)
1199 element.AppendChild(document.CreateTextNode(reader.Value.ToString()));
1201 else if (reader.TokenType == JsonToken.Integer)
1203 element.AppendChild(document.CreateTextNode(XmlConvert.ToString((long)reader.Value)));
1205 else if (reader.TokenType == JsonToken.Float)
1207 element.AppendChild(document.CreateTextNode(XmlConvert.ToString((double)reader.Value)));
1209 else if (reader.TokenType == JsonToken.Boolean)
1211 element.AppendChild(document.CreateTextNode(XmlConvert.ToString((bool)reader.Value)));
1213 else if (reader.TokenType == JsonToken.Date)
1215 DateTime d = (DateTime)reader.Value;
1216 element.AppendChild(document.CreateTextNode(XmlConvert.ToString(d, DateTimeUtils.ToSerializationMode(d.Kind))));
1218 else if (reader.TokenType == JsonToken.Null)
1220 // empty element. do nothing
1224 // finished element will have no children to deserialize
1225 if (reader.TokenType != JsonToken.EndObject)
1227 manager.PushScope();
1229 DeserializeNode(reader, document, manager, element);
1236 private void ReadArrayElements(JsonReader reader, IXmlDocument document, string propertyName, IXmlNode currentNode, XmlNamespaceManager manager)
1238 string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);
1240 IXmlElement nestedArrayElement = CreateElement(propertyName, document, elementPrefix, manager);
1242 currentNode.AppendChild(nestedArrayElement);
1245 while (reader.Read() && reader.TokenType != JsonToken.EndArray)
1247 DeserializeValue(reader, document, manager, propertyName, nestedArrayElement);
1251 if (WriteArrayAttribute)
1253 AddJsonArrayAttribute(nestedArrayElement, document);
1256 if (count == 1 && WriteArrayAttribute)
1258 IXmlElement arrayElement = nestedArrayElement.ChildNodes.CastValid<IXmlElement>().Single(n => n.LocalName == propertyName);
1259 AddJsonArrayAttribute(arrayElement, document);
1263 private void AddJsonArrayAttribute(IXmlElement element, IXmlDocument document)
1265 element.SetAttributeNode(document.CreateAttribute("json:Array", JsonNamespaceUri, "true"));
1268 // linq to xml doesn't automatically include prefixes via the namespace manager
1269 if (element is XElementWrapper)
1271 if (element.GetPrefixOfNamespace(JsonNamespaceUri) == null)
1273 element.SetAttributeNode(document.CreateAttribute("xmlns:json", "http://www.w3.org/2000/xmlns/", JsonNamespaceUri));
1279 private Dictionary<string, string> ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager)
1281 Dictionary<string, string> attributeNameValues = new Dictionary<string, string>();
1282 bool finishedAttributes = false;
1283 bool finishedElement = false;
1285 // a string token means the element only has a single text child
1286 if (reader.TokenType != JsonToken.String
1287 && reader.TokenType != JsonToken.Null
1288 && reader.TokenType != JsonToken.Boolean
1289 && reader.TokenType != JsonToken.Integer
1290 && reader.TokenType != JsonToken.Float
1291 && reader.TokenType != JsonToken.Date
1292 && reader.TokenType != JsonToken.StartConstructor)
1294 // read properties until first non-attribute is encountered
1295 while (!finishedAttributes && !finishedElement && reader.Read())
1297 switch (reader.TokenType)
1299 case JsonToken.PropertyName:
1300 string attributeName = reader.Value.ToString();
1301 string attributeValue;
1303 if (!string.IsNullOrEmpty(attributeName))
1305 char firstChar = attributeName[0];
1310 attributeName = attributeName.Substring(1);
1312 attributeValue = reader.Value.ToString();
1313 attributeNameValues.Add(attributeName, attributeValue);
1315 string namespacePrefix;
1316 if (IsNamespaceAttribute(attributeName, out namespacePrefix))
1318 manager.AddNamespace(namespacePrefix, attributeValue);
1322 attributeName = attributeName.Substring(1);
1324 attributeValue = reader.Value.ToString();
1326 // check that JsonNamespaceUri is in scope
1327 // if it isn't then add it to document and namespace manager
1328 string jsonPrefix = manager.LookupPrefix(JsonNamespaceUri);
1329 if (jsonPrefix == null)
1331 // ensure that the prefix used is free
1333 while (manager.LookupNamespace("json" + i) != null)
1335 i = i.GetValueOrDefault() + 1;
1337 jsonPrefix = "json" + i;
1339 attributeNameValues.Add("xmlns:" + jsonPrefix, JsonNamespaceUri);
1340 manager.AddNamespace(jsonPrefix, JsonNamespaceUri);
1343 attributeNameValues.Add(jsonPrefix + ":" + attributeName, attributeValue);
1346 finishedAttributes = true;
1352 finishedAttributes = true;
1356 case JsonToken.EndObject:
1357 finishedElement = true;
1360 throw new JsonSerializationException("Unexpected JsonToken: " + reader.TokenType);
1365 return attributeNameValues;
1368 private void CreateInstruction(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName)
1370 if (propertyName == DeclarationName)
1372 string version = null;
1373 string encoding = null;
1374 string standalone = null;
1375 while (reader.Read() && reader.TokenType != JsonToken.EndObject)
1377 switch (reader.Value.ToString())
1381 version = reader.Value.ToString();
1385 encoding = reader.Value.ToString();
1389 standalone = reader.Value.ToString();
1392 throw new JsonSerializationException("Unexpected property name encountered while deserializing XmlDeclaration: " + reader.Value);
1396 IXmlNode declaration = document.CreateXmlDeclaration(version, encoding, standalone);
1397 currentNode.AppendChild(declaration);
1401 IXmlNode instruction = document.CreateProcessingInstruction(propertyName.Substring(1), reader.Value.ToString());
1402 currentNode.AppendChild(instruction);
1406 private IXmlElement CreateElement(string elementName, IXmlDocument document, string elementPrefix, XmlNamespaceManager manager)
1408 return (!string.IsNullOrEmpty(elementPrefix))
1409 ? document.CreateElement(elementName, manager.LookupNamespace(elementPrefix))
1410 : document.CreateElement(elementName);
1413 private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, IXmlNode currentNode)
1417 switch (reader.TokenType)
1419 case JsonToken.PropertyName:
1420 if (currentNode.NodeType == XmlNodeType.Document && document.DocumentElement != null)
1421 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.");
1423 string propertyName = reader.Value.ToString();
1426 if (reader.TokenType == JsonToken.StartArray)
1429 while (reader.Read() && reader.TokenType != JsonToken.EndArray)
1431 DeserializeValue(reader, document, manager, propertyName, currentNode);
1435 if (count == 1 && WriteArrayAttribute)
1437 IXmlElement arrayElement = currentNode.ChildNodes.CastValid<IXmlElement>().Single(n => n.LocalName == propertyName);
1438 AddJsonArrayAttribute(arrayElement, document);
1443 DeserializeValue(reader, document, manager, propertyName, currentNode);
1446 case JsonToken.StartConstructor:
1447 string constructorName = reader.Value.ToString();
1449 while (reader.Read() && reader.TokenType != JsonToken.EndConstructor)
1451 DeserializeValue(reader, document, manager, constructorName, currentNode);
1454 case JsonToken.Comment:
1455 currentNode.AppendChild(document.CreateComment((string)reader.Value));
1457 case JsonToken.EndObject:
1458 case JsonToken.EndArray:
1461 throw new JsonSerializationException("Unexpected JsonToken when deserializing node: " + reader.TokenType);
1463 } while (reader.TokenType == JsonToken.PropertyName || reader.Read());
1464 // don't read if current token is a property. token was already read when parsing element attributes
1468 /// Checks if the attributeName is a namespace attribute.
1470 /// <param name="attributeName">Attribute name to test.</param>
1471 /// <param name="prefix">The attribute name prefix if it has one, otherwise an empty string.</param>
1472 /// <returns>True if attribute name is for a namespace attribute, otherwise false.</returns>
1473 private bool IsNamespaceAttribute(string attributeName, out string prefix)
1475 if (attributeName.StartsWith("xmlns", StringComparison.Ordinal))
1477 if (attributeName.Length == 5)
1479 prefix = string.Empty;
1482 else if (attributeName[5] == ':')
1484 prefix = attributeName.Substring(6, attributeName.Length - 6);
1492 private IEnumerable<IXmlNode> ValueAttributes(IEnumerable<IXmlNode> c)
1494 return c.Where(a => a.NamespaceURI != JsonNamespaceUri);
1499 /// Determines whether this instance can convert the specified value type.
1501 /// <param name="valueType">Type of the value.</param>
1503 /// <c>true</c> if this instance can convert the specified value type; otherwise, <c>false</c>.
1505 public override bool CanConvert(Type valueType)
1508 if (typeof(XObject).IsAssignableFrom(valueType))
1512 if (typeof(XmlNode).IsAssignableFrom(valueType))