Reputation: 31
I have been doing a lot of research on various ways to compare directories of XML files to each other, such that each "actual build" XML file has a matching "template build" XML file. These templates are going to be the actual config files for future builds, so I need to go back through the currently working config files and check for differences in data. These differences will be included as client changeable configurations for the future builds.
I have looked at the XML Diff and Patch (both GUI and VisStu forms) and tried to get differences, but it returns exceptions left and right and can never get the diffGram created. It seems that the XD&P is looking for library elements that no longer exist or have been changed in ways that break it.
Now, I am brand new to XML and LINQ, but I know this is where my answer lies. I have been thinking about creating path strings for every line such that the following xml file:
<configuration>
<title>#ClientOfficialName# Interactive Map</title>
<subtitle>Powered By Yada</subtitle>
<logo>assets/images/mainpageglobe.png</logo>
<style alpha="0.9">
<colors>0xffffff,0x777777,0x555555,0x333333,0xffffff</colors>
<font name="Verdana"/>
<titlefont name="Verdana"/>
<subtitlefont name="Verdana"/>
</style>
Would create strings like:
configuration/title/"#ClientOfficialName# Interactive Map"
configuration/subtitle/"Powered By Yada"
configuration/logo/"assets/iamges/mainpageglobe.png"
configuration/style/alpha/"0.9"
configuration/style/colors/"0xffffff,0x777777,0x555555,0x333333,0xffffff"
and so on like this.
In this manner, I can get every line from the Actual and the Template files and compare them based on "if they are of the same node path, then compare text. If text of all exact siblings does not match, put string into differenceOutput.txt".
So far this is the best concept I have come up with. If anyone can help me achieve this (through this or any other method), I would greatly appreciate it.
I currently have the directory system working no problem, I just have no idea where to start with the population of the string containers from the xml file:
static void Main(string[] args)
{
//Set Up File Paths
var actualBuildPath = @"C:\actual";
var templateBuildPath = @"C:\template";
//Output File Setups
var missingFileList = new List<string>();
var differenceList = new List<string>();
//Iterate through Template Directory checking to see if the Current Build Directory
//has everything and finding differences if they exist
foreach (var filePath in Directory.GetFiles(templateBuildPath, "*.xml", SearchOption.AllDirectories))
{
//Announce Current File
Console.WriteLine("File: {0} ", filePath);
//Make Sure file Exists in current build
if (File.Exists(filePath.Replace(templateBuildPath, actualBuildPath)))
{
//Fill in String Containers as prep for comparison
var templateBuildFormattedXmlLines = PopulateStringContainerFromXML(filePath);
var actualBuildFormattedXmlLines = PopulateStringContainerFromXML(filePath.Replace(templateBuildPath, actualBuildPath));
//COMPARISON SECTION-------------------------------------------------------
xmlFileCompare(templateBuildFormattedXmlLines, actualBuildFormattedXmlLines);
}
//Put missing file into missing file output file
else
missingFileList.Add("Missing: " + filePath.Replace(templateBuildPath, actualBuildPath));
}
//Create Output Folder and Output Files
if (!Directory.Exists(actualBuildPath + @"\Outputs"))
Directory.CreateDirectory(actualBuildPath + @"\Outputs");
File.WriteAllLines(actualBuildPath + @"\Outputs\MissingFiles.txt", missingFileList);
File.WriteAllLines(actualBuildPath + @"\Outputs\differenceList.txt", differenceList);
//Wait to close console until user interacts
Console.ReadLine();
}
Upvotes: 3
Views: 260
Reputation: 383
Assuming all the configuration files are the same (grammatically) I would recomend to read them into a object and compare these objects, with this you have the possibility to make a finer grained comparison e.g the subtitle may be left out of the comparison.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace XMLTest
{
class Program
{
static void Main(string[] args)
{
//You can use the XDocument.Load() Method to load a xml from a file path rather than a string
string xml = "<configuration><title>#ClientOfficialName# Interactive Map</title><subtitle>Powered By Yada</subtitle><logo>assets/images/mainpageglobe.png</logo><style alpha=\"0.9\"> <colors>0xffffff,0x777777,0x555555,0x333333,0xffffff</colors> <font name=\"Verdana\"/> <titlefont name=\"Verdana\"/> <subtitlefont name=\"Verdana\"/></style></configuration>";
XDocument d = XDocument.Parse(xml);
Configuration c = new Configuration();
c.Title = d.Descendants().Where(x => x.Name == "title").FirstOrDefault().Value;
c.SubTitle = d.Descendants().Where(x => x.Name == "subtitle").FirstOrDefault().Value;
c.Logo = d.Descendants().Where(x => x.Name == "logo").FirstOrDefault().Value;
Configuration.Style s = new Configuration.Style();
s.Alpha = (from attr in d.Descendants().Attributes() select attr).Where(x => x.Name == "alpha").FirstOrDefault().Value;
string tmp = d.Descendants().Where(x => x.Name == "colors").FirstOrDefault().Value;
foreach (string str in tmp.Split(','))
{
s.Colors.Add(Convert.ToInt32(str, 16));
}
s.FontName = (from attr in d.Descendants().Where(x=>x.Name =="font").Attributes() select attr).Where(x => x.Name == "name").FirstOrDefault().Value;
s.TitleFontName = (from attr in d.Descendants().Where(x => x.Name == "titlefont").Attributes() select attr).Where(x => x.Name == "name").FirstOrDefault().Value;
s.SubtitleFontName = (from attr in d.Descendants().Where(x => x.Name == "subtitlefont").Attributes() select attr).Where(x => x.Name == "name").FirstOrDefault().Value;
c.MyStyle = s;
Console.WriteLine(c.ToString());
Console.ReadKey();
}
}
public class Configuration : IComparable
{
public string Title;
public string SubTitle;
public string Logo;
public Style MyStyle;
public override string ToString()
{
return string.Format("Configuration : Title: {0}, Subtitle {1}, Logo {2}, Style: {3}",Title,SubTitle,Logo,MyStyle.ToString());
}
public class Style
{
public string Alpha;
public List<int> Colors = new List<int>();
public string FontName;
public string TitleFontName;
public string SubtitleFontName;
public override string ToString()
{
string s = "Alpha :" +Alpha;
s+= ", Colors: ";
foreach(int i in Colors){
s += string.Format("{0:x},",i);
}
s += " FontName :" + FontName;
s += " TitleFontName :" + TitleFontName;
s += " SubTitleFontName :" + SubtitleFontName;
return s;
}
}
public int CompareTo(object obj)
{
if ((obj as Configuration) == null)
{
throw new ArgumentException("Not instance of configuration");
}
//Very simple comparison, ranks by the title in the comparison object, here you could compare all the other values e.g Subtitle , logo and such to test if two instances are Equal
return String.Compare(this.Title, ((Configuration)obj).Title, true);
}
}
}
For a more Complete overview of Implementing Comparison see: https://msdn.microsoft.com/en-us/library/system.icomparable.compareto%28v=vs.110%29.aspx
Upvotes: 1