-Fixed converting XElements without namespace attribute to JSON
This commit is contained in:
@@ -2670,6 +2670,32 @@ namespace Newtonsoft.Json.Tests.Converters
|
||||
|
||||
Assert.AreEqual("null", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeExplicitAttributeNamespace()
|
||||
{
|
||||
var original = XElement.Parse("<MyElement xmlns=\"http://example.com\" />");
|
||||
Assert.AreEqual(@"<MyElement xmlns=""http://example.com"" />", original.ToString());
|
||||
|
||||
var json = JsonConvert.SerializeObject(original);
|
||||
Assert.AreEqual(@"{""MyElement"":{""@xmlns"":""http://example.com""}}", json);
|
||||
|
||||
var deserialized = JsonConvert.DeserializeObject<XElement>(json);
|
||||
Assert.AreEqual(@"<MyElement xmlns=""http://example.com"" />", deserialized.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeImplicitAttributeNamespace()
|
||||
{
|
||||
var original = new XElement("{http://example.com}MyElement");
|
||||
Assert.AreEqual(@"<MyElement xmlns=""http://example.com"" />", original.ToString());
|
||||
|
||||
var json = JsonConvert.SerializeObject(original);
|
||||
Assert.AreEqual(@"{""MyElement"":{""@xmlns"":""http://example.com""}}", json);
|
||||
|
||||
var deserialized = JsonConvert.DeserializeObject<XElement>(json);
|
||||
Assert.AreEqual(@"<MyElement xmlns=""http://example.com"" />", deserialized.ToString());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,6 +374,40 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
Assert.AreEqual(7, c.ExtensionData.Count);
|
||||
}
|
||||
|
||||
[JsonObject(MemberSerialization.OptIn)]
|
||||
public class MyClass
|
||||
{
|
||||
public int NotForJson { get; set; }
|
||||
|
||||
[JsonPropertyAttribute(Required = Required.Always)]
|
||||
public int ForJson { get; set; }
|
||||
|
||||
[JsonExtensionData(ReadData = true, WriteData = true)]
|
||||
public IDictionary<String, JToken> ExtraInfoJson { get; set; }
|
||||
|
||||
public MyClass(MyClass other = null)
|
||||
{
|
||||
if (other != null)
|
||||
{
|
||||
// copy construct
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PopulateWithExtensionData()
|
||||
{
|
||||
string jsonStirng = @"{ ""ForJson"" : 33 , ""extra1"" : 11, ""extra2"" : 22 }";
|
||||
|
||||
MyClass c = new MyClass();
|
||||
|
||||
JsonConvert.PopulateObject(jsonStirng, c);
|
||||
|
||||
Assert.AreEqual(2, c.ExtraInfoJson.Count);
|
||||
Assert.AreEqual(11, (int)c.ExtraInfoJson["extra1"]);
|
||||
Assert.AreEqual(22, (int)c.ExtraInfoJson["extra2"]);
|
||||
}
|
||||
|
||||
public class MultipleExtensionDataAttributesTestClass
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
@@ -528,6 +528,64 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
JObject o = (JObject)actual.Payload;
|
||||
Assert.AreEqual("System.Byte[], mscorlib", (string)o["$type"]);
|
||||
Assert.AreEqual("AAECAwQFBgcICQ==", (string)o["$value"]);
|
||||
Assert.AreEqual(null, o.Parent);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadAhead_JObject_NoParent()
|
||||
{
|
||||
ItemWithUntypedPayload actual = JsonConvert.DeserializeObject<ItemWithUntypedPayload>(@"{
|
||||
""Payload"": {}
|
||||
}",
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead
|
||||
});
|
||||
|
||||
JObject o = (JObject)actual.Payload;
|
||||
Assert.AreEqual(null, o.Parent);
|
||||
}
|
||||
|
||||
public class ItemWithJTokens
|
||||
{
|
||||
public JValue Payload1 { get; set; }
|
||||
public JObject Payload2 { get; set; }
|
||||
public JArray Payload3 { get; set; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadAhead_TypedJValue_NoParent()
|
||||
{
|
||||
ItemWithJTokens actual = (ItemWithJTokens)JsonConvert.DeserializeObject(@"{
|
||||
""Payload1"": 1,
|
||||
""Payload2"": {},
|
||||
""Payload3"": [1],
|
||||
""$type"": ""Newtonsoft.Json.Tests.Serialization.MetadataPropertyHandlingTests+ItemWithJTokens, Newtonsoft.Json.Tests""
|
||||
}",
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead,
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
});
|
||||
|
||||
Assert.AreEqual(null, actual.Payload1.Parent);
|
||||
Assert.AreEqual(null, actual.Payload2.Parent);
|
||||
Assert.AreEqual(null, actual.Payload3.Parent);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadAhead_JArray_NoParent()
|
||||
{
|
||||
ItemWithUntypedPayload actual = JsonConvert.DeserializeObject<ItemWithUntypedPayload>(@"{
|
||||
""Payload"": [1]
|
||||
}",
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead
|
||||
});
|
||||
|
||||
JArray o = (JArray)actual.Payload;
|
||||
Assert.AreEqual(null, o.Parent);
|
||||
}
|
||||
|
||||
public class ItemWithUntypedPayload
|
||||
|
||||
@@ -46,7 +46,6 @@ using System.Linq;
|
||||
|
||||
namespace Newtonsoft.Json.Converters
|
||||
{
|
||||
|
||||
#region XmlNodeWrappers
|
||||
#if !DOTNET && !PORTABLE && !PORTABLE40
|
||||
internal class XmlDocumentWrapper : XmlNodeWrapper, IXmlDocument
|
||||
@@ -235,6 +234,7 @@ namespace Newtonsoft.Json.Converters
|
||||
{
|
||||
private readonly XmlNode _node;
|
||||
private IList<IXmlNode> _childNodes;
|
||||
private IList<IXmlNode> _attributes;
|
||||
|
||||
public XmlNodeWrapper(XmlNode node)
|
||||
{
|
||||
@@ -295,7 +295,14 @@ namespace Newtonsoft.Json.Converters
|
||||
return null;
|
||||
}
|
||||
|
||||
return _node.Attributes.Cast<XmlAttribute>().Select(WrapNode).ToList();
|
||||
// attributes is read multiple times
|
||||
// cache results to prevent multiple reads which kills perf in large documents
|
||||
if (_attributes == null)
|
||||
{
|
||||
_attributes = _node.Attributes.Cast<XmlAttribute>().Select(WrapNode).ToList();
|
||||
}
|
||||
|
||||
return _attributes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,6 +334,7 @@ namespace Newtonsoft.Json.Converters
|
||||
XmlNodeWrapper xmlNodeWrapper = (XmlNodeWrapper)newChild;
|
||||
_node.AppendChild(xmlNodeWrapper._node);
|
||||
_childNodes = null;
|
||||
_attributes = null;
|
||||
|
||||
return newChild;
|
||||
}
|
||||
@@ -861,6 +869,8 @@ namespace Newtonsoft.Json.Converters
|
||||
|
||||
internal class XElementWrapper : XContainerWrapper, IXmlElement
|
||||
{
|
||||
private IList<IXmlNode> _attributes;
|
||||
|
||||
private XElement Element
|
||||
{
|
||||
get { return (XElement)WrappedNode; }
|
||||
@@ -875,11 +885,52 @@ namespace Newtonsoft.Json.Converters
|
||||
{
|
||||
XObjectWrapper wrapper = (XObjectWrapper)attribute;
|
||||
Element.Add(wrapper.WrappedNode);
|
||||
_attributes = null;
|
||||
}
|
||||
|
||||
public override IList<IXmlNode> Attributes
|
||||
{
|
||||
get { return Element.Attributes().Select(a => new XAttributeWrapper(a)).Cast<IXmlNode>().ToList(); }
|
||||
get
|
||||
{
|
||||
// attributes is read multiple times
|
||||
// cache results to prevent multiple reads which kills perf in large documents
|
||||
if (_attributes == null)
|
||||
{
|
||||
_attributes = Element.Attributes().Select(a => new XAttributeWrapper(a)).Cast<IXmlNode>().ToList();
|
||||
|
||||
// ensure elements created with a namespace but no namespace attribute are converted correctly
|
||||
// e.g. new XElement("{http://example.com}MyElement");
|
||||
string namespaceUri = NamespaceUri;
|
||||
if (!string.IsNullOrEmpty(namespaceUri) && namespaceUri != ParentNode?.NamespaceUri)
|
||||
{
|
||||
if (string.IsNullOrEmpty(GetPrefixOfNamespace(namespaceUri)))
|
||||
{
|
||||
bool namespaceDeclared = false;
|
||||
foreach (IXmlNode attribute in _attributes)
|
||||
{
|
||||
if (attribute.LocalName == "xmlns" && string.IsNullOrEmpty(attribute.NamespaceUri) && attribute.Value == namespaceUri)
|
||||
{
|
||||
namespaceDeclared = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!namespaceDeclared)
|
||||
{
|
||||
_attributes.Insert(0, new XAttributeWrapper(new XAttribute("xmlns", namespaceUri)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _attributes;
|
||||
}
|
||||
}
|
||||
|
||||
public override IXmlNode AppendChild(IXmlNode newChild)
|
||||
{
|
||||
IXmlNode result = base.AppendChild(newChild);
|
||||
_attributes = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string Value
|
||||
|
||||
Reference in New Issue
Block a user