2016-07-26 16 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); 

しかしそこに、私はどのようにconvertionの間にパスを追加するには考えているために今、私はそれがこの方法を行いますか?

+0

あなたはJSONにXMLから変換されていない、あなたは '_value'と' _pathと完全に異なる表現を作成します'何かを保持する属性。ソースXMLと望ましいJSon出力の例を投稿してください。別のシェイプをシリアル化する場合は、中間ステップで変換を実行し(たとえばLINQを使用)、結果をシリアライズします –

答えて

0

しかし、それは遠回りに見えますが

と比較Json.netはXmlNodeConverterという名前JsonConverterのそれ自身の実装を使用しています。だから、あなたはそれが遠回りではない見てみたい場合は、あなたが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]" 
      } 
     } 
     ] 
    } 
    } 
} 
関連する問題