All files
[pithos-ms-client] / trunk / Libraries / Json40r2 / Source / Src / Newtonsoft.Json / Converters / XmlNodeConverter.cs
1 #region License
2 // Copyright (c) 2007 James Newton-King
3 //
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
11 // conditions:
12 //
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
15 //
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.
24 #endregion
25
26 #if !SILVERLIGHT || WINDOWS_PHONE
27 using System;
28 using System.Collections.Generic;
29 using System.Xml;
30 #if !NET20
31 using System.Xml.Linq;
32 #endif
33 using Newtonsoft.Json.Utilities;
34 using System.Linq;
35
36 namespace Newtonsoft.Json.Converters
37 {
38   #region XmlNodeWrappers
39 #if !SILVERLIGHT
40   internal class XmlDocumentWrapper : XmlNodeWrapper, IXmlDocument
41   {
42     private XmlDocument _document;
43
44     public XmlDocumentWrapper(XmlDocument document)
45       : base(document)
46     {
47       _document = document;
48     }
49
50     public IXmlNode CreateComment(string data)
51     {
52       return new XmlNodeWrapper(_document.CreateComment(data));
53     }
54
55     public IXmlNode CreateTextNode(string text)
56     {
57       return new XmlNodeWrapper(_document.CreateTextNode(text));
58     }
59
60     public IXmlNode CreateCDataSection(string data)
61     {
62       return new XmlNodeWrapper(_document.CreateCDataSection(data));
63     }
64
65     public IXmlNode CreateWhitespace(string text)
66     {
67       return new XmlNodeWrapper(_document.CreateWhitespace(text));
68     }
69
70     public IXmlNode CreateSignificantWhitespace(string text)
71     {
72       return new XmlNodeWrapper(_document.CreateSignificantWhitespace(text));
73     }
74
75     public IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone)
76     {
77       return new XmlNodeWrapper(_document.CreateXmlDeclaration(version, encoding, standalone));
78     }
79
80     public IXmlNode CreateProcessingInstruction(string target, string data)
81     {
82       return new XmlNodeWrapper(_document.CreateProcessingInstruction(target, data));
83     }
84
85     public IXmlElement CreateElement(string elementName)
86     {
87       return new XmlElementWrapper(_document.CreateElement(elementName));
88     }
89
90     public IXmlElement CreateElement(string qualifiedName, string namespaceURI)
91     {
92       return new XmlElementWrapper(_document.CreateElement(qualifiedName, namespaceURI));
93     }
94
95     public IXmlNode CreateAttribute(string name, string value)
96     {
97       XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(name));
98       attribute.Value = value;
99
100       return attribute;
101     }
102
103     public IXmlNode CreateAttribute(string qualifiedName, string namespaceURI, string value)
104     {
105       XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(qualifiedName, namespaceURI));
106       attribute.Value = value;
107
108       return attribute;
109     }
110
111     public IXmlElement DocumentElement
112     {
113       get
114       {
115         if (_document.DocumentElement == null)
116           return null;
117
118         return new XmlElementWrapper(_document.DocumentElement);
119       }
120     }
121   }
122
123   internal class XmlElementWrapper : XmlNodeWrapper, IXmlElement
124   {
125     private XmlElement _element;
126
127     public XmlElementWrapper(XmlElement element)
128       : base(element)
129     {
130       _element = element;
131     }
132
133     public void SetAttributeNode(IXmlNode attribute)
134     {
135       XmlNodeWrapper xmlAttributeWrapper = (XmlNodeWrapper)attribute;
136
137       _element.SetAttributeNode((XmlAttribute) xmlAttributeWrapper.WrappedNode);
138     }
139
140     public string GetPrefixOfNamespace(string namespaceURI)
141     {
142       return _element.GetPrefixOfNamespace(namespaceURI);
143     }
144   }
145
146   internal class XmlDeclarationWrapper : XmlNodeWrapper, IXmlDeclaration
147   {
148     private XmlDeclaration _declaration;
149
150     public XmlDeclarationWrapper(XmlDeclaration declaration)
151       : base(declaration)
152     {
153       _declaration = declaration;
154     }
155
156     public string Version
157     {
158       get { return _declaration.Version; }
159     }
160
161     public string Encoding
162     {
163       get { return _declaration.Encoding; }
164       set { _declaration.Encoding = value; }
165     }
166
167     public string Standalone
168     {
169       get { return _declaration.Standalone; }
170       set { _declaration.Standalone = value; }
171     }
172   }
173
174   internal class XmlNodeWrapper : IXmlNode
175   {
176     private readonly XmlNode _node;
177
178     public XmlNodeWrapper(XmlNode node)
179     {
180       _node = node;
181     }
182
183     public object WrappedNode
184     {
185       get { return _node; }
186     }
187
188     public XmlNodeType NodeType
189     {
190       get { return _node.NodeType; }
191     }
192
193     public string Name
194     {
195       get { return _node.Name; }
196     }
197
198     public string LocalName
199     {
200       get { return _node.LocalName; }
201     }
202
203     public IList<IXmlNode> ChildNodes
204     {
205       get { return _node.ChildNodes.Cast<XmlNode>().Select(n => WrapNode(n)).ToList(); }
206     }
207
208     private IXmlNode WrapNode(XmlNode node)
209     {
210       switch (node.NodeType)
211       {
212         case XmlNodeType.Element:
213           return new XmlElementWrapper((XmlElement) node);
214         case XmlNodeType.XmlDeclaration:
215           return new XmlDeclarationWrapper((XmlDeclaration) node);
216         default:
217           return new XmlNodeWrapper(node);
218       }
219     }
220
221     public IList<IXmlNode> Attributes
222     {
223       get
224       {
225         if (_node.Attributes == null)
226           return null;
227
228         return _node.Attributes.Cast<XmlAttribute>().Select(a => WrapNode(a)).ToList();
229       }
230     }
231
232     public IXmlNode ParentNode
233     {
234       get
235       {
236         XmlNode node = (_node is XmlAttribute)
237                          ? ((XmlAttribute) _node).OwnerElement
238                          : _node.ParentNode;
239         
240         if (node == null)
241           return null;
242
243         return WrapNode(node);
244       }
245     }
246
247     public string Value
248     {
249       get { return _node.Value; }
250       set { _node.Value = value; }
251     }
252
253     public IXmlNode AppendChild(IXmlNode newChild)
254     {
255       XmlNodeWrapper xmlNodeWrapper = (XmlNodeWrapper) newChild;
256       _node.AppendChild(xmlNodeWrapper._node);
257
258       return newChild;
259     }
260
261     public string Prefix
262     {
263       get { return _node.Prefix; }
264     }
265
266     public string NamespaceURI
267     {
268       get { return _node.NamespaceURI; }
269     }
270   }
271 #endif
272   #endregion
273
274   #region Interfaces
275   internal interface IXmlDocument : IXmlNode
276   {
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);
288
289     IXmlElement DocumentElement { get; }
290   }
291
292   internal interface IXmlDeclaration : IXmlNode
293   {
294     string Version { get; }
295     string Encoding { get; set; }
296     string Standalone { get; set; }
297   }
298
299   internal interface IXmlElement : IXmlNode
300   {
301     void SetAttributeNode(IXmlNode attribute);
302     string GetPrefixOfNamespace(string namespaceURI);
303   }
304
305   internal interface IXmlNode
306   {
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; }
316   }
317   #endregion
318
319   #region XNodeWrappers
320 #if !NET20
321   internal class XDeclarationWrapper : XObjectWrapper, IXmlDeclaration
322   {
323     internal readonly XDeclaration _declaration;
324
325     public XDeclarationWrapper(XDeclaration declaration)
326       : base(null)
327     {
328       _declaration = declaration;
329     }
330
331     public override XmlNodeType NodeType
332     {
333       get { return XmlNodeType.XmlDeclaration; }
334     }
335
336     public string Version
337     {
338       get { return _declaration.Version; }
339     }
340
341     public string Encoding
342     {
343       get { return _declaration.Encoding; }
344       set { _declaration.Encoding = value; }
345     }
346
347     public string Standalone
348     {
349       get { return _declaration.Standalone; }
350       set { _declaration.Standalone = value; }
351     }
352   }
353
354   internal class XDocumentWrapper : XContainerWrapper, IXmlDocument
355   {
356     private XDocument Document
357     {
358       get { return (XDocument)WrappedNode; }
359     }
360
361     public XDocumentWrapper(XDocument document)
362       : base(document)
363     {
364     }
365
366     public override IList<IXmlNode> ChildNodes
367     {
368       get
369       {
370         IList<IXmlNode> childNodes = base.ChildNodes;
371
372         if (Document.Declaration != null)
373           childNodes.Insert(0, new XDeclarationWrapper(Document.Declaration));
374
375         return childNodes;
376       }
377     }
378
379     public IXmlNode CreateComment(string text)
380     {
381       return new XObjectWrapper(new XComment(text));
382     }
383
384     public IXmlNode CreateTextNode(string text)
385     {
386       return new XObjectWrapper(new XText(text));
387     }
388
389     public IXmlNode CreateCDataSection(string data)
390     {
391       return new XObjectWrapper(new XCData(data));
392     }
393
394     public IXmlNode CreateWhitespace(string text)
395     {
396       return new XObjectWrapper(new XText(text));
397     }
398
399     public IXmlNode CreateSignificantWhitespace(string text)
400     {
401       return new XObjectWrapper(new XText(text));
402     }
403
404     public IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone)
405     {
406       return new XDeclarationWrapper(new XDeclaration(version, encoding, standalone));
407     }
408
409     public IXmlNode CreateProcessingInstruction(string target, string data)
410     {
411       return new XProcessingInstructionWrapper(new XProcessingInstruction(target, data));
412     }
413
414     public IXmlElement CreateElement(string elementName)
415     {
416       return new XElementWrapper(new XElement(elementName));
417     }
418
419     public IXmlElement CreateElement(string qualifiedName, string namespaceURI)
420     {
421       string localName = MiscellaneousUtils.GetLocalName(qualifiedName);
422       return new XElementWrapper(new XElement(XName.Get(localName, namespaceURI)));
423     }
424
425     public IXmlNode CreateAttribute(string name, string value)
426     {
427       return new XAttributeWrapper(new XAttribute(name, value));
428     }
429
430     public IXmlNode CreateAttribute(string qualifiedName, string namespaceURI, string value)
431     {
432       string localName = MiscellaneousUtils.GetLocalName(qualifiedName);
433       return new XAttributeWrapper(new XAttribute(XName.Get(localName, namespaceURI), value));
434     }
435
436     public IXmlElement DocumentElement
437     {
438       get
439       {
440         if (Document.Root == null)
441           return null;
442
443         return new XElementWrapper(Document.Root);
444       }
445     }
446
447     public override IXmlNode AppendChild(IXmlNode newChild)
448     {
449       XDeclarationWrapper declarationWrapper = newChild as XDeclarationWrapper;
450       if (declarationWrapper != null)
451       {
452         Document.Declaration = declarationWrapper._declaration;
453         return declarationWrapper;
454       }
455       else
456       {
457         return base.AppendChild(newChild);
458       }
459     }
460   }
461
462   internal class XTextWrapper : XObjectWrapper
463   {
464     private XText Text
465     {
466       get { return (XText)WrappedNode; }
467     }
468
469     public XTextWrapper(XText text)
470       : base(text)
471     {
472     }
473
474     public override string Value
475     {
476       get { return Text.Value; }
477       set { Text.Value = value; }
478     }
479
480     public override IXmlNode ParentNode
481     {
482       get
483       {
484         if (Text.Parent == null)
485           return null;
486         
487         return XContainerWrapper.WrapNode(Text.Parent);
488       }
489     }
490   }
491
492   internal class XCommentWrapper : XObjectWrapper
493   {
494     private XComment Text
495     {
496       get { return (XComment)WrappedNode; }
497     }
498
499     public XCommentWrapper(XComment text)
500       : base(text)
501     {
502     }
503
504     public override string Value
505     {
506       get { return Text.Value; }
507       set { Text.Value = value; }
508     }
509
510     public override IXmlNode ParentNode
511     {
512       get
513       {
514         if (Text.Parent == null)
515           return null;
516
517         return XContainerWrapper.WrapNode(Text.Parent);
518       }
519     }
520   }
521
522   internal class XProcessingInstructionWrapper : XObjectWrapper
523   {
524     private XProcessingInstruction ProcessingInstruction
525     {
526       get { return (XProcessingInstruction)WrappedNode; }
527     }
528
529     public XProcessingInstructionWrapper(XProcessingInstruction processingInstruction)
530       : base(processingInstruction)
531     {
532     }
533
534     public override string LocalName
535     {
536       get { return ProcessingInstruction.Target; }
537     }
538
539     public override string Value
540     {
541       get { return ProcessingInstruction.Data; }
542       set { ProcessingInstruction.Data = value; }
543     }
544   }
545
546   internal class XContainerWrapper : XObjectWrapper
547   {
548     private XContainer Container
549     {
550       get { return (XContainer)WrappedNode; }
551     }
552
553     public XContainerWrapper(XContainer container)
554       : base(container)
555     {
556     }
557
558     public override IList<IXmlNode> ChildNodes
559     {
560       get { return Container.Nodes().Select(n => WrapNode(n)).ToList(); }
561     }
562
563     public override IXmlNode ParentNode
564     {
565       get
566       {
567         if (Container.Parent == null)
568           return null;
569         
570         return WrapNode(Container.Parent);
571       }
572     }
573
574     internal static IXmlNode WrapNode(XObject node)
575     {
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);
590       else
591         return new XObjectWrapper(node);
592     }
593
594     public override IXmlNode AppendChild(IXmlNode newChild)
595     {
596       Container.Add(newChild.WrappedNode);
597       return newChild;
598     }
599   }
600
601   internal class XObjectWrapper : IXmlNode
602   {
603     private readonly XObject _xmlObject;
604
605     public XObjectWrapper(XObject xmlObject)
606     {
607       _xmlObject = xmlObject;
608     }
609
610     public object WrappedNode
611     {
612       get { return _xmlObject; }
613     }
614
615     public virtual XmlNodeType NodeType
616     {
617       get { return _xmlObject.NodeType; }
618     }
619
620     public virtual string LocalName
621     {
622       get { return null; }
623     }
624
625     public virtual IList<IXmlNode> ChildNodes
626     {
627       get { return new List<IXmlNode>(); }
628     }
629
630     public virtual IList<IXmlNode> Attributes
631     {
632       get { return null; }
633     }
634
635     public virtual IXmlNode ParentNode
636     {
637       get { return null; }
638     }
639
640     public virtual string Value
641     {
642       get { return null; }
643       set { throw new InvalidOperationException(); }
644     }
645
646     public virtual IXmlNode AppendChild(IXmlNode newChild)
647     {
648       throw new InvalidOperationException();
649     }
650
651     public virtual string NamespaceURI
652     {
653       get { return null; }
654     }
655   }
656
657   internal class XAttributeWrapper : XObjectWrapper
658   {
659     private XAttribute Attribute
660     {
661       get { return (XAttribute)WrappedNode; }
662     }
663
664     public XAttributeWrapper(XAttribute attribute)
665       : base(attribute)
666     {
667     }
668
669     public override string Value
670     {
671       get { return Attribute.Value; }
672       set { Attribute.Value = value; }
673     }
674
675     public override string LocalName
676     {
677       get { return Attribute.Name.LocalName; }
678     }
679
680     public override string NamespaceURI
681     {
682       get { return Attribute.Name.NamespaceName; }
683     }
684
685     public override IXmlNode ParentNode
686     {
687       get
688       {
689         if (Attribute.Parent == null)
690           return null;
691
692         return XContainerWrapper.WrapNode(Attribute.Parent);
693       }
694     }
695   }
696
697   internal class XElementWrapper : XContainerWrapper, IXmlElement
698   {
699     private XElement Element
700     {
701       get { return (XElement) WrappedNode; }
702     }
703
704     public XElementWrapper(XElement element)
705       : base(element)
706     {
707     }
708
709     public void SetAttributeNode(IXmlNode attribute)
710     {
711       XObjectWrapper wrapper = (XObjectWrapper)attribute;
712       Element.Add(wrapper.WrappedNode);
713     }
714
715     public override IList<IXmlNode> Attributes
716     {
717       get { return Element.Attributes().Select(a => new XAttributeWrapper(a)).Cast<IXmlNode>().ToList(); }
718     }
719
720     public override string Value
721     {
722       get { return Element.Value; }
723       set { Element.Value = value; }
724     }
725
726     public override string LocalName
727     {
728       get { return Element.Name.LocalName; }
729     }
730
731     public override string NamespaceURI
732     {
733       get { return Element.Name.NamespaceName; }
734     }
735
736     public string GetPrefixOfNamespace(string namespaceURI)
737     {
738       return Element.GetPrefixOfNamespace(namespaceURI);
739     }
740   }
741 #endif
742   #endregion
743
744   /// <summary>
745   /// Converts XML to and from JSON.
746   /// </summary>
747   public class XmlNodeConverter : JsonConverter
748   {
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";
756
757     /// <summary>
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.
759     /// </summary>
760     /// <value>The name of the deserialize root element.</value>
761     public string DeserializeRootElementName { get; set; }
762
763     /// <summary>
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.
766     /// </summary>
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; }
769
770     /// <summary>
771     /// Gets or sets a value indicating whether to write the root JSON object.
772     /// </summary>
773     /// <value><c>true</c> if the JSON root object is omitted; otherwise, <c>false</c>.</value>
774     public bool OmitRootObject { get; set; }
775
776     #region Writing
777     /// <summary>
778     /// Writes the JSON representation of the object.
779     /// </summary>
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)
784     {
785       IXmlNode node = WrapXml(value);
786
787       XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
788       PushParentNamespaces(node, manager);
789
790       if (!OmitRootObject)
791         writer.WriteStartObject();
792
793       SerializeNode(writer, node, manager, !OmitRootObject);
794       
795       if (!OmitRootObject)
796         writer.WriteEndObject();
797     }
798
799     private IXmlNode WrapXml(object value)
800     {
801 #if !NET20
802       if (value is XObject)
803         return XContainerWrapper.WrapNode((XObject)value);
804 #endif
805 #if !SILVERLIGHT
806       if (value is XmlNode)
807         return new XmlNodeWrapper((XmlNode)value);
808 #endif
809       
810       throw new ArgumentException("Value must be an XML object.", "value");
811     }
812
813     private void PushParentNamespaces(IXmlNode node, XmlNamespaceManager manager)
814     {
815       List<IXmlNode> parentElements = null;
816
817       IXmlNode parent = node;
818       while ((parent = parent.ParentNode) != null)
819       {
820         if (parent.NodeType == XmlNodeType.Element)
821         {
822           if (parentElements == null)
823             parentElements = new List<IXmlNode>();
824
825           parentElements.Add(parent);
826         }
827       }
828
829       if (parentElements != null)
830       {
831         parentElements.Reverse();
832
833         foreach (IXmlNode parentElement in parentElements)
834         {
835           manager.PushScope();
836           foreach (IXmlNode attribute in parentElement.Attributes)
837           {
838             if (attribute.NamespaceURI == "http://www.w3.org/2000/xmlns/" && attribute.LocalName != "xmlns")
839               manager.AddNamespace(attribute.LocalName, attribute.Value);
840           }
841         }
842       }
843     }
844
845     private string ResolveFullName(IXmlNode node, XmlNamespaceManager manager)
846     {
847       string prefix = (node.NamespaceURI == null || (node.LocalName == "xmlns" && node.NamespaceURI == "http://www.w3.org/2000/xmlns/"))
848                         ? null
849                         : manager.LookupPrefix(node.NamespaceURI);
850
851       if (!string.IsNullOrEmpty(prefix))
852         return prefix + ":" + node.LocalName;
853       else
854         return node.LocalName;
855     }
856
857     private string GetPropertyName(IXmlNode node, XmlNamespaceManager manager)
858     {
859       switch (node.NodeType)
860       {
861         case XmlNodeType.Attribute:
862           if (node.NamespaceURI == JsonNamespaceUri)
863             return "$" + node.LocalName;
864           else
865             return "@" + ResolveFullName(node, manager);
866         case XmlNodeType.CDATA:
867           return CDataName;
868         case XmlNodeType.Comment:
869           return CommentName;
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:
879           return TextName;
880         case XmlNodeType.Whitespace:
881           return WhitespaceName;
882         default:
883           throw new JsonSerializationException("Unexpected XmlNodeType when getting node name: " + node.NodeType);
884       }
885     }
886
887     private bool IsArray(IXmlNode node)
888     {
889       IXmlNode jsonArrayAttribute = (node.Attributes != null)
890                                       ? node.Attributes.SingleOrDefault(a => a.LocalName == "Array" && a.NamespaceURI == JsonNamespaceUri)
891                                       : null;
892       
893       return (jsonArrayAttribute != null && XmlConvert.ToBoolean(jsonArrayAttribute.Value));
894     }
895
896     private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
897     {
898       // group nodes together by name
899       Dictionary<string, List<IXmlNode>> nodesGroupedByName = new Dictionary<string, List<IXmlNode>>();
900
901       for (int i = 0; i < node.ChildNodes.Count; i++)
902       {
903         IXmlNode childNode = node.ChildNodes[i];
904         string nodeName = GetPropertyName(childNode, manager);
905
906         List<IXmlNode> nodes;
907         if (!nodesGroupedByName.TryGetValue(nodeName, out nodes))
908         {
909           nodes = new List<IXmlNode>();
910           nodesGroupedByName.Add(nodeName, nodes);
911         }
912
913         nodes.Add(childNode);
914       }
915
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)
919       {
920         List<IXmlNode> groupedNodes = nodeNameGroup.Value;
921         bool writeArray;
922
923         if (groupedNodes.Count == 1)
924         {
925           writeArray = IsArray(groupedNodes[0]);
926         }
927         else
928         {
929           writeArray = true;
930         }
931
932         if (!writeArray)
933         {
934           SerializeNode(writer, groupedNodes[0], manager, writePropertyName);
935         }
936         else
937         {
938           string elementNames = nodeNameGroup.Key;
939
940           if (writePropertyName)
941             writer.WritePropertyName(elementNames);
942
943           writer.WriteStartArray();
944
945           for (int i = 0; i < groupedNodes.Count; i++)
946           {
947             SerializeNode(writer, groupedNodes[i], manager, false);
948           }
949
950           writer.WriteEndArray();
951         }
952       }
953     }
954
955     private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
956     {
957       switch (node.NodeType)
958       {
959         case XmlNodeType.Document:
960         case XmlNodeType.DocumentFragment:
961           SerializeGroupedNodes(writer, node, manager, writePropertyName);
962           break;
963         case XmlNodeType.Element:
964           if (IsArray(node) && node.ChildNodes.All(n => n.LocalName == node.LocalName))
965           {
966             SerializeGroupedNodes(writer, node, manager, false);
967           }
968           else
969           {
970             foreach (IXmlNode attribute in node.Attributes)
971             {
972               if (attribute.NamespaceURI == "http://www.w3.org/2000/xmlns/")
973               {
974                 string prefix = (attribute.LocalName != "xmlns")
975                                   ? attribute.LocalName
976                                   : string.Empty;
977
978                 manager.AddNamespace(prefix, attribute.Value);
979               }
980             }
981
982             if (writePropertyName)
983               writer.WritePropertyName(GetPropertyName(node, manager));
984
985             if (ValueAttributes(node.Attributes).Count() == 0 && node.ChildNodes.Count == 1
986                 && node.ChildNodes[0].NodeType == XmlNodeType.Text)
987             {
988               // write elements with a single text child as a name value pair
989               writer.WriteValue(node.ChildNodes[0].Value);
990             }
991             else if (node.ChildNodes.Count == 0 && CollectionUtils.IsNullOrEmpty(node.Attributes))
992             {
993               // empty element
994               writer.WriteNull();
995             }
996             else
997             {
998               writer.WriteStartObject();
999
1000               for (int i = 0; i < node.Attributes.Count; i++)
1001               {
1002                 SerializeNode(writer, node.Attributes[i], manager, true);
1003               }
1004
1005               SerializeGroupedNodes(writer, node, manager, true);
1006
1007               writer.WriteEndObject();
1008             }
1009           }
1010
1011           break;
1012         case XmlNodeType.Comment:
1013           if (writePropertyName)
1014             writer.WriteComment(node.Value);
1015           break;
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)
1023             return;
1024
1025           if (node.NamespaceURI == JsonNamespaceUri)
1026           {
1027             if (node.LocalName == "Array")
1028               return;
1029           }
1030
1031           if (writePropertyName)
1032             writer.WritePropertyName(GetPropertyName(node, manager));
1033           writer.WriteValue(node.Value);
1034           break;
1035         case XmlNodeType.XmlDeclaration:
1036           IXmlDeclaration declaration = (IXmlDeclaration)node;
1037           writer.WritePropertyName(GetPropertyName(node, manager));
1038           writer.WriteStartObject();
1039
1040           if (!string.IsNullOrEmpty(declaration.Version))
1041           {
1042             writer.WritePropertyName("@version");
1043             writer.WriteValue(declaration.Version);
1044           }
1045           if (!string.IsNullOrEmpty(declaration.Encoding))
1046           {
1047             writer.WritePropertyName("@encoding");
1048             writer.WriteValue(declaration.Encoding);
1049           }
1050           if (!string.IsNullOrEmpty(declaration.Standalone))
1051           {
1052             writer.WritePropertyName("@standalone");
1053             writer.WriteValue(declaration.Standalone);
1054           }
1055
1056           writer.WriteEndObject();
1057           break;
1058         default:
1059           throw new JsonSerializationException("Unexpected XmlNodeType when serializing nodes: " + node.NodeType);
1060       }
1061     }
1062     #endregion
1063
1064     #region Reading
1065     /// <summary>
1066     /// Reads the JSON representation of the object.
1067     /// </summary>
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)
1074     {
1075       XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
1076       IXmlDocument document = null;
1077       IXmlNode rootNode = null;
1078
1079 #if !NET20
1080       if (typeof(XObject).IsAssignableFrom(objectType))
1081       {
1082         if (objectType != typeof (XDocument) && objectType != typeof (XElement))
1083           throw new JsonSerializationException("XmlNodeConverter only supports deserializing XDocument or XElement.");
1084
1085         XDocument d = new XDocument();
1086         document = new XDocumentWrapper(d);
1087         rootNode = document;
1088       }
1089 #endif
1090 #if !SILVERLIGHT
1091       if (typeof(XmlNode).IsAssignableFrom(objectType))
1092       {
1093         if (objectType != typeof (XmlDocument))
1094           throw new JsonSerializationException("XmlNodeConverter only supports deserializing XmlDocuments");
1095
1096         XmlDocument d = new XmlDocument();
1097         document = new XmlDocumentWrapper(d);
1098         rootNode = document;
1099       }
1100 #endif
1101       
1102       if (document == null || rootNode == null)
1103         throw new JsonSerializationException("Unexpected type when converting XML: " + objectType);
1104
1105       if (reader.TokenType != JsonToken.StartObject)
1106         throw new JsonSerializationException("XmlNodeConverter can only convert JSON that begins with an object.");
1107
1108       if (!string.IsNullOrEmpty(DeserializeRootElementName))
1109       {
1110         //rootNode = document.CreateElement(DeserializeRootElementName);
1111         //document.AppendChild(rootNode);
1112         ReadElement(reader, document, rootNode, DeserializeRootElementName, manager);
1113       }
1114       else
1115       {
1116         reader.Read();
1117         DeserializeNode(reader, document, manager, rootNode);
1118       }
1119
1120 #if !NET20
1121       if (objectType == typeof(XElement))
1122       {
1123         XElement element = (XElement)document.DocumentElement.WrappedNode;
1124         element.Remove();
1125
1126         return element;
1127       }
1128 #endif
1129
1130       return document.WrappedNode;
1131     }
1132
1133     private void DeserializeValue(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, string propertyName, IXmlNode currentNode)
1134     {
1135       switch (propertyName)
1136       {
1137         case TextName:
1138           currentNode.AppendChild(document.CreateTextNode(reader.Value.ToString()));
1139           break;
1140         case CDataName:
1141           currentNode.AppendChild(document.CreateCDataSection(reader.Value.ToString()));
1142           break;
1143         case WhitespaceName:
1144           currentNode.AppendChild(document.CreateWhitespace(reader.Value.ToString()));
1145           break;
1146         case SignificantWhitespaceName:
1147           currentNode.AppendChild(document.CreateSignificantWhitespace(reader.Value.ToString()));
1148           break;
1149         default:
1150           // processing instructions and the xml declaration start with ?
1151           if (!string.IsNullOrEmpty(propertyName) && propertyName[0] == '?')
1152           {
1153             CreateInstruction(reader, document, currentNode, propertyName);
1154           }
1155           else
1156           {
1157             if (reader.TokenType == JsonToken.StartArray)
1158             {
1159               // handle nested arrays
1160               ReadArrayElements(reader, document, propertyName, currentNode, manager);
1161               return;
1162             }
1163
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);
1167           }
1168           break;
1169       }
1170     }
1171
1172     private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, XmlNamespaceManager manager)
1173     {
1174       if (string.IsNullOrEmpty(propertyName))
1175         throw new JsonSerializationException("XmlNodeConverter cannot convert JSON with an empty property name to XML.");
1176
1177       Dictionary<string, string> attributeNameValues = ReadAttributeElements(reader, manager);
1178
1179       string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);
1180
1181       IXmlElement element = CreateElement(propertyName, document, elementPrefix, manager);
1182
1183       currentNode.AppendChild(element);
1184
1185       // add attributes to newly created element
1186       foreach (KeyValuePair<string, string> nameValue in attributeNameValues)
1187       {
1188         string attributePrefix = MiscellaneousUtils.GetPrefix(nameValue.Key);
1189
1190         IXmlNode attribute = (!string.IsNullOrEmpty(attributePrefix))
1191                                ? document.CreateAttribute(nameValue.Key, manager.LookupNamespace(attributePrefix), nameValue.Value)
1192                                : document.CreateAttribute(nameValue.Key, nameValue.Value);
1193
1194         element.SetAttributeNode(attribute);
1195       }
1196
1197       if (reader.TokenType == JsonToken.String)
1198       {
1199         element.AppendChild(document.CreateTextNode(reader.Value.ToString()));
1200       }
1201       else if (reader.TokenType == JsonToken.Integer)
1202       {
1203         element.AppendChild(document.CreateTextNode(XmlConvert.ToString((long)reader.Value)));
1204       }
1205       else if (reader.TokenType == JsonToken.Float)
1206       {
1207         element.AppendChild(document.CreateTextNode(XmlConvert.ToString((double)reader.Value)));
1208       }
1209       else if (reader.TokenType == JsonToken.Boolean)
1210       {
1211         element.AppendChild(document.CreateTextNode(XmlConvert.ToString((bool)reader.Value)));
1212       }
1213       else if (reader.TokenType == JsonToken.Date)
1214       {
1215         DateTime d = (DateTime)reader.Value;
1216         element.AppendChild(document.CreateTextNode(XmlConvert.ToString(d, DateTimeUtils.ToSerializationMode(d.Kind))));
1217       }
1218       else if (reader.TokenType == JsonToken.Null)
1219       {
1220         // empty element. do nothing
1221       }
1222       else
1223       {
1224         // finished element will have no children to deserialize
1225         if (reader.TokenType != JsonToken.EndObject)
1226         {
1227           manager.PushScope();
1228
1229           DeserializeNode(reader, document, manager, element);
1230
1231           manager.PopScope();
1232         }
1233       }
1234     }
1235
1236     private void ReadArrayElements(JsonReader reader, IXmlDocument document, string propertyName, IXmlNode currentNode, XmlNamespaceManager manager)
1237     {
1238       string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);
1239
1240       IXmlElement nestedArrayElement = CreateElement(propertyName, document, elementPrefix, manager);
1241
1242       currentNode.AppendChild(nestedArrayElement);
1243
1244       int count = 0;
1245       while (reader.Read() && reader.TokenType != JsonToken.EndArray)
1246       {
1247         DeserializeValue(reader, document, manager, propertyName, nestedArrayElement);
1248         count++;
1249       }
1250
1251       if (WriteArrayAttribute)
1252       {
1253         AddJsonArrayAttribute(nestedArrayElement, document);
1254       }
1255
1256       if (count == 1 && WriteArrayAttribute)
1257       {
1258         IXmlElement arrayElement = nestedArrayElement.ChildNodes.CastValid<IXmlElement>().Single(n => n.LocalName == propertyName);
1259         AddJsonArrayAttribute(arrayElement, document);
1260       }
1261     }
1262
1263     private void AddJsonArrayAttribute(IXmlElement element, IXmlDocument document)
1264     {
1265       element.SetAttributeNode(document.CreateAttribute("json:Array", JsonNamespaceUri, "true"));
1266
1267 #if !NET20
1268       // linq to xml doesn't automatically include prefixes via the namespace manager
1269       if (element is XElementWrapper)
1270       {
1271         if (element.GetPrefixOfNamespace(JsonNamespaceUri) == null)
1272         {
1273           element.SetAttributeNode(document.CreateAttribute("xmlns:json", "http://www.w3.org/2000/xmlns/", JsonNamespaceUri));
1274         }
1275       }
1276 #endif
1277     }
1278
1279     private Dictionary<string, string> ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager)
1280     {
1281       Dictionary<string, string> attributeNameValues = new Dictionary<string, string>();
1282       bool finishedAttributes = false;
1283       bool finishedElement = false;
1284
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)
1293       {
1294         // read properties until first non-attribute is encountered
1295         while (!finishedAttributes && !finishedElement && reader.Read())
1296         {
1297           switch (reader.TokenType)
1298           {
1299             case JsonToken.PropertyName:
1300               string attributeName = reader.Value.ToString();
1301               string attributeValue;
1302
1303               if (!string.IsNullOrEmpty(attributeName))
1304               {
1305                 char firstChar = attributeName[0];
1306
1307                 switch (firstChar)
1308                 {
1309                   case '@':
1310                     attributeName = attributeName.Substring(1);
1311                     reader.Read();
1312                     attributeValue = reader.Value.ToString();
1313                     attributeNameValues.Add(attributeName, attributeValue);
1314
1315                     string namespacePrefix;
1316                     if (IsNamespaceAttribute(attributeName, out namespacePrefix))
1317                     {
1318                       manager.AddNamespace(namespacePrefix, attributeValue);
1319                     }
1320                     break;
1321                   case '$':
1322                     attributeName = attributeName.Substring(1);
1323                     reader.Read();
1324                     attributeValue = reader.Value.ToString();
1325
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)
1330                     {
1331                       // ensure that the prefix used is free
1332                       int? i = null;
1333                       while (manager.LookupNamespace("json" + i) != null)
1334                       {
1335                         i = i.GetValueOrDefault() + 1;
1336                       }
1337                       jsonPrefix = "json" + i;
1338
1339                       attributeNameValues.Add("xmlns:" + jsonPrefix, JsonNamespaceUri);
1340                       manager.AddNamespace(jsonPrefix, JsonNamespaceUri);
1341                     }
1342
1343                     attributeNameValues.Add(jsonPrefix + ":" + attributeName, attributeValue);
1344                     break;
1345                   default:
1346                     finishedAttributes = true;
1347                     break;
1348                 }
1349               }
1350               else
1351               {
1352                 finishedAttributes = true;
1353               }
1354
1355               break;
1356             case JsonToken.EndObject:
1357               finishedElement = true;
1358               break;
1359             default:
1360               throw new JsonSerializationException("Unexpected JsonToken: " + reader.TokenType);
1361           }
1362         }
1363       }
1364
1365       return attributeNameValues;
1366     }
1367
1368     private void CreateInstruction(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName)
1369     {
1370       if (propertyName == DeclarationName)
1371       {
1372         string version = null;
1373         string encoding = null;
1374         string standalone = null;
1375         while (reader.Read() && reader.TokenType != JsonToken.EndObject)
1376         {
1377           switch (reader.Value.ToString())
1378           {
1379             case "@version":
1380               reader.Read();
1381               version = reader.Value.ToString();
1382               break;
1383             case "@encoding":
1384               reader.Read();
1385               encoding = reader.Value.ToString();
1386               break;
1387             case "@standalone":
1388               reader.Read();
1389               standalone = reader.Value.ToString();
1390               break;
1391             default:
1392               throw new JsonSerializationException("Unexpected property name encountered while deserializing XmlDeclaration: " + reader.Value);
1393           }
1394         }
1395
1396         IXmlNode declaration = document.CreateXmlDeclaration(version, encoding, standalone);
1397         currentNode.AppendChild(declaration);
1398       }
1399       else
1400       {
1401         IXmlNode instruction = document.CreateProcessingInstruction(propertyName.Substring(1), reader.Value.ToString());
1402         currentNode.AppendChild(instruction);
1403       }
1404     }
1405
1406     private IXmlElement CreateElement(string elementName, IXmlDocument document, string elementPrefix, XmlNamespaceManager manager)
1407     {
1408       return (!string.IsNullOrEmpty(elementPrefix))
1409                ? document.CreateElement(elementName, manager.LookupNamespace(elementPrefix))
1410                : document.CreateElement(elementName);
1411     }
1412
1413     private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, IXmlNode currentNode)
1414     {
1415       do
1416       {
1417         switch (reader.TokenType)
1418         {
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.");
1422
1423             string propertyName = reader.Value.ToString();
1424             reader.Read();
1425
1426             if (reader.TokenType == JsonToken.StartArray)
1427             {
1428               int count = 0;
1429               while (reader.Read() && reader.TokenType != JsonToken.EndArray)
1430               {
1431                 DeserializeValue(reader, document, manager, propertyName, currentNode);
1432                 count++;
1433               }
1434
1435               if (count == 1 && WriteArrayAttribute)
1436               {
1437                 IXmlElement arrayElement = currentNode.ChildNodes.CastValid<IXmlElement>().Single(n => n.LocalName == propertyName);
1438                 AddJsonArrayAttribute(arrayElement, document);
1439               }
1440             }
1441             else
1442             {
1443               DeserializeValue(reader, document, manager, propertyName, currentNode);
1444             }
1445             break;
1446           case JsonToken.StartConstructor:
1447             string constructorName = reader.Value.ToString();
1448
1449             while (reader.Read() && reader.TokenType != JsonToken.EndConstructor)
1450             {
1451               DeserializeValue(reader, document, manager, constructorName, currentNode);
1452             }
1453             break;
1454           case JsonToken.Comment:
1455             currentNode.AppendChild(document.CreateComment((string)reader.Value));
1456             break;
1457           case JsonToken.EndObject:
1458           case JsonToken.EndArray:
1459             return;
1460           default:
1461             throw new JsonSerializationException("Unexpected JsonToken when deserializing node: " + reader.TokenType);
1462         }
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
1465     }
1466
1467     /// <summary>
1468     /// Checks if the attributeName is a namespace attribute.
1469     /// </summary>
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)
1474     {
1475       if (attributeName.StartsWith("xmlns", StringComparison.Ordinal))
1476       {
1477         if (attributeName.Length == 5)
1478         {
1479           prefix = string.Empty;
1480           return true;
1481         }
1482         else if (attributeName[5] == ':')
1483         {
1484           prefix = attributeName.Substring(6, attributeName.Length - 6);
1485           return true;
1486         }
1487       }
1488       prefix = null;
1489       return false;
1490     }
1491
1492     private IEnumerable<IXmlNode> ValueAttributes(IEnumerable<IXmlNode> c)
1493     {
1494       return c.Where(a => a.NamespaceURI != JsonNamespaceUri);
1495     }
1496     #endregion
1497
1498     /// <summary>
1499     /// Determines whether this instance can convert the specified value type.
1500     /// </summary>
1501     /// <param name="valueType">Type of the value.</param>
1502     /// <returns>
1503     ///         <c>true</c> if this instance can convert the specified value type; otherwise, <c>false</c>.
1504     /// </returns>
1505     public override bool CanConvert(Type valueType)
1506     {
1507 #if !NET20
1508       if (typeof(XObject).IsAssignableFrom(valueType))
1509         return true;
1510 #endif
1511 #if !SILVERLIGHT
1512       if (typeof(XmlNode).IsAssignableFrom(valueType))
1513         return true;
1514 #endif
1515
1516       return false;
1517     }
1518   }
1519 }
1520 #endif