2016-07-26 114 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]" 
      } 
     } 
     ] 
    } 
    } 
}