Bin ein mittelmäßiger C# Programmierer.
Ich möchte in einem Ordner yaml-Dateien unbekannter Struktur validieren. Mir reicht also eine Methode, die für gültige yaml-Dateien true, für ungültige false zurückliefert. Der Inhalt der Dateien interessiert weiter nicht.
Ich habe per nuget die Bibliothek yamlDotNet ausprobiert, komm damit aber nicht klar. Da gibt es zwar ein Beispiel , das eine yaml-Datei validiert.
// By manipulating the list of node deserializers,
// it is easy to add behavior to the deserializer.
// This example shows how to validate the objects as they are deserialized.
using System;
using System.IO;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using YamlDotNet.Core;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NodeDeserializers;
// First, we'll implement a new INodeDeserializer
// that will decorate another INodeDeserializer with validation:
public class ValidatingNodeDeserializer : INodeDeserializer
{
private readonly INodeDeserializer _nodeDeserializer;
public ValidatingNodeDeserializer(INodeDeserializer nodeDeserializer)
{
_nodeDeserializer = nodeDeserializer;
}
public bool Deserialize(EventReader reader, Type expectedType,
Func<EventReader, Type, object> nestedObjectDeserializer,
out object value)
{
if (_nodeDeserializer.Deserialize(reader, expectedType,
nestedObjectDeserializer, out value))
{
var context = new ValidationContext(value, null, null);
Validator.ValidateObject(value, context, true);
return true;
}
return false;
}
}
public class Program
{
public static void Main()
{
// Then we wrap the existing ObjectNodeDeserializer
// with our ValidatingNodeDeserializer:
var deserializer = new Deserializer();
var objectDeserializer = deserializer.NodeDeserializers
.Select((d, i) => new {
Deserializer = d as ObjectNodeDeserializer,
Index = i
})
.First(d => d.Deserializer != null);
deserializer.NodeDeserializers[objectDeserializer.Index] =
new ValidatingNodeDeserializer(objectDeserializer.Deserializer);
// This will fail with a validation exception
deserializer.Deserialize<Data>(new StringReader(@"Name: ~"));
}
}
public class Data
{
[Required]
public string Name { get; set; }
}
Das Beispiel setzt aber voraus, dass ich die "Key-Namen" der assoziativen Listen der yaml-Datei kenne. Die kenne ich bei meinen yaml-Dateien allerdings nicht.
Habt Ihr Tipps oder auch nur Stichwörter, die mir weiterhelfen?
Das Problem ist, dass diese Komponente mit Serialisierung und Deserialisierung arbeitet.
Damit dies aber klappt, muss der Typ der aus der YAML Datei gelesen werden soll bekannt sein.
Entsprechend bringt dir diese Komponente nichts, da du eben den Content nicht kennst.
Im schlimmsten Fall müsstest du dir einen eigenen Parser basteln, der den Dateiaufbau wirklich sauber validieren kann ohne die Typen darin zu kennen.
Ob das aber klappt, kann ich mangels YAML Erfahrung nicht sagen.
Die Frage ist, was dies für Dateien sind und warum du diese validieren musst.
Kannst du dazu noch ein paar Informationen liefern?
Vielleicht lässt sich das Problem anderst lösen, wenn der Ursprung der Dateien klar ist.
Nachtrag:
Könnte vielleicht doch noch was werden mit der Komponente.
Folgendes Snippet gibt es noch bei den Beispielen.
Die ersten Zeilen sollten reichen.
Du musst im Bestfall nur schauen ob Load eine Exception wirft bei ungültigen Dokumenten.
Ist zwar kein schöner Ansatz, dürfte aber reichen um das Problem zu lösen.
using System;
using System.Text;
using System.IO;
using System.Collections.Generic;
using YamlDotNet.RepresentationModel;
namespace YamlDotNet.Samples
{
public class LoadYamlStream
{
public void Main()
{
// Setup the input
var input = new StringReader(Document);
// Load the stream
var yaml = new YamlStream();
yaml.Load(input);
// Examine the stream
var mapping =
(YamlMappingNode)yaml.Documents[0].RootNode;
foreach (var entry in mapping.Children)
{
Console.WriteLine(((YamlScalarNode)entry.Key).Value);
}
// List all the items
var items = (YamlSequenceNode)mapping.Children[new YamlScalarNode("items")];
foreach (YamlMappingNode item in items)
{
Console.WriteLine(
"{0}\t{1}",
item.Children[new YamlScalarNode("part_no")],
item.Children[new YamlScalarNode("descrip")]
);
}
}
private const string Document = @"---
receipt: Oz-Ware Purchase Invoice
date: 2007-08-06
customer:
given: Dorothy
family: Gale
items:
- part_no: A4786
descrip: Water Bucket (Filled)
price: 1.47
quantity: 4
- part_no: E1628
descrip: High Heeled ""Ruby"" Slippers
price: 100.27
quantity: 1
bill-to: &id001
street: |
123 Tornado Alley
Suite 16
city: East Westville
state: KS
ship-to: *id001
specialDelivery: >
Follow the Yellow Brick
Road to the Emerald City.
Pay no attention to the
man behind the curtain.
...";
}
}
Nachtrag 2:
Wenn ich den Code richtig lese, sollte es reichen einen StreamReader pro Datei an die Load Methode zu geben.
Dann liest er die Dateien durch und sollte bei ungültigen Daten sogar knallen.
Entsprechend sollte die Lösung mit dem Snippet recht einfach sein.
Code könnte dann so aussehen.
Ist nur schnell in Notepad++ runtergetippt, musst du also selbst testen und prüfen ob es so passt 😃
public bool ParseFile(string filePath)
{
using(StreamReader reader = new StreamReader(File.OpenRead(filePath))
{
try
{
// Load the stream
var yaml = new YamlStream();
yaml.Load(reader);
// Dokumente sollten nicht leer sein!
if(yaml.Documents.Count == 0)
return false;
// Examine the stream
var mapping = (YamlMappingNode)yaml.Documents[0].RootNode;
// Root Node hat keine Child Nodes, sollte auch nicht sein
if(mapping.Children.Count == 0)
return false;
return true;
}
catch(Exception e)
{
// ToDo:
// Exception bearbeiten
}
// Hier kommen wir nur hin, wenn wir eine Exception hatten!
return false;
}
}
T-Virus
Developer, Developer, Developer, Developer....
99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.
Herzlichen Dank! Das funktioniert. Konnte in Deinem fix in Notepad++ runtergehackten Code nur in der Zeile
yaml.Load(reader);
keinen Streamreader übergeben. Mit StringReader ging es dann.
@cScharping
Eigentlich gibt es eine Überladung, die einen TextReader erwartet.
Da StreamReader eine Ableitung von TextReader ist, sollte es eigentlich keine Probleme geben.
Oder gab es einen Compilerfehler?
Entsprechende Methode in YamlStream:
public void Load(TextReader input)
T-Virus
Developer, Developer, Developer, Developer....
99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.