2016-07-26 98 views
1

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

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; 
     } 

但它看起来迂回比较:

XmlDocument doc = new XmlDocument(); 
doc.LoadXml(xml); 
string jsonText = JsonConvert.SerializeXmlNode(doc); 

但那里我不知道如何皈依过程中添加的路径?

+0

你是不是从XML转换成JSON,您创建一个完全不同的表现与'_value'和'_path '拥有......某些东西的属性。请发布源XML和期望的JSon输出的示例。如果要序列化不同的形状,请在中间步骤(例如,使用LINQ)中执行转换,然后序列化结果 –

回答

0

但它看起来迂回比较

Json.net使用它自己的执行JsonConverter命名为XmlNodeConverter。所以,如果你希望它看起来没有迂回,可以实现your own JsonConverter并使用它:

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

这是一个很好的,但相当复杂的任务。

但是更简单一点的方法是在序列化之前使用xpath属性追加xml节点。例如:

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]" 
      } 
     } 
     ] 
    } 
    } 
}