tisdag 26 april 2011

DeSerialize XML file with namespaces

Given the following XML file, I wanted to iterate over all of the records and summarize the values of all elements named HANDLED.
Each LANGUAGE has 12 records so I wanted a summary for each language and then spit it out into a .csv file.




TELEPHONE__2011-01-26.XML
345

1
SWE
12
1
4533
2400
6292
204
2196




I got nice exceptions occurring because of the namespace prefix when I first tried the following code:


var stats = from stat in xd.Descendants("CRP:PHONE_STATISTICS")
where stat.Element("LANGUAGE").Value == language
select new
{
Handled = int.Parse(stat.Element("HANDLED").Value),
Abandoned = int.Parse(stat.Element("ABANDONED").Value),
Language = stat.Element("LANGUAGE").Value
};


So I then found out that I could prefix the element names with the actual namespace provided in the root element of the document, like this:


XNamespace ns = "http://somedomain/CR/PHONE";

var stats = from stat in xd.Descendants(ns + "PHONE_STATISTICS")


The end result looks like this:


namespace XMLSummarizer
{
class Program
{
static void Main(string[] args)
{
XNamespace ns = "http://somedomain/CR/PHONE";

string txtLogFileName = @"data.csv";
string XMLfolder = Directory.GetCurrentDirectory();

TextWriter tw = new StreamWriter(txtLogFileName);

tw.WriteLine("Date;Month;Handled;Abandoned;Language");

foreach (var file in System.IO.Directory.EnumerateFiles(XMLfolder,"*.xml"))
{
DateTime statsDate = DateTime.Parse(file.Substring(file.IndexOf("_PHONE") + 7, 10));
Console.WriteLine(statsDate.ToShortDateString());

XDocument xd = XDocument.Load(file);

string[] languages = new string[] { "SWE", "DAN", "NOR", "FIN" };

foreach (string language in languages)
{
SummarizeDataPerDay(ns, tw, xd, language, statsDate);
}
}

tw.Flush();
tw.Close();

Console.WriteLine("Operation completed successfully. Press [Enter] to close application.");
Console.ReadLine();
}

private static void SummarizeDataPerDay(XNamespace ns, TextWriter tw, XDocument xd, string language, DateTime dataDate)
{
var stats = from stat in xd.Descendants(ns + "PHONE_STATISTICS")
where stat.Element("LANGUAGE").Value == language
select new
{
Handled = int.Parse(stat.Element("HANDLED").Value),
Abandoned = int.Parse(stat.Element("ABANDONED").Value),
Language = stat.Element("LANGUAGE").Value
};

string lang = "";
int handledCalls = 0;
int abandonedCalls = 0;

foreach (var stat in stats)
{
handledCalls += stat.Handled;
abandonedCalls += stat.Abandoned;
lang = stat.Language;
}

tw.WriteLine(dataDate + ";" + dataDate.Month + ";" + handledCalls + ";" + abandonedCalls + ";" + lang);
}
}
}