【问题标题】:Newtonsoft DeserializeXNode expands internal arrays incorrectlyNewtonsoft DeserializeXNode 错误地扩展内部数组
【发布时间】:2017-09-24 00:57:08
【问题描述】:

我有一个 JSON 对象,如下所示:

{
  "property1": "value1",
  "property2": "value2",
  "property3": ["value3","value4","value5"]
}

但是,当我尝试使用 DeserializeXNode 转换为 XML 时,数组消失了。

<MyObj>
    <property1>value1</property1>
    <property2>value2</property2>
    <property3>value3</property3>
    <property3>value4</property3>
    <property3>value5</property3>
</MyObj>

当我尝试重新序列化回对象时,这会导致问题,因为我收到“无法将字符串转换为字符串 []”错误。此外,当我尝试解析文档时,重复的属性被覆盖,只剩下最后一个值。我尝试将 DeserializeXNode 的第三个参数设置为正确的想法,这样可以正确标记数组,但这并没有改变任何东西。

根据我对 Newtonsoft 文档的理解,XML 应该看起来更像:

<MyObj>
    <property1>value1</property1>
    <property2>value2</property2>
    <property3 type="array">
        <item>value3</item>
        <item>value4</item>
        <item>value5</item>
    </property3>
</MyObj>

我需要做什么才能使数组正确转换为 XML,以便它作为数组返回 JSON?

作为参考,这是我正在使用的代码(继承,所以我不确定它是否有意义):

ObjectToXML:

var json = JsonConvert.SerializeObject(o);
var xdoc = JsonConvert.DeserializeXNode(json, "MyObj", true);
return xdoc.ToString();

XMLToObject:

XDocument d = XDocument.Parse(xml, LoadOptions.None);
d.Descendants().ForEach(e => e.Attributes().Remove());
var json = JsonConvert.SerializeXNode(d);
json = json.Replace("\"?xml\":{\"@version\":\"1.0\",\"@encoding\":\"utf-16\"},\"MyObj\":{", "")
    .Replace("{\"MyObj\":", "")
    .Replace("}}", "}")
    .Replace("{\"anyType\":", "")
    .Replace("]}", "]");
return JsonConvert.DeserializeObject<T>(json);

还有对象本身:

public class MyObj
{
    public string property1 { get; set; }
    public string property2 { get; set; }
    public string[] property3 { get; set; }
}

【问题讨论】:

  • xml 应该是什么样的?
  • @AakashM 根据文档编辑了我期望看到的内容

标签: c# arrays json xml json.net


【解决方案1】:

我不确定你在documentation 的什么地方读到了这篇文章。我已经查看过,但找不到任何表明 XML 应该像您建议的那样的内容。

其工作原理是可以将多个具有相同名称的元素推断为一个数组。来自文档:

同一层级的多个同名节点组合成一个数组。

如果只有一个元素源自数组,那么您正在使用的重载会指示序列化程序添加一个属性,指示该元素是一个数组。您的输出将如下所示:

<MyObj xmlns:json="http://james.newtonking.com/projects/json">
  <property1>value1</property1>
  <property2>value2</property2>
  <property3 json:Array="true">value3</property3>
</MyObj>

如果您使用以下代码通过 XML 往返:

var asXml = JsonConvert.DeserializeXNode(json, "MyObj", writeArrayAttribute: true);
var asJson = JsonConvert.SerializeXNode(asXml, Formatting.Indented, omitRootObject: true);

您会得到完全相同的 JSON。所以我在这里找不到问题。

您可以在this fiddle 中看到结果,包括反序列化为MyObj

【讨论】:

  • 是的,如果我能让 XML 像这样转换回 JSON,它会完美地回落到对象中。那没有发生。 XML 仅包含数组中的最后一个值,不包含数组属性。
  • @Roger 我已经更新了我的答案。在我的测试中,您的 JSON 通过 XML 往返。
  • 感谢指正。我用你的代码替换了我的方法,它似乎适用于多个值。但是,单值数组在反序列化时会中断,因为 JSON 出于某种原因返回 "property3": [{"#text": "value3"}]。这也发生在你的小提琴中。有什么想法吗?
  • @Roger 现在 很奇怪。我希望这是因为 XML 具有属性,这就是序列化程序处理带有属性的元素的方式:属性是键/值对,而带有键 #text 的文本。听起来您真正应该在这里使用的是XmlSerializer - 这将使您从XML 到MyObj 而无需JSON 步骤。如果您需要 JSON,则可以序列化该对象。请参阅this fiddle,它显示了此操作与数组中的单个项目一起使用。
猜你喜欢
  • 2016-09-09
  • 1970-01-01
  • 2016-11-17
  • 1970-01-01
  • 2015-03-02
  • 1970-01-01
  • 2012-03-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多