2015-10-06 14 views
9

10レベル以上のネストされたJSONオブジェクトをC#.NETのCSVファイルに変換しています。ネストされたJSONをCSVに変換する

私はJavaScriptSerializer().Deserialize<ObjectA>(json)またはXmlNode xml = (XmlDocument)JsonConvert.DeserializeXmlNode(json)を使用してオブジェクトを分解しています。私はさらにオブジェクトを使ってCSVファイルに書き込むことができます。ただし、JSONオブジェクトはさらに拡張されています。実際に使用されていないほとんどのデータですので、rawデータのダンプを優先します。

構造を宣言することなく、データをCSV形式にダンプすることは簡単ですか?

サンプルJSON

{ 
"F1":1, 
"F2":2, 
"F3":[ 
    { 
     "E1":3, 
     "E2":4 
    }, 
    { 
     "E1":5, 
     "E2":6 
    }, 
    { 
     "E1":7, 
     "E2":8, 
     "E3":[ 
      { 
       "D1":9, 
       "D2":10 
      } 
     ] 
    },  
] 
} 

そして、あなたの要求に矛盾があります

F1,F2,E1,E2,D1,D2 
1,2 
1,2,3,4 
1,2,5,6 
1,2,7,8,9,10 
+0

あなたはそのデータをデータテーブルに変換できません。そこからCSV – MethodMan

+0

@MethodManに変換してください。これはまさに私が最初のいくつかのレベルを処理したものです。結局のところ、それらを構造化するのは時間がかかりすぎるので、オートメーションがあるかどうかを確認しています。 – ydoow

+0

そこから来るデータの源はどこですか?それはdbに格納されていますか? – MethodMan

答えて

6

私の予想CSV出力がある:あなたが行が子を持つルートオブジェクト、のために生成されるようにしたいが、 "F3[2]"オブジェクトの行が生成されることは望ましくありません。このオブジェクトには子もあります。つまり、少なくとも1つのプリミティブ値プロパティを持つオブジェクトの行を、そのオブジェクトがルートオブジェクトか、少なくとも1つのプリミティブ値プロパティを持つ子孫オブジェクトを持たない限り印刷します。 。それは少しトリッキーですが、出力

public static class EnumerableExtensions 
{ 
    // http://stackoverflow.com/questions/3471899/how-to-convert-linq-results-to-hashset-or-hashedset 
    public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source) 
    { 
     return new HashSet<T>(source); 
    } 
} 

使用LINQ to JSON

 var obj = JObject.Parse(json); 

     // Collect column titles: all property names whose values are of type JValue, distinct, in order of encountering them. 
     var values = obj.DescendantsAndSelf() 
      .OfType<JProperty>() 
      .Where(p => p.Value is JValue) 
      .GroupBy(p => p.Name) 
      .ToList(); 

     var columns = values.Select(g => g.Key).ToArray(); 

     // Filter JObjects that have child objects that have values. 
     var parentsWithChildren = values.SelectMany(g => g).SelectMany(v => v.AncestorsAndSelf().OfType<JObject>().Skip(1)).ToHashSet(); 

     // Collect all data rows: for every object, go through the column titles and get the value of that property in the closest ancestor or self that has a value of that name. 
     var rows = obj 
      .DescendantsAndSelf() 
      .OfType<JObject>() 
      .Where(o => o.PropertyValues().OfType<JValue>().Any()) 
      .Where(o => o == obj || !parentsWithChildren.Contains(o)) // Show a row for the root object + objects that have no children. 
      .Select(o => columns.Select(c => o.AncestorsAndSelf() 
       .OfType<JObject>() 
       .Select(parent => parent[c]) 
       .Where(v => v is JValue) 
       .Select(v => (string)v) 
       .FirstOrDefault()) 
       .Reverse() // Trim trailing nulls 
       .SkipWhile(s => s == null) 
       .Reverse()); 

     // Convert to CSV 
     var csvRows = new[] { columns }.Concat(rows).Select(r => string.Join(",", r)); 
     var csv = string.Join("\n", csvRows); 

     Console.WriteLine(csv); 

で行うことができます。

F1,F2,E1,E2,D1,D2 
1,2 
1,2,3,4 
1,2,5,6 
1,2,7,8,9,10 
+0

これは解決策としてマークされていないか、少なくともコメントされているのは残念です。何か....私はこれを試して終わると私は戻って報告します。 –

1

を私はこれを書いて、それが私のために働いているの ここでは、オブジェクトツリーのすべてのブレッドクランプをヘッダーにprop_ を支える、フォーマットPROP1のヘッダーにatantionため

public Dictionary<string, string> ComplexJsonToDictionary(JObject jObject, Dictionary<string, string> result, string field) 
    { 
     foreach (var property in jObject.Properties()) 
     { 
      var endField = field + (string.IsNullOrEmpty(field) ? "" : "_") + property.Name; 

      var innerDictionary = new Dictionary<string, string>(); 
      try 
      { 
       var innerValue = JObject.Parse(Convert.ToString(property.Value)); 


       result.AddOrOverride(ComplexJsonToDictionary(innerValue, innerDictionary, endField)); 
      } 
      catch (Exception) 
      { 
       try 
       { 
        var innerValues = JArray.Parse(Convert.ToString(property.Value)); 
        try 
        { 
         var i = 0; 
         foreach (var token in innerValues) 
         { 
          var innerValue = JObject.Parse(Convert.ToString(token)); 

          result.AddOrOverride(ComplexJsonToDictionary(innerValue, innerDictionary, endField+i++)); 
         } 
        } 
        catch (Exception) 
        { 
         result.Add(endField, string.Join(",", innerValues.Values<string>())); 
        } 
       } 
       catch (Exception) 
       { 
        result.Add(endField, property.Value.ToString()); 
       } 
      } 
     } 
     return result; 
    } 

感謝をjarrayプロパティオブジェクトを保存し、適切な場合には、レビューを書いてください。