简化xml到json的转换

时间:2016-07-26 10:14:44

标签: c# json xml

我正在寻找一种简单的方法将xml转换为json,并附加选项将完整的xpath添加为属性。现在我这样做:

panic: template: :2: function "IsIPv4" not defined

但与以下相比,它看起来很迂回:

  private static string XmlToJson(string xmlString)
        {
            return new JavaScriptSerializer().Serialize(GetXmlValues(XElement.Parse(xmlString)));
        }

        private static Dictionary<string, object> GetXmlValues(XElement xml)
        {
            var attr = xml.Attributes().ToDictionary(d => d.Name.LocalName, d => (object)d.Value);
            if (xml.HasElements)
            {
                attr.Add("_children", xml.Elements().Select(e => GetXmlValues(e)));
                attr.Add("_path", xml.GetPath());
            }
            else if (!xml.IsEmpty)
            {
                attr.Add("_value", xml.Value);
               attr.Add("_path", xml.GetPath());
            }
            return new Dictionary<string, object> { { xml.Name.LocalName, attr } };
        }

       private static string GetPath(this XElement node)
        {
            string path = node.Name.LocalName;
            XElement currentNode = node;
            while (currentNode.Parent != null)
            {
                currentNode = currentNode.Parent;
                path = currentNode.Name.LocalName + "/" + path;
            }
            return path;
        }

但是我不知道如何在转换过程中添加路径?

1 个答案:

答案 0 :(得分:0)

  

但与

相比,它看起来很迂回

Json.net使用它自己的名为JsonConverterXmlNodeConverter实现。因此,如果您希望它看起来不迂回,您可以实现your own JsonConverter并使用它:

var doc = XDocument.Parse(xml);
var json = JsonConvert.SerializeObject(doc, new MyXmlWithXPathJsonConverter());

这是一项很好但非常复杂的任务。

但更简单的方法是在序列化之前将xml节点附加到xpath属性。例如:

public void AppendXPath(XContainer container)
{
    if (container == null)
        throw new ArgumentNullException("container");

    var doc = container as XDocument;
    if (doc != null)
        AppendXPath(doc.Root, "", 1);
    else
        AppendXPath(container as XElement, "/", 1);
}

private void AppendXPath(XElement node, string parent, int num)
{
    var path = $"{parent}/{node.Name}[{num}]";

    if (node.Attribute("xpath") != null)
        throw new InvalidOperationException($"Node {path} already contains xpath attribute");

    var indicies = new Dictionary<XName, int>();

    foreach (var child in node.Elements())
    {
        int index;
        if (indicies.TryGetValue(child.Name, out index))
            indicies[child.Name] = ++index;
        else
            indicies[child.Name] = index = 1;

        AppendXPath(child, path, index);
    }

    node.Add(new XAttribute("xpath", path));
}

测试:

void Test()
{
    var xml =
@"<xml>
    <foo>
        <one />
        <other />
    </foo>
    <bar data=""abc"">
        <item order=""3"" />
        <item order=""1"">
            <child whatever="""" />
        </item>
    </bar>
</xml>";

    var doc = XDocument.Parse(xml);
    AppendXPath(doc);
    var json = JsonConvert.SerializeObject(doc, Newtonsoft.Json.Formatting.Indented);
    Console.WriteLine(json);
}

结果:

{
  "xml": {
    "@xpath": "/xml[1]",
    "foo": {
      "@xpath": "/xml[1]/foo[1]",
      "one": {
        "@xpath": "/xml[1]/foo[1]/one[1]"
      },
      "other": {
        "@xpath": "/xml[1]/foo[1]/other[1]"
      }
    },
    "bar": {
      "@data": "abc",
      "@xpath": "/xml[1]/bar[1]",
      "item": [
        {
          "@order": "3",
          "@xpath": "/xml[1]/bar[1]/item[1]"
        },
        {
          "@order": "1",
          "@xpath": "/xml[1]/bar[1]/item[2]",
          "child": {
            "@whatever": "",
            "@xpath": "/xml[1]/bar[1]/item[2]/child[1]"
          }
        }
      ]
    }
  }
}