You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2156 lines
78 KiB

  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. #if HAVE_BIG_INTEGER
  26. using System.Numerics;
  27. #endif
  28. using System;
  29. using System.Collections.Generic;
  30. using System.Globalization;
  31. using System.Xml;
  32. using Newtonsoft.Json.Serialization;
  33. #if !NET20
  34. using System.Xml.Linq;
  35. #endif
  36. using Newtonsoft.Json.Utilities;
  37. using System.Runtime.CompilerServices;
  38. namespace Newtonsoft.Json.Converters
  39. {
  40. #region XmlNodeWrappers
  41. internal class XmlDocumentWrapper : XmlNodeWrapper, IXmlDocument
  42. {
  43. private readonly XmlDocument _document;
  44. public XmlDocumentWrapper(XmlDocument document)
  45. : base(document)
  46. {
  47. _document = document;
  48. }
  49. public IXmlNode CreateComment(string data)
  50. {
  51. return new XmlNodeWrapper(_document.CreateComment(data));
  52. }
  53. public IXmlNode CreateTextNode(string text)
  54. {
  55. return new XmlNodeWrapper(_document.CreateTextNode(text));
  56. }
  57. public IXmlNode CreateCDataSection(string data)
  58. {
  59. return new XmlNodeWrapper(_document.CreateCDataSection(data));
  60. }
  61. public IXmlNode CreateWhitespace(string text)
  62. {
  63. return new XmlNodeWrapper(_document.CreateWhitespace(text));
  64. }
  65. public IXmlNode CreateSignificantWhitespace(string text)
  66. {
  67. return new XmlNodeWrapper(_document.CreateSignificantWhitespace(text));
  68. }
  69. public IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone)
  70. {
  71. return new XmlDeclarationWrapper(_document.CreateXmlDeclaration(version, encoding, standalone));
  72. }
  73. public IXmlNode CreateXmlDocumentType(string name, string publicId, string systemId, string internalSubset)
  74. {
  75. return new XmlDocumentTypeWrapper(_document.CreateDocumentType(name, publicId, systemId, null));
  76. }
  77. public IXmlNode CreateProcessingInstruction(string target, string data)
  78. {
  79. return new XmlNodeWrapper(_document.CreateProcessingInstruction(target, data));
  80. }
  81. public IXmlElement CreateElement(string elementName)
  82. {
  83. return new XmlElementWrapper(_document.CreateElement(elementName));
  84. }
  85. public IXmlElement CreateElement(string qualifiedName, string namespaceUri)
  86. {
  87. return new XmlElementWrapper(_document.CreateElement(qualifiedName, namespaceUri));
  88. }
  89. public IXmlNode CreateAttribute(string name, string value)
  90. {
  91. XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(name));
  92. attribute.Value = value;
  93. return attribute;
  94. }
  95. public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value)
  96. {
  97. XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(qualifiedName, namespaceUri));
  98. attribute.Value = value;
  99. return attribute;
  100. }
  101. public IXmlElement DocumentElement
  102. {
  103. get
  104. {
  105. if (_document.DocumentElement == null)
  106. {
  107. return null;
  108. }
  109. return new XmlElementWrapper(_document.DocumentElement);
  110. }
  111. }
  112. }
  113. internal class XmlElementWrapper : XmlNodeWrapper, IXmlElement
  114. {
  115. private readonly XmlElement _element;
  116. public XmlElementWrapper(XmlElement element)
  117. : base(element)
  118. {
  119. _element = element;
  120. }
  121. public void SetAttributeNode(IXmlNode attribute)
  122. {
  123. XmlNodeWrapper xmlAttributeWrapper = (XmlNodeWrapper)attribute;
  124. _element.SetAttributeNode((XmlAttribute)xmlAttributeWrapper.WrappedNode);
  125. }
  126. public string GetPrefixOfNamespace(string namespaceUri)
  127. {
  128. return _element.GetPrefixOfNamespace(namespaceUri);
  129. }
  130. public bool IsEmpty => _element.IsEmpty;
  131. }
  132. internal class XmlDeclarationWrapper : XmlNodeWrapper, IXmlDeclaration
  133. {
  134. private readonly XmlDeclaration _declaration;
  135. public XmlDeclarationWrapper(XmlDeclaration declaration)
  136. : base(declaration)
  137. {
  138. _declaration = declaration;
  139. }
  140. public string Version => _declaration.Version;
  141. public string Encoding
  142. {
  143. get => _declaration.Encoding;
  144. set => _declaration.Encoding = value;
  145. }
  146. public string Standalone
  147. {
  148. get => _declaration.Standalone;
  149. set => _declaration.Standalone = value;
  150. }
  151. }
  152. internal class XmlDocumentTypeWrapper : XmlNodeWrapper, IXmlDocumentType
  153. {
  154. private readonly XmlDocumentType _documentType;
  155. public XmlDocumentTypeWrapper(XmlDocumentType documentType)
  156. : base(documentType)
  157. {
  158. _documentType = documentType;
  159. }
  160. public string Name => _documentType.Name;
  161. public string System => _documentType.SystemId;
  162. public string Public => _documentType.PublicId;
  163. public string InternalSubset => _documentType.InternalSubset;
  164. public override string LocalName => "DOCTYPE";
  165. }
  166. internal class XmlNodeWrapper : IXmlNode
  167. {
  168. private readonly XmlNode _node;
  169. private List<IXmlNode> _childNodes;
  170. private List<IXmlNode> _attributes;
  171. public XmlNodeWrapper(XmlNode node)
  172. {
  173. _node = node;
  174. }
  175. public object WrappedNode => _node;
  176. public XmlNodeType NodeType => _node.NodeType;
  177. public virtual string LocalName => _node.LocalName;
  178. public List<IXmlNode> ChildNodes
  179. {
  180. get
  181. {
  182. // childnodes is read multiple times
  183. // cache results to prevent multiple reads which kills perf in large documents
  184. if (_childNodes == null)
  185. {
  186. if (!_node.HasChildNodes)
  187. {
  188. _childNodes = XmlNodeConverter.EmptyChildNodes;
  189. }
  190. else
  191. {
  192. _childNodes = new List<IXmlNode>(_node.ChildNodes.Count);
  193. foreach (XmlNode childNode in _node.ChildNodes)
  194. {
  195. _childNodes.Add(WrapNode(childNode));
  196. }
  197. }
  198. }
  199. return _childNodes;
  200. }
  201. }
  202. protected virtual bool HasChildNodes => _node.HasChildNodes;
  203. internal static IXmlNode WrapNode(XmlNode node)
  204. {
  205. switch (node.NodeType)
  206. {
  207. case XmlNodeType.Element:
  208. return new XmlElementWrapper((XmlElement)node);
  209. case XmlNodeType.XmlDeclaration:
  210. return new XmlDeclarationWrapper((XmlDeclaration)node);
  211. case XmlNodeType.DocumentType:
  212. return new XmlDocumentTypeWrapper((XmlDocumentType)node);
  213. default:
  214. return new XmlNodeWrapper(node);
  215. }
  216. }
  217. public List<IXmlNode> Attributes
  218. {
  219. get
  220. {
  221. // attributes is read multiple times
  222. // cache results to prevent multiple reads which kills perf in large documents
  223. if (_attributes == null)
  224. {
  225. if (!HasAttributes)
  226. {
  227. _attributes = XmlNodeConverter.EmptyChildNodes;
  228. }
  229. else
  230. {
  231. _attributes = new List<IXmlNode>(_node.Attributes.Count);
  232. foreach (XmlAttribute attribute in _node.Attributes)
  233. {
  234. _attributes.Add(WrapNode(attribute));
  235. }
  236. }
  237. }
  238. return _attributes;
  239. }
  240. }
  241. private bool HasAttributes
  242. {
  243. get
  244. {
  245. if (_node is XmlElement element)
  246. {
  247. return element.HasAttributes;
  248. }
  249. return _node.Attributes?.Count > 0;
  250. }
  251. }
  252. public IXmlNode ParentNode
  253. {
  254. get
  255. {
  256. XmlNode node = _node is XmlAttribute attribute ? attribute.OwnerElement : _node.ParentNode;
  257. if (node == null)
  258. {
  259. return null;
  260. }
  261. return WrapNode(node);
  262. }
  263. }
  264. public string Value
  265. {
  266. get => _node.Value;
  267. set => _node.Value = value;
  268. }
  269. public IXmlNode AppendChild(IXmlNode newChild)
  270. {
  271. XmlNodeWrapper xmlNodeWrapper = (XmlNodeWrapper)newChild;
  272. _node.AppendChild(xmlNodeWrapper._node);
  273. _childNodes = null;
  274. _attributes = null;
  275. return newChild;
  276. }
  277. public string NamespaceUri => _node.NamespaceURI;
  278. }
  279. #endregion
  280. #region Interfaces
  281. internal interface IXmlDocument : IXmlNode
  282. {
  283. IXmlNode CreateComment(string text);
  284. IXmlNode CreateTextNode(string text);
  285. IXmlNode CreateCDataSection(string data);
  286. IXmlNode CreateWhitespace(string text);
  287. IXmlNode CreateSignificantWhitespace(string text);
  288. IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone);
  289. IXmlNode CreateXmlDocumentType(string name, string publicId, string systemId, string internalSubset);
  290. IXmlNode CreateProcessingInstruction(string target, string data);
  291. IXmlElement CreateElement(string elementName);
  292. IXmlElement CreateElement(string qualifiedName, string namespaceUri);
  293. IXmlNode CreateAttribute(string name, string value);
  294. IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value);
  295. IXmlElement DocumentElement { get; }
  296. }
  297. internal interface IXmlDeclaration : IXmlNode
  298. {
  299. string Version { get; }
  300. string Encoding { get; set; }
  301. string Standalone { get; set; }
  302. }
  303. internal interface IXmlDocumentType : IXmlNode
  304. {
  305. string Name { get; }
  306. string System { get; }
  307. string Public { get; }
  308. string InternalSubset { get; }
  309. }
  310. internal interface IXmlElement : IXmlNode
  311. {
  312. void SetAttributeNode(IXmlNode attribute);
  313. string GetPrefixOfNamespace(string namespaceUri);
  314. bool IsEmpty { get; }
  315. }
  316. internal interface IXmlNode
  317. {
  318. XmlNodeType NodeType { get; }
  319. string LocalName { get; }
  320. List<IXmlNode> ChildNodes { get; }
  321. List<IXmlNode> Attributes { get; }
  322. IXmlNode ParentNode { get; }
  323. string Value { get; set; }
  324. IXmlNode AppendChild(IXmlNode newChild);
  325. string NamespaceUri { get; }
  326. object WrappedNode { get; }
  327. }
  328. #endregion
  329. #region XNodeWrappers
  330. #if !NET20
  331. internal class XDeclarationWrapper : XObjectWrapper, IXmlDeclaration
  332. {
  333. internal XDeclaration Declaration { get; }
  334. public XDeclarationWrapper(XDeclaration declaration)
  335. : base(null)
  336. {
  337. Declaration = declaration;
  338. }
  339. public override XmlNodeType NodeType => XmlNodeType.XmlDeclaration;
  340. public string Version => Declaration.Version;
  341. public string Encoding
  342. {
  343. get => Declaration.Encoding;
  344. set => Declaration.Encoding = value;
  345. }
  346. public string Standalone
  347. {
  348. get => Declaration.Standalone;
  349. set => Declaration.Standalone = value;
  350. }
  351. }
  352. internal class XDocumentTypeWrapper : XObjectWrapper, IXmlDocumentType
  353. {
  354. private readonly XDocumentType _documentType;
  355. public XDocumentTypeWrapper(XDocumentType documentType)
  356. : base(documentType)
  357. {
  358. _documentType = documentType;
  359. }
  360. public string Name => _documentType.Name;
  361. public string System => _documentType.SystemId;
  362. public string Public => _documentType.PublicId;
  363. public string InternalSubset => _documentType.InternalSubset;
  364. public override string LocalName => "DOCTYPE";
  365. }
  366. internal class XDocumentWrapper : XContainerWrapper, IXmlDocument
  367. {
  368. private XDocument Document => (XDocument)WrappedNode;
  369. public XDocumentWrapper(XDocument document)
  370. : base(document)
  371. {
  372. }
  373. public override List<IXmlNode> ChildNodes
  374. {
  375. get
  376. {
  377. List<IXmlNode> childNodes = base.ChildNodes;
  378. if (Document.Declaration != null && (childNodes.Count == 0 || childNodes[0].NodeType != XmlNodeType.XmlDeclaration))
  379. {
  380. childNodes.Insert(0, new XDeclarationWrapper(Document.Declaration));
  381. }
  382. return childNodes;
  383. }
  384. }
  385. protected override bool HasChildNodes
  386. {
  387. get
  388. {
  389. if (base.HasChildNodes)
  390. {
  391. return true;
  392. }
  393. return Document.Declaration != null;
  394. }
  395. }
  396. public IXmlNode CreateComment(string text)
  397. {
  398. return new XObjectWrapper(new XComment(text));
  399. }
  400. public IXmlNode CreateTextNode(string text)
  401. {
  402. return new XObjectWrapper(new XText(text));
  403. }
  404. public IXmlNode CreateCDataSection(string data)
  405. {
  406. return new XObjectWrapper(new XCData(data));
  407. }
  408. public IXmlNode CreateWhitespace(string text)
  409. {
  410. return new XObjectWrapper(new XText(text));
  411. }
  412. public IXmlNode CreateSignificantWhitespace(string text)
  413. {
  414. return new XObjectWrapper(new XText(text));
  415. }
  416. public IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone)
  417. {
  418. return new XDeclarationWrapper(new XDeclaration(version, encoding, standalone));
  419. }
  420. public IXmlNode CreateXmlDocumentType(string name, string publicId, string systemId, string internalSubset)
  421. {
  422. return new XDocumentTypeWrapper(new XDocumentType(name, publicId, systemId, internalSubset));
  423. }
  424. public IXmlNode CreateProcessingInstruction(string target, string data)
  425. {
  426. return new XProcessingInstructionWrapper(new XProcessingInstruction(target, data));
  427. }
  428. public IXmlElement CreateElement(string elementName)
  429. {
  430. return new XElementWrapper(new XElement(elementName));
  431. }
  432. public IXmlElement CreateElement(string qualifiedName, string namespaceUri)
  433. {
  434. string localName = MiscellaneousUtils.GetLocalName(qualifiedName);
  435. return new XElementWrapper(new XElement(XName.Get(localName, namespaceUri)));
  436. }
  437. public IXmlNode CreateAttribute(string name, string value)
  438. {
  439. return new XAttributeWrapper(new XAttribute(name, value));
  440. }
  441. public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value)
  442. {
  443. string localName = MiscellaneousUtils.GetLocalName(qualifiedName);
  444. return new XAttributeWrapper(new XAttribute(XName.Get(localName, namespaceUri), value));
  445. }
  446. public IXmlElement DocumentElement
  447. {
  448. get
  449. {
  450. if (Document.Root == null)
  451. {
  452. return null;
  453. }
  454. return new XElementWrapper(Document.Root);
  455. }
  456. }
  457. public override IXmlNode AppendChild(IXmlNode newChild)
  458. {
  459. if (newChild is XDeclarationWrapper declarationWrapper)
  460. {
  461. Document.Declaration = declarationWrapper.Declaration;
  462. return declarationWrapper;
  463. }
  464. else
  465. {
  466. return base.AppendChild(newChild);
  467. }
  468. }
  469. }
  470. internal class XTextWrapper : XObjectWrapper
  471. {
  472. private XText Text => (XText)WrappedNode;
  473. public XTextWrapper(XText text)
  474. : base(text)
  475. {
  476. }
  477. public override string Value
  478. {
  479. get => Text.Value;
  480. set => Text.Value = value;
  481. }
  482. public override IXmlNode ParentNode
  483. {
  484. get
  485. {
  486. if (Text.Parent == null)
  487. {
  488. return null;
  489. }
  490. return XContainerWrapper.WrapNode(Text.Parent);
  491. }
  492. }
  493. }
  494. internal class XCommentWrapper : XObjectWrapper
  495. {
  496. private XComment Text => (XComment)WrappedNode;
  497. public XCommentWrapper(XComment text)
  498. : base(text)
  499. {
  500. }
  501. public override string Value
  502. {
  503. get => Text.Value;
  504. set => Text.Value = value;
  505. }
  506. public override IXmlNode ParentNode
  507. {
  508. get
  509. {
  510. if (Text.Parent == null)
  511. {
  512. return null;
  513. }
  514. return XContainerWrapper.WrapNode(Text.Parent);
  515. }
  516. }
  517. }
  518. internal class XProcessingInstructionWrapper : XObjectWrapper
  519. {
  520. private XProcessingInstruction ProcessingInstruction => (XProcessingInstruction)WrappedNode;
  521. public XProcessingInstructionWrapper(XProcessingInstruction processingInstruction)
  522. : base(processingInstruction)
  523. {
  524. }
  525. public override string LocalName => ProcessingInstruction.Target;
  526. public override string Value
  527. {
  528. get => ProcessingInstruction.Data;
  529. set => ProcessingInstruction.Data = value;
  530. }
  531. }
  532. internal class XContainerWrapper : XObjectWrapper
  533. {
  534. private List<IXmlNode> _childNodes;
  535. private XContainer Container => (XContainer)WrappedNode;
  536. public XContainerWrapper(XContainer container)
  537. : base(container)
  538. {
  539. }
  540. public override List<IXmlNode> ChildNodes
  541. {
  542. get
  543. {
  544. // childnodes is read multiple times
  545. // cache results to prevent multiple reads which kills perf in large documents
  546. if (_childNodes == null)
  547. {
  548. if (!HasChildNodes)
  549. {
  550. _childNodes = XmlNodeConverter.EmptyChildNodes;
  551. }
  552. else
  553. {
  554. _childNodes = new List<IXmlNode>();
  555. foreach (XNode node in Container.Nodes())
  556. {
  557. _childNodes.Add(WrapNode(node));
  558. }
  559. }
  560. }
  561. return _childNodes;
  562. }
  563. }
  564. protected virtual bool HasChildNodes => Container.LastNode != null;
  565. public override IXmlNode ParentNode
  566. {
  567. get
  568. {
  569. if (Container.Parent == null)
  570. {
  571. return null;
  572. }
  573. return WrapNode(Container.Parent);
  574. }
  575. }
  576. internal static IXmlNode WrapNode(XObject node)
  577. {
  578. if (node is XDocument document)
  579. {
  580. return new XDocumentWrapper(document);
  581. }
  582. if (node is XElement element)
  583. {
  584. return new XElementWrapper(element);
  585. }
  586. if (node is XContainer container)
  587. {
  588. return new XContainerWrapper(container);
  589. }
  590. if (node is XProcessingInstruction pi)
  591. {
  592. return new XProcessingInstructionWrapper(pi);
  593. }
  594. if (node is XText text)
  595. {
  596. return new XTextWrapper(text);
  597. }
  598. if (node is XComment comment)
  599. {
  600. return new XCommentWrapper(comment);
  601. }
  602. if (node is XAttribute attribute)
  603. {
  604. return new XAttributeWrapper(attribute);
  605. }
  606. if (node is XDocumentType type)
  607. {
  608. return new XDocumentTypeWrapper(type);
  609. }
  610. return new XObjectWrapper(node);
  611. }
  612. public override IXmlNode AppendChild(IXmlNode newChild)
  613. {
  614. Container.Add(newChild.WrappedNode);
  615. _childNodes = null;
  616. return newChild;
  617. }
  618. }
  619. internal class XObjectWrapper : IXmlNode
  620. {
  621. private readonly XObject _xmlObject;
  622. public XObjectWrapper(XObject xmlObject)
  623. {
  624. _xmlObject = xmlObject;
  625. }
  626. public object WrappedNode => _xmlObject;
  627. public virtual XmlNodeType NodeType => _xmlObject.NodeType;
  628. public virtual string LocalName => null;
  629. public virtual List<IXmlNode> ChildNodes => XmlNodeConverter.EmptyChildNodes;
  630. public virtual List<IXmlNode> Attributes => XmlNodeConverter.EmptyChildNodes;
  631. public virtual IXmlNode ParentNode => null;
  632. public virtual string Value
  633. {
  634. get => null;
  635. set => throw new InvalidOperationException();
  636. }
  637. public virtual IXmlNode AppendChild(IXmlNode newChild)
  638. {
  639. throw new InvalidOperationException();
  640. }
  641. public virtual string NamespaceUri => null;
  642. }
  643. internal class XAttributeWrapper : XObjectWrapper
  644. {
  645. private XAttribute Attribute => (XAttribute)WrappedNode;
  646. public XAttributeWrapper(XAttribute attribute)
  647. : base(attribute)
  648. {
  649. }
  650. public override string Value
  651. {
  652. get => Attribute.Value;
  653. set => Attribute.Value = value;
  654. }
  655. public override string LocalName => Attribute.Name.LocalName;
  656. public override string NamespaceUri => Attribute.Name.NamespaceName;
  657. public override IXmlNode ParentNode
  658. {
  659. get
  660. {
  661. if (Attribute.Parent == null)
  662. {
  663. return null;
  664. }
  665. return XContainerWrapper.WrapNode(Attribute.Parent);
  666. }
  667. }
  668. }
  669. internal class XElementWrapper : XContainerWrapper, IXmlElement
  670. {
  671. private List<IXmlNode> _attributes;
  672. private XElement Element => (XElement)WrappedNode;
  673. public XElementWrapper(XElement element)
  674. : base(element)
  675. {
  676. }
  677. public void SetAttributeNode(IXmlNode attribute)
  678. {
  679. XObjectWrapper wrapper = (XObjectWrapper)attribute;
  680. Element.Add(wrapper.WrappedNode);
  681. _attributes = null;
  682. }
  683. public override List<IXmlNode> Attributes
  684. {
  685. get
  686. {
  687. // attributes is read multiple times
  688. // cache results to prevent multiple reads which kills perf in large documents
  689. if (_attributes == null)
  690. {
  691. if (!Element.HasAttributes && !HasImplicitNamespaceAttribute(NamespaceUri))
  692. {
  693. _attributes = XmlNodeConverter.EmptyChildNodes;
  694. }
  695. else
  696. {
  697. _attributes = new List<IXmlNode>();
  698. foreach (XAttribute attribute in Element.Attributes())
  699. {
  700. _attributes.Add(new XAttributeWrapper(attribute));
  701. }
  702. // ensure elements created with a namespace but no namespace attribute are converted correctly
  703. // e.g. new XElement("{http://example.com}MyElement");
  704. string namespaceUri = NamespaceUri;
  705. if (HasImplicitNamespaceAttribute(namespaceUri))
  706. {
  707. _attributes.Insert(0, new XAttributeWrapper(new XAttribute("xmlns", namespaceUri)));
  708. }
  709. }
  710. }
  711. return _attributes;
  712. }
  713. }
  714. private bool HasImplicitNamespaceAttribute(string namespaceUri)
  715. {
  716. if (!string.IsNullOrEmpty(namespaceUri) && namespaceUri != ParentNode?.NamespaceUri)
  717. {
  718. if (string.IsNullOrEmpty(GetPrefixOfNamespace(namespaceUri)))
  719. {
  720. bool namespaceDeclared = false;
  721. if (Element.HasAttributes)
  722. {
  723. foreach (XAttribute attribute in Element.Attributes())
  724. {
  725. if (attribute.Name.LocalName == "xmlns" && string.IsNullOrEmpty(attribute.Name.NamespaceName) && attribute.Value == namespaceUri)
  726. {
  727. namespaceDeclared = true;
  728. }
  729. }
  730. }
  731. if (!namespaceDeclared)
  732. {
  733. return true;
  734. }
  735. }
  736. }
  737. return false;
  738. }
  739. public override IXmlNode AppendChild(IXmlNode newChild)
  740. {
  741. IXmlNode result = base.AppendChild(newChild);
  742. _attributes = null;
  743. return result;
  744. }
  745. public override string Value
  746. {
  747. get => Element.Value;
  748. set => Element.Value = value;
  749. }
  750. public override string LocalName => Element.Name.LocalName;
  751. public override string NamespaceUri => Element.Name.NamespaceName;
  752. public string GetPrefixOfNamespace(string namespaceUri)
  753. {
  754. return Element.GetPrefixOfNamespace(namespaceUri);
  755. }
  756. public bool IsEmpty => Element.IsEmpty;
  757. }
  758. #endif
  759. #endregion
  760. /// <summary>
  761. /// Converts XML to and from JSON.
  762. /// </summary>
  763. internal class XmlNodeConverter : JsonConverter
  764. {
  765. internal static readonly List<IXmlNode> EmptyChildNodes = new List<IXmlNode>();
  766. private const string TextName = "#text";
  767. private const string CommentName = "#comment";
  768. private const string CDataName = "#cdata-section";
  769. private const string WhitespaceName = "#whitespace";
  770. private const string SignificantWhitespaceName = "#significant-whitespace";
  771. private const string DeclarationName = "?xml";
  772. private const string JsonNamespaceUri = "http://james.newtonking.com/projects/json";
  773. /// <summary>
  774. /// Gets or sets the name of the root element to insert when deserializing to XML if the JSON structure has produced multiple root elements.
  775. /// </summary>
  776. /// <value>The name of the deserialized root element.</value>
  777. public string DeserializeRootElementName { get; set; }
  778. /// <summary>
  779. /// Gets or sets a flag to indicate whether to write the Json.NET array attribute.
  780. /// This attribute helps preserve arrays when converting the written XML back to JSON.
  781. /// </summary>
  782. /// <value><c>true</c> if the array attribute is written to the XML; otherwise, <c>false</c>.</value>
  783. public bool WriteArrayAttribute { get; set; }
  784. /// <summary>
  785. /// Gets or sets a value indicating whether to write the root JSON object.
  786. /// </summary>
  787. /// <value><c>true</c> if the JSON root object is omitted; otherwise, <c>false</c>.</value>
  788. public bool OmitRootObject { get; set; }
  789. #region Writing
  790. /// <summary>
  791. /// Writes the JSON representation of the object.
  792. /// </summary>
  793. /// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
  794. /// <param name="serializer">The calling serializer.</param>
  795. /// <param name="value">The value.</param>
  796. public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
  797. {
  798. if (value == null)
  799. {
  800. writer.WriteNull();
  801. return;
  802. }
  803. IXmlNode node = WrapXml(value);
  804. XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
  805. PushParentNamespaces(node, manager);
  806. if (!OmitRootObject)
  807. {
  808. writer.WriteStartObject();
  809. }
  810. SerializeNode(writer, node, manager, !OmitRootObject);
  811. if (!OmitRootObject)
  812. {
  813. writer.WriteEndObject();
  814. }
  815. }
  816. private IXmlNode WrapXml(object value)
  817. {
  818. #if !NET20
  819. if (value is XObject xObject)
  820. {
  821. return XContainerWrapper.WrapNode(xObject);
  822. }
  823. #endif
  824. if (value is XmlNode node)
  825. {
  826. return XmlNodeWrapper.WrapNode(node);
  827. }
  828. throw new ArgumentException("Value must be an XML object.", nameof(value));
  829. }
  830. private void PushParentNamespaces(IXmlNode node, XmlNamespaceManager manager)
  831. {
  832. List<IXmlNode> parentElements = null;
  833. IXmlNode parent = node;
  834. while ((parent = parent.ParentNode) != null)
  835. {
  836. if (parent.NodeType == XmlNodeType.Element)
  837. {
  838. if (parentElements == null)
  839. {
  840. parentElements = new List<IXmlNode>();
  841. }
  842. parentElements.Add(parent);
  843. }
  844. }
  845. if (parentElements != null)
  846. {
  847. parentElements.Reverse();
  848. foreach (IXmlNode parentElement in parentElements)
  849. {
  850. manager.PushScope();
  851. foreach (IXmlNode attribute in parentElement.Attributes)
  852. {
  853. if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/" && attribute.LocalName != "xmlns")
  854. {
  855. manager.AddNamespace(attribute.LocalName, attribute.Value);
  856. }
  857. }
  858. }
  859. }
  860. }
  861. private string ResolveFullName(IXmlNode node, XmlNamespaceManager manager)
  862. {
  863. string prefix = (node.NamespaceUri == null || (node.LocalName == "xmlns" && node.NamespaceUri == "http://www.w3.org/2000/xmlns/"))
  864. ? null
  865. : manager.LookupPrefix(node.NamespaceUri);
  866. if (!string.IsNullOrEmpty(prefix))
  867. {
  868. return prefix + ":" + XmlConvert.DecodeName(node.LocalName);
  869. }
  870. else
  871. {
  872. return XmlConvert.DecodeName(node.LocalName);
  873. }
  874. }
  875. private string GetPropertyName(IXmlNode node, XmlNamespaceManager manager)
  876. {
  877. switch (node.NodeType)
  878. {
  879. case XmlNodeType.Attribute:
  880. if (node.NamespaceUri == JsonNamespaceUri)
  881. {
  882. return "$" + node.LocalName;
  883. }
  884. else
  885. {
  886. return "@" + ResolveFullName(node, manager);
  887. }
  888. case XmlNodeType.CDATA:
  889. return CDataName;
  890. case XmlNodeType.Comment:
  891. return CommentName;
  892. case XmlNodeType.Element:
  893. if (node.NamespaceUri == JsonNamespaceUri)
  894. {
  895. return "$" + node.LocalName;
  896. }
  897. else
  898. {
  899. return ResolveFullName(node, manager);
  900. }
  901. case XmlNodeType.ProcessingInstruction:
  902. return "?" + ResolveFullName(node, manager);
  903. case XmlNodeType.DocumentType:
  904. return "!" + ResolveFullName(node, manager);
  905. case XmlNodeType.XmlDeclaration:
  906. return DeclarationName;
  907. case XmlNodeType.SignificantWhitespace:
  908. return SignificantWhitespaceName;
  909. case XmlNodeType.Text:
  910. return TextName;
  911. case XmlNodeType.Whitespace:
  912. return WhitespaceName;
  913. default:
  914. throw new JsonSerializationException("Unexpected XmlNodeType when getting node name: " + node.NodeType);
  915. }
  916. }
  917. private bool IsArray(IXmlNode node)
  918. {
  919. foreach (IXmlNode attribute in node.Attributes)
  920. {
  921. if (attribute.LocalName == "Array" && attribute.NamespaceUri == JsonNamespaceUri)
  922. {
  923. return XmlConvert.ToBoolean(attribute.Value);
  924. }
  925. }
  926. return false;
  927. }
  928. private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
  929. {
  930. switch (node.ChildNodes.Count)
  931. {
  932. case 0:
  933. {
  934. // nothing to serialize
  935. break;
  936. }
  937. case 1:
  938. {
  939. // avoid grouping when there is only one node
  940. string nodeName = GetPropertyName(node.ChildNodes[0], manager);
  941. WriteGroupedNodes(writer, manager, writePropertyName, node.ChildNodes, nodeName);
  942. break;
  943. }
  944. default:
  945. {
  946. // check whether nodes have the same name
  947. // if they don't then group into dictionary together by name
  948. // value of dictionary will be a single IXmlNode when there is one for a name,
  949. // or a List<IXmlNode> when there are multiple
  950. Dictionary<string, object> nodesGroupedByName = null;
  951. string nodeName = null;
  952. for (int i = 0; i < node.ChildNodes.Count; i++)
  953. {
  954. IXmlNode childNode = node.ChildNodes[i];
  955. string currentNodeName = GetPropertyName(childNode, manager);
  956. if (nodesGroupedByName == null)
  957. {
  958. if (nodeName == null)
  959. {
  960. nodeName = currentNodeName;
  961. }
  962. else if (currentNodeName == nodeName)
  963. {
  964. // current node name matches others
  965. }
  966. else
  967. {
  968. nodesGroupedByName = new Dictionary<string, object>();
  969. if (i > 1)
  970. {
  971. List<IXmlNode> nodes = new List<IXmlNode>(i);
  972. for (int j = 0; j < i; j++)
  973. {
  974. nodes.Add(node.ChildNodes[j]);
  975. }
  976. nodesGroupedByName.Add(nodeName, nodes);
  977. }
  978. else
  979. {
  980. nodesGroupedByName.Add(nodeName, node.ChildNodes[0]);
  981. }
  982. nodesGroupedByName.Add(currentNodeName, childNode);
  983. }
  984. }
  985. else
  986. {
  987. if (!nodesGroupedByName.TryGetValue(currentNodeName, out object value))
  988. {
  989. nodesGroupedByName.Add(currentNodeName, childNode);
  990. }
  991. else
  992. {
  993. if (!(value is List<IXmlNode> nodes))
  994. {
  995. nodes = new List<IXmlNode> {(IXmlNode)value};
  996. nodesGroupedByName[currentNodeName] = nodes;
  997. }
  998. nodes.Add(childNode);
  999. }
  1000. }
  1001. }
  1002. if (nodesGroupedByName == null)
  1003. {
  1004. WriteGroupedNodes(writer, manager, writePropertyName, node.ChildNodes, nodeName);
  1005. }
  1006. else
  1007. {
  1008. // loop through grouped nodes. write single name instances as normal,
  1009. // write multiple names together in an array
  1010. foreach (KeyValuePair<string, object> nodeNameGroup in nodesGroupedByName)
  1011. {
  1012. if (nodeNameGroup.Value is List<IXmlNode> nodes)
  1013. {
  1014. WriteGroupedNodes(writer, manager, writePropertyName, nodes, nodeNameGroup.Key);
  1015. }
  1016. else
  1017. {
  1018. WriteGroupedNodes(writer, manager, writePropertyName, (IXmlNode)nodeNameGroup.Value, nodeNameGroup.Key);
  1019. }
  1020. }
  1021. }
  1022. break;
  1023. }
  1024. }
  1025. }
  1026. private void WriteGroupedNodes(JsonWriter writer, XmlNamespaceManager manager, bool writePropertyName, List<IXmlNode> groupedNodes, string elementNames)
  1027. {
  1028. bool writeArray = groupedNodes.Count != 1 || IsArray(groupedNodes[0]);
  1029. if (!writeArray)
  1030. {
  1031. SerializeNode(writer, groupedNodes[0], manager, writePropertyName);
  1032. }
  1033. else
  1034. {
  1035. if (writePropertyName)
  1036. {
  1037. writer.WritePropertyName(elementNames);
  1038. }
  1039. writer.WriteStartArray();
  1040. for (int i = 0; i < groupedNodes.Count; i++)
  1041. {
  1042. SerializeNode(writer, groupedNodes[i], manager, false);
  1043. }
  1044. writer.WriteEndArray();
  1045. }
  1046. }
  1047. private void WriteGroupedNodes(JsonWriter writer, XmlNamespaceManager manager, bool writePropertyName, IXmlNode node, string elementNames)
  1048. {
  1049. bool writeArray = IsArray(node);
  1050. if (!writeArray)
  1051. {
  1052. SerializeNode(writer, node, manager, writePropertyName);
  1053. }
  1054. else
  1055. {
  1056. if (writePropertyName)
  1057. {
  1058. writer.WritePropertyName(elementNames);
  1059. }
  1060. writer.WriteStartArray();
  1061. SerializeNode(writer, node, manager, false);
  1062. writer.WriteEndArray();
  1063. }
  1064. }
  1065. private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager manager, bool writePropertyName)
  1066. {
  1067. switch (node.NodeType)
  1068. {
  1069. case XmlNodeType.Document:
  1070. case XmlNodeType.DocumentFragment:
  1071. SerializeGroupedNodes(writer, node, manager, writePropertyName);
  1072. break;
  1073. case XmlNodeType.Element:
  1074. if (IsArray(node) && AllSameName(node) && node.ChildNodes.Count > 0)
  1075. {
  1076. SerializeGroupedNodes(writer, node, manager, false);
  1077. }
  1078. else
  1079. {
  1080. manager.PushScope();
  1081. foreach (IXmlNode attribute in node.Attributes)
  1082. {
  1083. if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/")
  1084. {
  1085. string namespacePrefix = (attribute.LocalName != "xmlns")
  1086. ? XmlConvert.DecodeName(attribute.LocalName)
  1087. : string.Empty;
  1088. string namespaceUri = attribute.Value;
  1089. manager.AddNamespace(namespacePrefix, namespaceUri);
  1090. }
  1091. }
  1092. if (writePropertyName)
  1093. {
  1094. writer.WritePropertyName(GetPropertyName(node, manager));
  1095. }
  1096. if (!ValueAttributes(node.Attributes) && node.ChildNodes.Count == 1
  1097. && node.ChildNodes[0].NodeType == XmlNodeType.Text)
  1098. {
  1099. // write elements with a single text child as a name value pair
  1100. writer.WriteValue(node.ChildNodes[0].Value);
  1101. }
  1102. else if (node.ChildNodes.Count == 0 && node.Attributes.Count == 0)
  1103. {
  1104. IXmlElement element = (IXmlElement)node;
  1105. // empty element
  1106. if (element.IsEmpty)
  1107. {
  1108. writer.WriteNull();
  1109. }
  1110. else
  1111. {
  1112. writer.WriteValue(string.Empty);
  1113. }
  1114. }
  1115. else
  1116. {
  1117. writer.WriteStartObject();
  1118. for (int i = 0; i < node.Attributes.Count; i++)
  1119. {
  1120. SerializeNode(writer, node.Attributes[i], manager, true);
  1121. }
  1122. SerializeGroupedNodes(writer, node, manager, true);
  1123. writer.WriteEndObject();
  1124. }
  1125. manager.PopScope();
  1126. }
  1127. break;
  1128. case XmlNodeType.Comment:
  1129. if (writePropertyName)
  1130. {
  1131. writer.WriteComment(node.Value);
  1132. }
  1133. break;
  1134. case XmlNodeType.Attribute:
  1135. case XmlNodeType.Text:
  1136. case XmlNodeType.CDATA:
  1137. case XmlNodeType.ProcessingInstruction:
  1138. case XmlNodeType.Whitespace:
  1139. case XmlNodeType.SignificantWhitespace:
  1140. if (node.NamespaceUri == "http://www.w3.org/2000/xmlns/" && node.Value == JsonNamespaceUri)
  1141. {
  1142. return;
  1143. }
  1144. if (node.NamespaceUri == JsonNamespaceUri)
  1145. {
  1146. if (node.LocalName == "Array")
  1147. {
  1148. return;
  1149. }
  1150. }
  1151. if (writePropertyName)
  1152. {
  1153. writer.WritePropertyName(GetPropertyName(node, manager));
  1154. }
  1155. writer.WriteValue(node.Value);
  1156. break;
  1157. case XmlNodeType.XmlDeclaration:
  1158. IXmlDeclaration declaration = (IXmlDeclaration)node;
  1159. writer.WritePropertyName(GetPropertyName(node, manager));
  1160. writer.WriteStartObject();
  1161. if (!string.IsNullOrEmpty(declaration.Version))
  1162. {
  1163. writer.WritePropertyName("@version");
  1164. writer.WriteValue(declaration.Version);
  1165. }
  1166. if (!string.IsNullOrEmpty(declaration.Encoding))
  1167. {
  1168. writer.WritePropertyName("@encoding");
  1169. writer.WriteValue(declaration.Encoding);
  1170. }
  1171. if (!string.IsNullOrEmpty(declaration.Standalone))
  1172. {
  1173. writer.WritePropertyName("@standalone");
  1174. writer.WriteValue(declaration.Standalone);
  1175. }
  1176. writer.WriteEndObject();
  1177. break;
  1178. case XmlNodeType.DocumentType:
  1179. IXmlDocumentType documentType = (IXmlDocumentType)node;
  1180. writer.WritePropertyName(GetPropertyName(node, manager));
  1181. writer.WriteStartObject();
  1182. if (!string.IsNullOrEmpty(documentType.Name))
  1183. {
  1184. writer.WritePropertyName("@name");
  1185. writer.WriteValue(documentType.Name);
  1186. }
  1187. if (!string.IsNullOrEmpty(documentType.Public))
  1188. {
  1189. writer.WritePropertyName("@public");
  1190. writer.WriteValue(documentType.Public);
  1191. }
  1192. if (!string.IsNullOrEmpty(documentType.System))
  1193. {
  1194. writer.WritePropertyName("@system");
  1195. writer.WriteValue(documentType.System);
  1196. }
  1197. if (!string.IsNullOrEmpty(documentType.InternalSubset))
  1198. {
  1199. writer.WritePropertyName("@internalSubset");
  1200. writer.WriteValue(documentType.InternalSubset);
  1201. }
  1202. writer.WriteEndObject();
  1203. break;
  1204. default:
  1205. throw new JsonSerializationException("Unexpected XmlNodeType when serializing nodes: " + node.NodeType);
  1206. }
  1207. }
  1208. private static bool AllSameName(IXmlNode node)
  1209. {
  1210. foreach (IXmlNode childNode in node.ChildNodes)
  1211. {
  1212. if (childNode.LocalName != node.LocalName)
  1213. {
  1214. return false;
  1215. }
  1216. }
  1217. return true;
  1218. }
  1219. #endregion
  1220. #region Reading
  1221. /// <summary>
  1222. /// Reads the JSON representation of the object.
  1223. /// </summary>
  1224. /// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
  1225. /// <param name="objectType">Type of the object.</param>
  1226. /// <param name="existingValue">The existing value of object being read.</param>
  1227. /// <param name="serializer">The calling serializer.</param>
  1228. /// <returns>The object value.</returns>
  1229. public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
  1230. {
  1231. switch (reader.TokenType)
  1232. {
  1233. case JsonToken.Null:
  1234. return null;
  1235. case JsonToken.StartObject:
  1236. break;
  1237. default:
  1238. throw JsonSerializationException.Create(reader, "XmlNodeConverter can only convert JSON that begins with an object.");
  1239. }
  1240. XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
  1241. IXmlDocument document = null;
  1242. IXmlNode rootNode = null;
  1243. #if !NET20
  1244. if (typeof(XObject).IsAssignableFrom(objectType))
  1245. {
  1246. if (objectType != typeof(XContainer)
  1247. && objectType != typeof(XDocument)
  1248. && objectType != typeof(XElement)
  1249. && objectType != typeof(XNode)
  1250. && objectType != typeof(XObject))
  1251. {
  1252. throw JsonSerializationException.Create(reader, "XmlNodeConverter only supports deserializing XDocument, XElement, XContainer, XNode or XObject.");
  1253. }
  1254. XDocument d = new XDocument();
  1255. document = new XDocumentWrapper(d);
  1256. rootNode = document;
  1257. }
  1258. #endif
  1259. if (typeof(XmlNode).IsAssignableFrom(objectType))
  1260. {
  1261. if (objectType != typeof(XmlDocument)
  1262. && objectType != typeof(XmlElement)
  1263. && objectType != typeof(XmlNode))
  1264. {
  1265. throw JsonSerializationException.Create(reader, "XmlNodeConverter only supports deserializing XmlDocument, XmlElement or XmlNode.");
  1266. }
  1267. XmlDocument d = new XmlDocument();
  1268. // prevent http request when resolving any DTD references
  1269. d.XmlResolver = null;
  1270. document = new XmlDocumentWrapper(d);
  1271. rootNode = document;
  1272. }
  1273. if (document == null || rootNode == null)
  1274. {
  1275. throw JsonSerializationException.Create(reader, "Unexpected type when converting XML: " + objectType);
  1276. }
  1277. if (!string.IsNullOrEmpty(DeserializeRootElementName))
  1278. {
  1279. ReadElement(reader, document, rootNode, DeserializeRootElementName, manager);
  1280. }
  1281. else
  1282. {
  1283. reader.ReadAndAssert();
  1284. DeserializeNode(reader, document, manager, rootNode);
  1285. }
  1286. #if !NET20
  1287. if (objectType == typeof(XElement))
  1288. {
  1289. XElement element = (XElement)document.DocumentElement.WrappedNode;
  1290. element.Remove();
  1291. return element;
  1292. }
  1293. #endif
  1294. if (objectType == typeof(XmlElement))
  1295. {
  1296. return document.DocumentElement.WrappedNode;
  1297. }
  1298. return document.WrappedNode;
  1299. }
  1300. private void DeserializeValue(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, string propertyName, IXmlNode currentNode)
  1301. {
  1302. switch (propertyName)
  1303. {
  1304. case TextName:
  1305. currentNode.AppendChild(document.CreateTextNode(ConvertTokenToXmlValue(reader)));
  1306. break;
  1307. case CDataName:
  1308. currentNode.AppendChild(document.CreateCDataSection(ConvertTokenToXmlValue(reader)));
  1309. break;
  1310. case WhitespaceName:
  1311. currentNode.AppendChild(document.CreateWhitespace(ConvertTokenToXmlValue(reader)));
  1312. break;
  1313. case SignificantWhitespaceName:
  1314. currentNode.AppendChild(document.CreateSignificantWhitespace(ConvertTokenToXmlValue(reader)));
  1315. break;
  1316. default:
  1317. // processing instructions and the xml declaration start with ?
  1318. if (!string.IsNullOrEmpty(propertyName) && propertyName[0] == '?')
  1319. {
  1320. CreateInstruction(reader, document, currentNode, propertyName);
  1321. }
  1322. else if (string.Equals(propertyName, "!DOCTYPE", StringComparison.OrdinalIgnoreCase))
  1323. {
  1324. CreateDocumentType(reader, document, currentNode);
  1325. }
  1326. else
  1327. {
  1328. if (reader.TokenType == JsonToken.StartArray)
  1329. {
  1330. // handle nested arrays
  1331. ReadArrayElements(reader, document, propertyName, currentNode, manager);
  1332. return;
  1333. }
  1334. // have to wait until attributes have been parsed before creating element
  1335. // attributes may contain namespace info used by the element
  1336. ReadElement(reader, document, currentNode, propertyName, manager);
  1337. }
  1338. break;
  1339. }
  1340. }
  1341. private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, XmlNamespaceManager manager)
  1342. {
  1343. if (string.IsNullOrEmpty(propertyName))
  1344. {
  1345. throw JsonSerializationException.Create(reader, "XmlNodeConverter cannot convert JSON with an empty property name to XML.");
  1346. }
  1347. Dictionary<string, string> attributeNameValues = ReadAttributeElements(reader, manager);
  1348. string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);
  1349. if (propertyName.StartsWith('@'))
  1350. {
  1351. string attributeName = propertyName.Substring(1);
  1352. string attributePrefix = MiscellaneousUtils.GetPrefix(attributeName);
  1353. AddAttribute(reader, document, currentNode, propertyName, attributeName, manager, attributePrefix);
  1354. return;
  1355. }
  1356. if (propertyName.StartsWith('$'))
  1357. {
  1358. switch (propertyName)
  1359. {
  1360. case JsonTypeReflector.ArrayValuesPropertyName:
  1361. propertyName = propertyName.Substring(1);
  1362. elementPrefix = manager.LookupPrefix(JsonNamespaceUri);
  1363. CreateElement(reader, document, currentNode, propertyName, manager, elementPrefix, attributeNameValues);
  1364. return;
  1365. case JsonTypeReflector.IdPropertyName:
  1366. case JsonTypeReflector.RefPropertyName:
  1367. case JsonTypeReflector.TypePropertyName:
  1368. case JsonTypeReflector.ValuePropertyName:
  1369. string attributeName = propertyName.Substring(1);
  1370. string attributePrefix = manager.LookupPrefix(JsonNamespaceUri);
  1371. AddAttribute(reader, document, currentNode, propertyName, attributeName, manager, attributePrefix);
  1372. return;
  1373. }
  1374. }
  1375. CreateElement(reader, document, currentNode, propertyName, manager, elementPrefix, attributeNameValues);
  1376. }
  1377. private void CreateElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string elementName, XmlNamespaceManager manager, string elementPrefix, Dictionary<string, string> attributeNameValues)
  1378. {
  1379. IXmlElement element = CreateElement(elementName, document, elementPrefix, manager);
  1380. currentNode.AppendChild(element);
  1381. if (attributeNameValues != null)
  1382. {
  1383. // add attributes to newly created element
  1384. foreach (KeyValuePair<string, string> nameValue in attributeNameValues)
  1385. {
  1386. string encodedName = XmlConvert.EncodeName(nameValue.Key);
  1387. string attributePrefix = MiscellaneousUtils.GetPrefix(nameValue.Key);
  1388. IXmlNode attribute = (!string.IsNullOrEmpty(attributePrefix)) ? document.CreateAttribute(encodedName, manager.LookupNamespace(attributePrefix) ?? string.Empty, nameValue.Value) : document.CreateAttribute(encodedName, nameValue.Value);
  1389. element.SetAttributeNode(attribute);
  1390. }
  1391. }
  1392. switch (reader.TokenType)
  1393. {
  1394. case JsonToken.String:
  1395. case JsonToken.Integer:
  1396. case JsonToken.Float:
  1397. case JsonToken.Boolean:
  1398. case JsonToken.Date:
  1399. case JsonToken.Bytes:
  1400. string text = ConvertTokenToXmlValue(reader);
  1401. if (text != null)
  1402. {
  1403. element.AppendChild(document.CreateTextNode(text));
  1404. }
  1405. break;
  1406. case JsonToken.Null:
  1407. // empty element. do nothing
  1408. break;
  1409. case JsonToken.EndObject:
  1410. // finished element will have no children to deserialize
  1411. manager.RemoveNamespace(string.Empty, manager.DefaultNamespace);
  1412. break;
  1413. default:
  1414. manager.PushScope();
  1415. DeserializeNode(reader, document, manager, element);
  1416. manager.PopScope();
  1417. manager.RemoveNamespace(string.Empty, manager.DefaultNamespace);
  1418. break;
  1419. }
  1420. }
  1421. private static void AddAttribute(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, string attributeName, XmlNamespaceManager manager, string attributePrefix)
  1422. {
  1423. if (currentNode.NodeType == XmlNodeType.Document)
  1424. {
  1425. throw JsonSerializationException.Create(reader, "JSON root object has property '{0}' that will be converted to an attribute. A root object cannot have any attribute properties. Consider specifying a DeserializeRootElementName.".FormatWith(CultureInfo.InvariantCulture, propertyName));
  1426. }
  1427. string encodedName = XmlConvert.EncodeName(attributeName);
  1428. string attributeValue = ConvertTokenToXmlValue(reader);
  1429. IXmlNode attribute = (!string.IsNullOrEmpty(attributePrefix))
  1430. ? document.CreateAttribute(encodedName, manager.LookupNamespace(attributePrefix), attributeValue)
  1431. : document.CreateAttribute(encodedName, attributeValue);
  1432. ((IXmlElement)currentNode).SetAttributeNode(attribute);
  1433. }
  1434. private static string ConvertTokenToXmlValue(JsonReader reader)
  1435. {
  1436. switch (reader.TokenType)
  1437. {
  1438. case JsonToken.String:
  1439. return reader.Value?.ToString();
  1440. case JsonToken.Integer:
  1441. #if HAVE_BIG_INTEGER
  1442. if (reader.Value is BigInteger i)
  1443. {
  1444. return i.ToString(CultureInfo.InvariantCulture);
  1445. }
  1446. #endif
  1447. return XmlConvert.ToString(Convert.ToInt64(reader.Value, CultureInfo.InvariantCulture));
  1448. case JsonToken.Float:
  1449. {
  1450. if (reader.Value is decimal d)
  1451. {
  1452. return XmlConvert.ToString(d);
  1453. }
  1454. if (reader.Value is float f)
  1455. {
  1456. return XmlConvert.ToString(f);
  1457. }
  1458. return XmlConvert.ToString(Convert.ToDouble(reader.Value, CultureInfo.InvariantCulture));
  1459. }
  1460. case JsonToken.Boolean:
  1461. return XmlConvert.ToString(Convert.ToBoolean(reader.Value, CultureInfo.InvariantCulture));
  1462. case JsonToken.Date:
  1463. {
  1464. #if !NET20
  1465. if (reader.Value is DateTimeOffset offset)
  1466. {
  1467. return XmlConvert.ToString(offset);
  1468. }
  1469. #endif
  1470. DateTime d = Convert.ToDateTime(reader.Value, CultureInfo.InvariantCulture);
  1471. #if !PORTABLE || NETSTANDARD1_3
  1472. return XmlConvert.ToString(d, DateTimeUtils.ToSerializationMode(d.Kind));
  1473. #else
  1474. return d.ToString(DateTimeUtils.ToDateTimeFormat(d.Kind), CultureInfo.InvariantCulture);
  1475. #endif
  1476. }
  1477. case JsonToken.Bytes:
  1478. return Convert.ToBase64String((byte[])reader.Value);
  1479. case JsonToken.Null:
  1480. return null;
  1481. default:
  1482. throw JsonSerializationException.Create(reader, "Cannot get an XML string value from token type '{0}'.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
  1483. }
  1484. }
  1485. private void ReadArrayElements(JsonReader reader, IXmlDocument document, string propertyName, IXmlNode currentNode, XmlNamespaceManager manager)
  1486. {
  1487. string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);
  1488. IXmlElement nestedArrayElement = CreateElement(propertyName, document, elementPrefix, manager);
  1489. currentNode.AppendChild(nestedArrayElement);
  1490. int count = 0;
  1491. while (reader.Read() && reader.TokenType != JsonToken.EndArray)
  1492. {
  1493. DeserializeValue(reader, document, manager, propertyName, nestedArrayElement);
  1494. count++;
  1495. }
  1496. if (WriteArrayAttribute)
  1497. {
  1498. AddJsonArrayAttribute(nestedArrayElement, document);
  1499. }
  1500. if (count == 1 && WriteArrayAttribute)
  1501. {
  1502. foreach (IXmlNode childNode in nestedArrayElement.ChildNodes)
  1503. {
  1504. if (childNode is IXmlElement element && element.LocalName == propertyName)
  1505. {
  1506. AddJsonArrayAttribute(element, document);
  1507. break;
  1508. }
  1509. }
  1510. }
  1511. }
  1512. private void AddJsonArrayAttribute(IXmlElement element, IXmlDocument document)
  1513. {
  1514. element.SetAttributeNode(document.CreateAttribute("json:Array", JsonNamespaceUri, "true"));
  1515. #if !NET20
  1516. // linq to xml doesn't automatically include prefixes via the namespace manager
  1517. if (element is XElementWrapper)
  1518. {
  1519. if (element.GetPrefixOfNamespace(JsonNamespaceUri) == null)
  1520. {
  1521. element.SetAttributeNode(document.CreateAttribute("xmlns:json", "http://www.w3.org/2000/xmlns/", JsonNamespaceUri));
  1522. }
  1523. }
  1524. #endif
  1525. }
  1526. private Dictionary<string, string> ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager)
  1527. {
  1528. // a string token means the element only has a single text child
  1529. switch (reader.TokenType)
  1530. {
  1531. case JsonToken.String:
  1532. case JsonToken.Null:
  1533. case JsonToken.Boolean:
  1534. case JsonToken.Integer:
  1535. case JsonToken.Float:
  1536. case JsonToken.Date:
  1537. case JsonToken.Bytes:
  1538. case JsonToken.StartConstructor:
  1539. return null;
  1540. }
  1541. Dictionary<string, string> attributeNameValues = null;
  1542. bool finished = false;
  1543. // read properties until first non-attribute is encountered
  1544. while (!finished && reader.Read())
  1545. {
  1546. switch (reader.TokenType)
  1547. {
  1548. case JsonToken.PropertyName:
  1549. string attributeName = reader.Value.ToString();
  1550. if (!string.IsNullOrEmpty(attributeName))
  1551. {
  1552. char firstChar = attributeName[0];
  1553. string attributeValue;
  1554. switch (firstChar)
  1555. {
  1556. case '@':
  1557. if (attributeNameValues == null)
  1558. {
  1559. attributeNameValues = new Dictionary<string, string>();
  1560. }
  1561. attributeName = attributeName.Substring(1);
  1562. reader.ReadAndAssert();
  1563. attributeValue = ConvertTokenToXmlValue(reader);
  1564. attributeNameValues.Add(attributeName, attributeValue);
  1565. if (IsNamespaceAttribute(attributeName, out string namespacePrefix))
  1566. {
  1567. manager.AddNamespace(namespacePrefix, attributeValue);
  1568. }
  1569. break;
  1570. case '$':
  1571. switch (attributeName)
  1572. {
  1573. case JsonTypeReflector.ArrayValuesPropertyName:
  1574. case JsonTypeReflector.IdPropertyName:
  1575. case JsonTypeReflector.RefPropertyName:
  1576. case JsonTypeReflector.TypePropertyName:
  1577. case JsonTypeReflector.ValuePropertyName:
  1578. // check that JsonNamespaceUri is in scope
  1579. // if it isn't then add it to document and namespace manager
  1580. string jsonPrefix = manager.LookupPrefix(JsonNamespaceUri);
  1581. if (jsonPrefix == null)
  1582. {
  1583. if (attributeNameValues == null)
  1584. {
  1585. attributeNameValues = new Dictionary<string, string>();
  1586. }
  1587. // ensure that the prefix used is free
  1588. int? i = null;
  1589. while (manager.LookupNamespace("json" + i) != null)
  1590. {
  1591. i = i.GetValueOrDefault() + 1;
  1592. }
  1593. jsonPrefix = "json" + i;
  1594. attributeNameValues.Add("xmlns:" + jsonPrefix, JsonNamespaceUri);
  1595. manager.AddNamespace(jsonPrefix, JsonNamespaceUri);
  1596. }
  1597. // special case $values, it will have a non-primitive value
  1598. if (attributeName == JsonTypeReflector.ArrayValuesPropertyName)
  1599. {
  1600. finished = true;
  1601. break;
  1602. }
  1603. attributeName = attributeName.Substring(1);
  1604. reader.ReadAndAssert();
  1605. if (!JsonTokenUtils.IsPrimitiveToken(reader.TokenType))
  1606. {
  1607. throw JsonSerializationException.Create(reader, "Unexpected JsonToken: " + reader.TokenType);
  1608. }
  1609. if (attributeNameValues == null)
  1610. {
  1611. attributeNameValues = new Dictionary<string, string>();
  1612. }
  1613. attributeValue = reader.Value?.ToString();
  1614. attributeNameValues.Add(jsonPrefix + ":" + attributeName, attributeValue);
  1615. break;
  1616. default:
  1617. finished = true;
  1618. break;
  1619. }
  1620. break;
  1621. default:
  1622. finished = true;
  1623. break;
  1624. }
  1625. }
  1626. else
  1627. {
  1628. finished = true;
  1629. }
  1630. break;
  1631. case JsonToken.EndObject:
  1632. case JsonToken.Comment:
  1633. finished = true;
  1634. break;
  1635. default:
  1636. throw JsonSerializationException.Create(reader, "Unexpected JsonToken: " + reader.TokenType);
  1637. }
  1638. }
  1639. return attributeNameValues;
  1640. }
  1641. private void CreateInstruction(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName)
  1642. {
  1643. if (propertyName == DeclarationName)
  1644. {
  1645. string version = null;
  1646. string encoding = null;
  1647. string standalone = null;
  1648. while (reader.Read() && reader.TokenType != JsonToken.EndObject)
  1649. {
  1650. switch (reader.Value.ToString())
  1651. {
  1652. case "@version":
  1653. reader.ReadAndAssert();
  1654. version = ConvertTokenToXmlValue(reader);
  1655. break;
  1656. case "@encoding":
  1657. reader.ReadAndAssert();
  1658. encoding = ConvertTokenToXmlValue(reader);
  1659. break;
  1660. case "@standalone":
  1661. reader.ReadAndAssert();
  1662. standalone = ConvertTokenToXmlValue(reader);
  1663. break;
  1664. default:
  1665. throw JsonSerializationException.Create(reader, "Unexpected property name encountered while deserializing XmlDeclaration: " + reader.Value);
  1666. }
  1667. }
  1668. IXmlNode declaration = document.CreateXmlDeclaration(version, encoding, standalone);
  1669. currentNode.AppendChild(declaration);
  1670. }
  1671. else
  1672. {
  1673. IXmlNode instruction = document.CreateProcessingInstruction(propertyName.Substring(1), ConvertTokenToXmlValue(reader));
  1674. currentNode.AppendChild(instruction);
  1675. }
  1676. }
  1677. private void CreateDocumentType(JsonReader reader, IXmlDocument document, IXmlNode currentNode)
  1678. {
  1679. string name = null;
  1680. string publicId = null;
  1681. string systemId = null;
  1682. string internalSubset = null;
  1683. while (reader.Read() && reader.TokenType != JsonToken.EndObject)
  1684. {
  1685. switch (reader.Value.ToString())
  1686. {
  1687. case "@name":
  1688. reader.ReadAndAssert();
  1689. name = ConvertTokenToXmlValue(reader);
  1690. break;
  1691. case "@public":
  1692. reader.ReadAndAssert();
  1693. publicId = ConvertTokenToXmlValue(reader);
  1694. break;
  1695. case "@system":
  1696. reader.ReadAndAssert();
  1697. systemId = ConvertTokenToXmlValue(reader);
  1698. break;
  1699. case "@internalSubset":
  1700. reader.ReadAndAssert();
  1701. internalSubset = ConvertTokenToXmlValue(reader);
  1702. break;
  1703. default:
  1704. throw JsonSerializationException.Create(reader, "Unexpected property name encountered while deserializing XmlDeclaration: " + reader.Value);
  1705. }
  1706. }
  1707. IXmlNode documentType = document.CreateXmlDocumentType(name, publicId, systemId, internalSubset);
  1708. currentNode.AppendChild(documentType);
  1709. }
  1710. private IXmlElement CreateElement(string elementName, IXmlDocument document, string elementPrefix, XmlNamespaceManager manager)
  1711. {
  1712. string encodeName = XmlConvert.EncodeName(elementName);
  1713. string ns = string.IsNullOrEmpty(elementPrefix) ? manager.DefaultNamespace : manager.LookupNamespace(elementPrefix);
  1714. IXmlElement element = (!string.IsNullOrEmpty(ns)) ? document.CreateElement(encodeName, ns) : document.CreateElement(encodeName);
  1715. return element;
  1716. }
  1717. private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamespaceManager manager, IXmlNode currentNode)
  1718. {
  1719. do
  1720. {
  1721. switch (reader.TokenType)
  1722. {
  1723. case JsonToken.PropertyName:
  1724. if (currentNode.NodeType == XmlNodeType.Document && document.DocumentElement != null)
  1725. {
  1726. throw JsonSerializationException.Create(reader, "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifying a DeserializeRootElementName.");
  1727. }
  1728. string propertyName = reader.Value.ToString();
  1729. reader.ReadAndAssert();
  1730. if (reader.TokenType == JsonToken.StartArray)
  1731. {
  1732. int count = 0;
  1733. while (reader.Read() && reader.TokenType != JsonToken.EndArray)
  1734. {
  1735. DeserializeValue(reader, document, manager, propertyName, currentNode);
  1736. count++;
  1737. }
  1738. if (count == 1 && WriteArrayAttribute)
  1739. {
  1740. foreach (IXmlNode childNode in currentNode.ChildNodes)
  1741. {
  1742. if (childNode is IXmlElement element && element.LocalName == propertyName)
  1743. {
  1744. AddJsonArrayAttribute(element, document);
  1745. break;
  1746. }
  1747. }
  1748. }
  1749. }
  1750. else
  1751. {
  1752. DeserializeValue(reader, document, manager, propertyName, currentNode);
  1753. }
  1754. continue;
  1755. case JsonToken.StartConstructor:
  1756. string constructorName = reader.Value.ToString();
  1757. while (reader.Read() && reader.TokenType != JsonToken.EndConstructor)
  1758. {
  1759. DeserializeValue(reader, document, manager, constructorName, currentNode);
  1760. }
  1761. break;
  1762. case JsonToken.Comment:
  1763. currentNode.AppendChild(document.CreateComment((string)reader.Value));
  1764. break;
  1765. case JsonToken.EndObject:
  1766. case JsonToken.EndArray:
  1767. return;
  1768. default:
  1769. throw JsonSerializationException.Create(reader, "Unexpected JsonToken when deserializing node: " + reader.TokenType);
  1770. }
  1771. } while (reader.Read());
  1772. // don't read if current token is a property. token was already read when parsing element attributes
  1773. }
  1774. /// <summary>
  1775. /// Checks if the <paramref name="attributeName"/> is a namespace attribute.
  1776. /// </summary>
  1777. /// <param name="attributeName">Attribute name to test.</param>
  1778. /// <param name="prefix">The attribute name prefix if it has one, otherwise an empty string.</param>
  1779. /// <returns><c>true</c> if attribute name is for a namespace attribute, otherwise <c>false</c>.</returns>
  1780. private bool IsNamespaceAttribute(string attributeName, out string prefix)
  1781. {
  1782. if (attributeName.StartsWith("xmlns", StringComparison.Ordinal))
  1783. {
  1784. if (attributeName.Length == 5)
  1785. {
  1786. prefix = string.Empty;
  1787. return true;
  1788. }
  1789. else if (attributeName[5] == ':')
  1790. {
  1791. prefix = attributeName.Substring(6, attributeName.Length - 6);
  1792. return true;
  1793. }
  1794. }
  1795. prefix = null;
  1796. return false;
  1797. }
  1798. private bool ValueAttributes(List<IXmlNode> c)
  1799. {
  1800. foreach (IXmlNode xmlNode in c)
  1801. {
  1802. if (xmlNode.NamespaceUri == JsonNamespaceUri)
  1803. {
  1804. continue;
  1805. }
  1806. if (xmlNode.NamespaceUri == "http://www.w3.org/2000/xmlns/" && xmlNode.Value == JsonNamespaceUri)
  1807. {
  1808. continue;
  1809. }
  1810. return true;
  1811. }
  1812. return false;
  1813. }
  1814. #endregion
  1815. /// <summary>
  1816. /// Determines whether this instance can convert the specified value type.
  1817. /// </summary>
  1818. /// <param name="valueType">Type of the value.</param>
  1819. /// <returns>
  1820. /// <c>true</c> if this instance can convert the specified value type; otherwise, <c>false</c>.
  1821. /// </returns>
  1822. public override bool CanConvert(Type valueType)
  1823. {
  1824. #if !NET20
  1825. if (valueType.AssignableToTypeName("System.Xml.Linq.XObject", false))
  1826. {
  1827. return IsXObject(valueType);
  1828. }
  1829. #endif
  1830. if (valueType.AssignableToTypeName("System.Xml.XmlNode", false))
  1831. {
  1832. return IsXmlNode(valueType);
  1833. }
  1834. return false;
  1835. }
  1836. #if !NET20
  1837. [MethodImpl(MethodImplOptions.NoInlining)]
  1838. private bool IsXObject(Type valueType)
  1839. {
  1840. return typeof(XObject).IsAssignableFrom(valueType);
  1841. }
  1842. #endif
  1843. [MethodImpl(MethodImplOptions.NoInlining)]
  1844. private bool IsXmlNode(Type valueType)
  1845. {
  1846. return typeof(XmlNode).IsAssignableFrom(valueType);
  1847. }
  1848. }
  1849. }