当循环遍历一个元素的数组时,xml到json使用newtonsoft问题

时间:2014-01-27 14:04:03

标签: c# xml linq json.net

只有在源xml中只有一个元素的集合时才会出错 在第一个元素的示例中,我正确获得子元素(item),但在第二个元素中只有一个子元素,因此代码抛出异常(无法访问Newtonsoft.Json.Linq.JProperty上的子值)

由于

JObject firstLevels = new JObject();
string sourceXML = "<Root>
                        <FirstLevel id=\"1\" name=\"1\">
                            <Item id=\"1\" name=\"1.1\" />
                                <Item id=\"2\" name=\"1.2\" />
                        </FirstLevel>
                        <FirstLevel id=\"2\" name=\"2\">
                            <Item id=\"1\" name=\"2.1\" />
                        </FirstLevel>
                    </Root>";

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(sourceXML);
XmlNodeList nodeList;
nodeList = xmlDoc.SelectNodes("Root/FirstLevel");
JArray jarray = new JArray();

foreach (XmlNode node in nodeList)
{
    string json = Newtonsoft.Json.JsonConvert.SerializeXmlNode(node);
    jarray.Add(JObject.Parse(json));
}

firstLevels["result"] = jarray;

foreach(var first in firstLevels["result"].Children<JObject>())
{
    Console.WriteLine(first["FirstLevel"]["@name"].Value<string>());

    foreach (var item in first["FirstLevel"]["Item"])
        Console.WriteLine(" -- " + item["@name"].Value<string>());
}

2 个答案:

答案 0 :(得分:2)

所以你这样做:

string json = Newtonsoft.Json.JsonConvert.SerializeXmlNode(node);

对于这两个节点:

<FirstLevel id=\"1\" name=\"1\">
    <Item id=\"1\" name=\"1.1\" />
        <Item id=\"2\" name=\"1.2\" />
</FirstLevel>

<FirstLevel id=\"2\" name=\"2\">
    <Item id=\"1\" name=\"2.1\" />
</FirstLevel>

现在,在第二种情况下,JSON .Net无法知道是创建一个包含单个元素的集合,还是只创建一个元素(即{a:{}}或{a:[{}]}}所以它将它转换为单个对象。

但这并不是你所期待的。您需要它始终是一个数组,以使您的JSON一致。这个问题已经有了这个问题:JSON.Net Xml Serialization misunderstands arrays值得一读。

因此,您认为我有几个选择:


调整您的XML以向JSON .Net提供有关如何操作的提示

为此,您需要向根节点(xmlns:json='http://james.newtonking.com/projects/json')添加命名空间,并为要参与数组的节点添加属性(json:Array='true')。

例如:

string sourceXML = "<Root xmlns:json='http://james.newtonking.com/projects/json'><FirstLevel id=\"1\" name=\"1\"><Item json:Array='true' id=\"1\" name=\"1.1\" /><Item json:Array='true' id=\"2\" name=\"1.2\" /></FirstLevel><FirstLevel id=\"2\" name=\"2\"><Item json:Array='true' id=\"1\" name=\"2.1\" /></FirstLevel></Root>";

详细信息:http://james.newtonking.com/projects/json/help/?topic=html/ConvertingJSONandXML.html


放入虚拟节点以强制JSON .NET序列化为数组

我真的不喜欢这个,但是如果你不能调整XML,那么将你的代码改成像这样的东西就可以了:

foreach (XmlNode node in nodeList)
{        
    string json;
    if (node.SelectNodes("Item").Count == 1)
    {
        // Append a dummy node and then strip it out - horrible!
        node.AppendChild(xmlDoc.CreateNode("element", "Item", ""));
        json = Newtonsoft.Json.JsonConvert.SerializeXmlNode(node).Replace(",null]", "]");
    }
    else
    {
        json = Newtonsoft.Json.JsonConvert.SerializeXmlNode(node);                    
    }

    jarray.Add(JObject.Parse(json));
}

检查时

当然,您可以在处理数据时检查类型,如下所示:

foreach (var first in firstLevels["result"].Children<JObject>())
{
    Console.WriteLine(first["FirstLevel"]["@name"].Value<string>());

    if (first["FirstLevel"]["Item"] is Newtonsoft.Json.Linq.JObject)
    {
        Console.WriteLine(" -- " + first["FirstLevel"]["Item"]["@name"].Value<string>());
    }
    else
    {
        foreach (var item in first["FirstLevel"]["Item"])
            Console.WriteLine(" -- " + item["@name"].Value<string>());
    }
}

答案 1 :(得分:0)

您无需手动执行此xml到json转换

string sourceXML = "<Root><FirstLevel id=\"1\" name=\"1\"><Item id=\"1\" name=\"1.1\" /><Item id=\"2\" name=\"1.2\" /></FirstLevel><FirstLevel id=\"2\" name=\"2\"><Item id=\"1\" name=\"2.1\" /></FirstLevel></Root>";

var json = JsonConvert.SerializeObject(XDocument.Parse(sourceXML));

或获取json数组

var json2 = JsonConvert.SerializeObject(XDocument.Parse(sourceXML)
                                                 .Descendants("FirstLevel"));