JSON 1 and JSON 2 should deserialize to the same XmlDocument.
Actual behavior
JSON 1 works.
JSON 2 fails. Some other programming languages randomize the order when serializing to JSON, which was then sent to C# server code using this library, resulting in this bug.
Newtonsoft.Json.JsonSerializationException: '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. Path '?xml', line 1, position 18.'
It should still call DeserializeValue, which calls CreateInstruction, which calls document.CreateXmlDeclaration. However, it should call PrependChild instead of AppendChild.
using System;
using System.IO;
using System.Xml;
public class Sample
{
public static void Main()
{
XmlDocument doc = new XmlDocument();
doc.LoadXml("<book genre='novel' ISBN='1-861001-57-5'>" +
"<title>Pride And Prejudice</title>" +
"</book>");
//Create an XML declaration.
XmlDeclaration xmldecl;
xmldecl = doc.CreateXmlDeclaration("1.0",null,null);
//Add the new node to the document.
XmlElement root = doc.DocumentElement;
doc.InsertBefore(xmldecl, root);
Console.WriteLine("Display the modified XML...");
doc.Save(Console.Out);
}
}
Source/destination types
Source/destination JSON
Example XML:
JSON 1:
JSON 2:
Expected behavior
JSON 1 and JSON 2 should deserialize to the same XmlDocument.
Actual behavior
JSON 1 works.
JSON 2 fails. Some other programming languages randomize the order when serializing to JSON, which was then sent to C# server code using this library, resulting in this bug.
Newtonsoft.Json.JsonSerializationException: '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. Path '?xml', line 1, position 18.'
Steps to reproduce
The bug is in this check:
https://github.com/JamesNK/Newtonsoft.Json/blob/0a2e291c0d9c0c7675d445703e51750363a549ef/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs#L2087-L2090
It should still call
DeserializeValue
, which callsCreateInstruction
, which callsdocument.CreateXmlDeclaration
. However, it should callPrependChild
instead ofAppendChild
.Consider the example at https://learn.microsoft.com/en-us/dotnet/api/system.xml.xmldocument.createxmldeclaration?view=net-7.0#examples