- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
在我的数据库中,我有一个包含很多列的表,其中一列包含一个 JSON 字符串(我无法控制它)。像这样:
Name Age ExtraData
---- --- ------------------
Bob 31 {c1: "1", c2: "2"} <-- string with JSON
我的 Web API 端点必须根据请求中的 Accept header 返回 XML 或 JSON。像这样:
JSON:
{
"Name": "Bob",
"Age": 31,
"ExtraData": {
"c1": 1,
"c2": 2
}
}
XML:
<person>
<Name>Bob</Name>
<Age>31</Age>
<ExtraData>
<c1>1</c1>
<c2>2</c2>
</ExtraData>
</person>
为此,我在 C# 中创建了一个这样的类:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Object ExtraData { get; set; }
}
当从数据库解析数据时,我会这样填写ExtraData
:
personInstance.ExtraData = JsonConvert.DeserializeObject(personTableRow.ExtraData);
当 Web API 返回 JSON 时,一切都按预期工作。
当 Web API 返回 XML 时,它给出一个异常:
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
内部异常是这样的(不是英文的):
Newtonsoft.Json.Linq.JToken has a circular reference and that is not supported. (O tipo 'Newtonsoft.Json.Linq.JToken' é um contrato de dados de coleção recursiva que não é suportado. Considere modificar a definição da coleção 'Newtonsoft.Json.Linq.JToken' para remover referências a si mesma.)
有没有办法在没有循环引用的情况下将 JSON 数据解析为对象?
最佳答案
您遇到了 XmlSerializer
的限制。将 JSON 对象(这是一组无序的名称/值对,用大括号括起来)反序列化为 c# object
时,Json.NET 创建一个类型为 JObject
的对象,不幸的是 XmlSerializer
不知道如何序列化 JObject
。特别是它陷入无限递归试图序列化 JToken.Parent
的 child 。因此,您需要将底层 object ExtraData
转换为 XmlSerializer
可以处理的类型。
但是,使用什么类型并不明显,因为:
表示 JSON 对象的最自然的 C# 类型是字典,以及 XmlSerializer
does not support dictionaries。
XmlSerializer
通过static 类型发现工作。可能遇到的 object
的所有多态子类型都必须通过 [XmlInclude(typof(T))]
声明。但是,如果这样做,XML 会将实际类型包含为 xsi:type
attribute,您似乎不希望在 XML 中出现这种情况。
您可以利用 [XmlAnyElement]
功能创建一个代理属性,使用 Json.NET 的 XElement
将您的 对象 ExtraData
与 XmlNodeConverter
相互转换:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
[XmlIgnore]
[JsonProperty]
public object ExtraData { get; set; }
[XmlAnyElement("ExtraData")]
[JsonIgnore]
public XElement ExtraDataXml
{
get
{
return JsonExtensions.SerializeExtraDataXElement("ExtraData", ExtraData);
}
set
{
ExtraData = JsonExtensions.DeserializeExtraDataXElement("ExtraData", value);
}
}
}
public static class JsonExtensions
{
public static XElement SerializeExtraDataXElement(string name, object extraData)
{
if (extraData == null)
return null;
var token = JToken.FromObject(extraData);
if (token is JValue)
{
return new XElement(name, (string)token);
}
else if (token is JArray)
{
return new JObject(new JProperty(name, token)).ToXElement(false, name, true);
}
else
{
return token.ToXElement(false, name, true);
}
}
public static object DeserializeExtraDataXElement(string name, XElement element)
{
object extraData;
if (element == null)
extraData = null;
else
{
extraData = element.ToJToken(true, name, true);
if (extraData is JObject)
{
var obj = (JObject)extraData;
if (obj.Count == 1 && obj.Properties().First().Name == name)
extraData = obj.Properties().First().Value;
}
if (extraData is JValue)
{
extraData = ((JValue)extraData).Value;
}
}
return extraData;
}
public static XElement ToXElement(this JToken obj, bool omitRootObject, string deserializeRootElementName, bool writeArrayAttribute)
{
if (obj == null)
return null;
using (var reader = obj.CreateReader())
{
var converter = new Newtonsoft.Json.Converters.XmlNodeConverter() { OmitRootObject = omitRootObject, DeserializeRootElementName = deserializeRootElementName, WriteArrayAttribute = writeArrayAttribute };
var jsonSerializer = JsonSerializer.CreateDefault(new JsonSerializerSettings { Converters = { converter } });
return jsonSerializer.Deserialize<XElement>(reader);
}
}
public static JToken ToJToken(this XElement xElement, bool omitRootObject, string deserializeRootElementName, bool writeArrayAttribute)
{
// Convert to Linq to XML JObject
var settings = new JsonSerializerSettings { Converters = { new XmlNodeConverter { OmitRootObject = omitRootObject, DeserializeRootElementName = deserializeRootElementName, WriteArrayAttribute = writeArrayAttribute } } };
var root = JToken.FromObject(xElement, JsonSerializer.CreateDefault(settings));
return root;
}
}
使用上面的类,我可以反序列化您的 JSON 并序列化为 XML,结果如下:
<Person>
<Name>Bob</Name>
<Age>31</Age>
<ExtraData>
<c1>1</c1>
<c2>2</c2>
</ExtraData>
</Person>
请注意,JSON 和 XML 之间存在导致问题的不一致:
JSON 原始值是“轻微”类型化的(如字符串、数字、 bool 值或空值),而 XML 文本是完全无类型的。因此,JSON 中的数值(和日期)作为字符串往返到 XML。
XML 没有数组的概念。因此,根容器为数组的 JSON 需要在序列化期间添加合成根元素。这会在转换过程中增加一些代码味道。
XML 必须有一个根元素,而有效的 JSON 可以包含原始值,例如字符串。在转换过程中再次需要合成根元素。
经过轻微测试的原型(prototype) fiddle here ,我在其中演示代码适用于 ExtraData
,它是一个 JSON 对象、一个字符串数组、一个字符串和一个 null
值(value)。
关于c# - 在 Web API 中将包含 JToken 的对象序列化为 XML 时出现循环引用异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40978662/
我的一位教授给了我们一些考试练习题,其中一个问题类似于下面(伪代码): a.setColor(blue); b.setColor(red); a = b; b.setColor(purple); b
我似乎经常使用这个测试 if( object && object !== "null" && object !== "undefined" ){ doSomething(); } 在对象上,我
C# Object/object 是值类型还是引用类型? 我检查过它们可以保留引用,但是这个引用不能用于更改对象。 using System; class MyClass { public s
我在通过 AJAX 发送 json 时遇到问题。 var data = [{"name": "Will", "surname": "Smith", "age": "40"},{"name": "Wil
当我尝试访问我的 View 中的对象 {{result}} 时(我从 Express js 服务器发送该对象),它只显示 [object][object]有谁知道如何获取 JSON 格式的值吗? 这是
我有不同类型的数据(可能是字符串、整数......)。这是一个简单的例子: public static void main(String[] args) { before("one"); }
嗨,我是 json 和 javascript 的新手。 我在这个网站找到了使用json数据作为表格的方法。 我很好奇为什么当我尝试使用 json 数据作为表时,我得到 [Object,Object]
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
我听别人说 null == object 比 object == null check 例如: void m1(Object obj ) { if(null == obj) // Is thi
Match 对象 提供了对正则表达式匹配的只读属性的访问。 说明 Match 对象只能通过 RegExp 对象的 Execute 方法来创建,该方法实际上返回了 Match 对象的集合。所有的
Class 对象 使用 Class 语句创建的对象。提供了对类的各种事件的访问。 说明 不允许显式地将一个变量声明为 Class 类型。在 VBScript 的上下文中,“类对象”一词指的是用
Folder 对象 提供对文件夹所有属性的访问。 说明 以下代码举例说明如何获得 Folder 对象并查看它的属性: Function ShowDateCreated(f
File 对象 提供对文件的所有属性的访问。 说明 以下代码举例说明如何获得一个 File 对象并查看它的属性: Function ShowDateCreated(fil
Drive 对象 提供对磁盘驱动器或网络共享的属性的访问。 说明 以下代码举例说明如何使用 Drive 对象访问驱动器的属性: Function ShowFreeSpac
FileSystemObject 对象 提供对计算机文件系统的访问。 说明 以下代码举例说明如何使用 FileSystemObject 对象返回一个 TextStream 对象,此对象可以被读
我是 javascript OOP 的新手,我认为这是一个相对基本的问题,但我无法通过搜索网络找到任何帮助。我是否遗漏了什么,或者我只是以错误的方式解决了这个问题? 这是我的示例代码: functio
我可以很容易地创造出很多不同的对象。例如像这样: var myObject = { myFunction: function () { return ""; } };
function Person(fname, lname) { this.fname = fname, this.lname = lname, this.getName = function()
任何人都可以向我解释为什么下面的代码给出 (object, Object) 吗? (console.log(dope) 给出了它应该的内容,但在 JSON.stringify 和 JSON.parse
我正在尝试完成散点图 exercise来自免费代码营。然而,我现在只自己学习了 d3 几个小时,在遵循 lynda.com 的教程后,我一直在尝试确定如何在工具提示中显示特定数据。 This code
我是一名优秀的程序员,十分优秀!