Deserializzare una “tabella” YAML di dati

Sto usando yamldotnet e c # per deserializzare un file creato da un’applicazione software di terze parti. I seguenti esempi di file YAML sono entrambi validi dall’applicazione:

#File1 Groups: - Name: ATeam FirstName, LastName, Age, Height: - [Joe, Soap, 21, 184] - [Mary, Ryan, 20, 169] - [Alex, Dole, 24, 174] #File2 Groups: - Name: ATeam FirstName, LastName, Height: - [Joe, Soap, 184] - [Mary, Ryan, 169] - [Alex, Dole, 174] 

Si noti che File2 non ha alcuna colonna Età ma il deserializzatore deve comunque riconoscere che il terzo valore su ogni riga è un’altezza anziché un’età. Questo dato dovrebbe rappresentare un tavolo di persone. Nel caso di File1, ad esempio, Mary Ryan ha 20 anni ed è alta 169 cm. Il deserializzatore deve capire le colonne che ha (per File2 ha solo FirstName, LastName e Height) e memorizza i dati di conseguenza negli oggetti giusti: Mary Ryan è alta 169 cm.

Allo stesso modo la documentazione del programma afferma che l’ordine delle colonne non è importante quindi File3 di seguito è un modo ugualmente valido per rappresentare i dati in File2 anche se Altezza è ora il primo:

 #File3 Groups: - Name: ATeam Height, FirstName, LastName: - [184, Joe, Soap] - [169, Mary, Ryan] - [174, Alex, Dole] 

Ho una serie di domande:

  1. È questo YAML standard? – Non sono riuscito a trovare nulla sull’uso di un numero di tasti sulla stessa riga seguito da due punti e liste di valori per rappresentare tabelle di dati.
  2. Come dovrei usare yamldotnet per deserializzare questo? Ci sono delle modifiche che posso apportare per aiutarlo?
  3. Se non riesco a utilizzare yamldotnet, come dovrei farlo?

    Come altre risposte dichiarate, questo è valido YAML. Tuttavia, la struttura del documento è specifica per l’applicazione e non utilizza alcuna caratteristica speciale di YAML per esprimere tabelle.

    È ansible analizzare facilmente questo documento utilizzando YamlDotNet. Tuttavia incontrerai due difficoltà. Il primo è che, poiché i nomi delle colonne sono posizionati all’interno della chiave, sarà necessario utilizzare un codice di serializzazione personalizzato per gestirli. Il secondo è che dovrai implementare una sorta di astrazione per poter accedere ai dati in modo tabellare.

    Ho messo una dimostrazione del concetto che illustrerà come analizzare e leggere i dati.

    Innanzitutto, crea un tipo per conservare le informazioni dal documento YAML:

     public class Document { public List Groups { get; set; } } public class Group { public string Name { get; set; } public IEnumerable ColumnNames { get; set; } public IList> Rows { get; set; } } 

    Quindi implementare IYamlTypeConverter per analizzare il tipo di Group :

     public class GroupYamlConverter : IYamlTypeConverter { private readonly Deserializer deserializer; public GroupYamlConverter(Deserializer deserializer) { this.deserializer = deserializer; } public bool Accepts(Type type) { return type == typeof(Group); } public object ReadYaml(IParser parser, Type type) { var group = new Group(); var reader = new EventReader(parser); do { var key = reader.Expect(); if(key.Value == "Name") { group.Name = reader.Expect().Value; } else { group.ColumnNames = key.Value .Split(',') .Select(n => n.Trim()) .ToArray(); group.Rows = deserializer.Deserialize>>(reader); } } while(!reader.Accept()); reader.Expect(); return group; } public void WriteYaml(IEmitter emitter, object value, Type type) { throw new NotImplementedException("TODO"); } } 

    Infine, registrare il convertitore nel deserializzatore e deserializzare il documento:

     var deserializer = new Deserializer(); deserializer.RegisterTypeConverter(new GroupYamlConverter(deserializer)); var document = deserializer.Deserialize(new StringReader(yaml)); 

    Puoi testare l’esempio operativo completo qui

    Questa è solo una prova di concetto, ma dovrebbe fungere da linea guida per la tua implementazione. Le cose che potrebbero essere migliorate includono:

    • Controllo e gestione di documenti non validi.
    • Migliorare la class del Group . Forse renderlo immutabile e aggiungere anche un indicizzatore.
    • Implementazione del metodo WriteYaml se si desidera il supporto per la serializzazione.

    Tutti questi sono file YAML validi. Si sta tuttavia erroneamente interpretando una chiave scalare con virgole come costituente una descrizione in YAML delle “colonne” nelle sequenze del valore associato a quella chiave.

    In File 1, FirstName, LastName, Age, Height è una chiave scalare a stringa singola per il mapping che è il primo elemento della sequenza che è il valore per il Group chiavi al livello superiore. Proprio come il name è. Puoi, ma non devi in ​​YAML, mettere le virgolette su tutto lo scalare.

    L’associazione che fai tra una stringa “Firstname” e “Joe” non è presente in YAML, puoi creare quell’associazione nel programma che interpreta la chiave (dividendola su ", " ) come sembra, ma YAML non ne sa nulla.

    Quindi, se vuoi essere intelligente, devi dividere tu stesso la stringa "FirstName, LastName, Age, Height" e utilizzare un meccanismo per utilizzare le “sottochiavi” per indicizzare le sequenze associate alla chiave.

    Se aiuta a capire tutto questo, il seguente è un dump json dei contenuti dei primi file, lì si vede chiaramente in cosa consistono le chiavi:

     {"Groups": [{"FirstName, LastName, Age, Height": [["Joe", "Soap", 21, 184], ["Mary", "Ryan", 20, 169], ["Alex", "Dole", 24, 174]], "Name": "ATeam"}]} 

    Ho usato la libreria ruamel.yaml basata su Python per questo (di cui sono l’autore) ma potresti anche usare un convertitore / correttore online come http://yaml-online-parser.appspot.com/