2015-10-06 18 views
9

Sto convertendo un oggetto JSON nidificato con più di 10 livelli nel file CSV in C# .NET.Conversione da JSON nidificato a CSV

Ho utilizzato JavaScriptSerializer().Deserialize<ObjectA>(json) o XmlNode xml = (XmlDocument)JsonConvert.DeserializeXmlNode(json) per suddividere l'oggetto. Con gli oggetti posso ulteriormente scrivere nel file CSV. Tuttavia ora l'oggetto JSON si espande ulteriormente. La maggior parte dei dati non è realmente in uso, quindi preferirei un dump di dati grezzi.

È così che posso semplicemente scaricare i dati in formato csv senza dichiarare la struttura?

Esempio JSON

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

E la mia uscita CSV atteso è

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

non è possibile convertire tali dati in un datatable .. quindi da lì convertire in CSV – MethodMan

+0

@MethodMan che è esattamente quello che ho fatto per gestire i primi livelli. Dopotutto, ho scoperto che è troppo dispendioso in termini di tempo per inserirli nella struttura, quindi sto verificando se c'è qualche automazione. – ydoow

+0

dov'è la fonte dei dati provenienti da ... è memorizzata in un db ..? – MethodMan

risposta

6

C'è un'incoerenza nella richiesta: si desidera una riga da generare per l'oggetto root, che ha figli, ma non si desidera generare una riga per l'oggetto "F3[2]", che ha anche figli. Quindi sembra che la tua regola sia, "stampa una riga per un oggetto con almeno una proprietà di valore primitivo, purché quell'oggetto sia l'oggetto radice o non abbia oggetti discendenti con almeno una proprietà valore primitivo" . Questo è un po 'difficile, ma può essere fatto con 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); 

Utilizzando

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

quali uscite:

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

È un peccato che questo non sia stato contrassegnato come soluzione o quanto meno commentato. Qualcosa ... Se finisco per provare, ti riporto. –

1

ho scritto questo e si sta lavorando per me Qui salviamo tutti i breadcrump dell'albero degli oggetti nelle intestazioni con il formato prop_ prop E salvare gli oggetti di proprietà jarray in intestazioni in formato prop1

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

Grazie per atantion e vi prego di scrivere una recensione, se del caso.