Skip to content
This repository has been archived by the owner on Mar 25, 2024. It is now read-only.

Commit

Permalink
Validate xml (#25)
Browse files Browse the repository at this point in the history
* added validation of changeLog after failed transaction

* continue after dataset fails

* write more info when validating

* group errorMessages by localId
  • Loading branch information
Jarle Pedersen authored May 20, 2019
1 parent 432444c commit 1b57760
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 7 deletions.
17 changes: 15 additions & 2 deletions CORESubscriber/Changelog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,21 @@ private static void DoTransactions(FileInfo fileInfo)

Dataset.SetEndindex(GetEndIndex(changelogXml));

changelogXml.Descendants(Provider.ChangelogNamespace + "transactions")
.ToList().ForEach(PrepareAndSendTransaction);
try
{
changelogXml.Descendants(Provider.ChangelogNamespace + "transactions")
.ToList().ForEach(PrepareAndSendTransaction);
}
catch (TransactionAbortedException)
{
Console.WriteLine("ERROR: Something went wrong in transaction. Attempting to validate changelog.");

Validator.Validate(changelogXml);

Console.WriteLine("INFO: Changelog is valid.");

throw;
}
}

private static void PrepareAndSendTransaction(XElement transaction)
Expand Down
33 changes: 28 additions & 5 deletions CORESubscriber/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,23 +91,46 @@ private static void SynchronizeSubscribedDatasets()
{
var timer = StartTimer();

var datasetsUpdated = GetSubscribedElements().Select(SynchronizeDataset).ToList();
var datasetsUpdated = new List<string>();

var datasetsFailed = new List<string>();

foreach (var subscribedElement in GetSubscribedElements())
{
try
{
datasetsUpdated.Add(SynchronizeDataset(subscribedElement));
}
catch (Exception e)
{
datasetsFailed.Add(Dataset.GetDatasetIdFromElement(subscribedElement));

HandleExceptionText(e);
}
}

timer.Stop();

WriteStatus(datasetsUpdated.Any(d => !string.IsNullOrWhiteSpace(d)), timer);
WriteStatus(datasetsUpdated.Any(d => !string.IsNullOrWhiteSpace(d)), datasetsFailed, timer);
}

private static void WriteStatus(bool updatesFound, Stopwatch timer)
private static void WriteStatus(bool updatesFound, IReadOnlyCollection<string> datasetsFailed, Stopwatch timer)
{
if (updatesFound)
{
Console.WriteLine($"Time used: {timer.Elapsed}");
Console.WriteLine($"INFO: Time used: {timer.Elapsed}");

return;
}

if (datasetsFailed.Count > 0)
{
Console.WriteLine($"ERROR: Datasets failed \r\n\t{string.Join(", ",datasetsFailed.Select(d => d).ToList())}");

return;
}

Console.WriteLine("All datasets are up to date");
Console.WriteLine("INFO: All datasets are up to date");
}

private static string SynchronizeDataset(XObject subscribed)
Expand Down
107 changes: 107 additions & 0 deletions CORESubscriber/Validator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
using CORESubscriber.Xml;

namespace CORESubscriber
{
public class Validator
{
public static void Validate(XDocument changelogXml)
{
var validationErrors = GetValidationErrors(changelogXml);

if (validationErrors.Count <= 0) return;

throw new ValidationException(GetErrorMessage(validationErrors));
}

private static string GetErrorMessage(List<ValidationError> validationErrors)
{
var message =
"ERROR: Validation failed. Listing errors\r\n----------------------------------------------------------------\r\n";

foreach (var validationError in validationErrors)
{
message += $"\r\n\tLocalId: {validationError.LocalId}";

foreach ( var errorText in validationError.ErrorTexts)
message +=
$"\r\n\r\n{errorText}";

message += "\r\n\r\n----------------------------------------------------------------\r\n";
}



return message;
}

private static List<ValidationError> GetValidationErrors(XDocument changelogXml)
{
var schemas = GetSchemas(changelogXml);

var validationErrors = new List<ValidationError>();

Console.WriteLine("INFO: Starting validation");

changelogXml.Validate(schemas, (o, e) =>
{
var parent = GetParent(o);

var localId = parent.Descendants().First(n => n.Name.LocalName == "lokalId").Value;

if (validationErrors.Any(v => v.LocalId == localId))
validationErrors.First(v => v.LocalId == localId).ErrorTexts.Add(e.Message);

else
validationErrors.Add(new ValidationError
{
Element = parent,
LocalId = localId,
ErrorTexts = new List<string> {e.Message}
});
});

return validationErrors;
}

private static XmlSchemaSet GetSchemas(XDocument changelogXml)
{
var schemas = new XmlSchemaSet { XmlResolver = new XmlUrlResolver() };

var schemaLocationSplit = changelogXml.Root?.Attributes().First(a => a.Name.LocalName == "schemaLocation").Value.Split(" ");

if (schemaLocationSplit == null) return schemas;

for (var i = 0; i <= schemaLocationSplit.Length / 2; i = i + 2)
{
if (schemaLocationSplit[i] == XmlNamespaces.Changelog) continue;

Console.WriteLine($"INFO: Adding schema {schemaLocationSplit[i + 1]}");

schemas.Add(XmlSchema.Read(new XmlTextReader(schemaLocationSplit[i + 1]), (sender, args) => { }));
}

return schemas;
}

private static XElement GetParent(object o)
{
var parent = ((XElement)o).Parent;

return parent != null && parent.Elements().Any(e => e.Name.LocalName == "identifikasjon") ? parent : GetParent(parent);
}

internal class ValidationError
{
public XElement Element { get; set; }
public List<string> ErrorTexts { get; set; }
public string LocalId { get; set; }
}
}
}

0 comments on commit 1b57760

Please sign in to comment.