I have a datatable that looks like the following
public static DataTable SetColumnHeaders(DataTable KeyDataTable)
{
KeyDataTable.Columns.Add(\"First_Name
You can bake your "isInsured" check and your selection of a person into the one query;
var query = from p in xmlDoc.Elements()
where ((string)p.Element("InsuredOrPrincipalInfo")
.Element("InsuredOrPrincipalRoleCd")) == "Insured"
select new
{
Firstname = (string)p.Element("GeneralPartyInfo")
.Element("NameInfo")
.Element("PersonName")
.Element("GivenName"),
LastName = (string)p.Element("GeneralPartyInfo")
.Element("NameInfo")
.Element("PersonName")
.Element("Surname"),
};
var person = query.FirstOrDefault();
if (person != null)
{
var fileRow = AutoDataTable.NewRow();
fileRow["First_Name"] = person.Firstname;
fileRow["Last_name"] = person.LastName;
}
This isn't super-robust in terms of handling XML in an unexpected format, but it should serve as a good starting point for you. Just fill out the anonymous object initialization with the rest of your elements, casting to the desired types.
This is what I have so far.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.IO;
using System.Data;
namespace xmlCustomReformat
{
class importXml
{
public DataTable _ComboDataTable;
public void ExportAutoToText()
{
DirectoryInfo AutoDir = new DirectoryInfo(FilePrep.AutoDirectory);
CreateDataTable(); // set column headers
foreach (FileInfo File in AutoDir.GetFiles())
{
DataRow fileRow = _ComboDataTable.NewRow();
XDocument xmlDoc = XDocument.Load(AutoDir + File.Name);
InsuredOrPrincipal[] insured = xmlDoc.Root
.Descendants("InsuredOrPrincipal")
.Select(x => new InsuredOrPrincipal(x))
.Where(ip => ip.InsuredOrPrincipalInfo.InsuredOrPrincipalRoleCd == "Insured")
.ToArray();
foreach (var person in insured)
{
fileRow["First_Name"] = person.GeneralPartyInfo.NameInfo.PersonName.GivenName;
fileRow["Last_name"] = person.GeneralPartyInfo.NameInfo.PersonName.Surname;
fileRow["Address1"] = person.GeneralPartyInfo.Addr.Address1;
fileRow["City"] = person.GeneralPartyInfo.Addr.City;
fileRow["State"] = person.GeneralPartyInfo.Addr.State;
fileRow["Zip"] = person.GeneralPartyInfo.Addr.Zip;
fileRow["Address2"] = " ";
fileRow["Zip4"] = " ";
fileRow["Match_File"] = File.Name.ToString();
_ComboDataTable.Rows.Add(fileRow);
}
}
}
public void ExportHomeToText()
{
DirectoryInfo HomeDir = new DirectoryInfo(FilePrep.HomeDirectory);
foreach (FileInfo File in HomeDir.GetFiles())
{
DataRow fileRow = _ComboDataTable.NewRow();
XDocument xmlDoc = XDocument.Load(HomeDir + File.Name);
InsuredOrPrincipal[] insured = xmlDoc.Root
.Descendants("InsuredOrPrincipal")
.Select(x => new InsuredOrPrincipal(x))
.Where(ip => ip.InsuredOrPrincipalInfo.InsuredOrPrincipalRoleCd == "Insured")
.ToArray();
foreach (var person in insured)
{
fileRow["First_Name"] = person.GeneralPartyInfo.NameInfo.PersonName.GivenName;
fileRow["Last_name"] = person.GeneralPartyInfo.NameInfo.PersonName.Surname;
fileRow["Address1"] = person.GeneralPartyInfo.Addr.Address1;
fileRow["City"] = person.GeneralPartyInfo.Addr.City;
fileRow["State"] = person.GeneralPartyInfo.Addr.State;
fileRow["Zip"] = person.GeneralPartyInfo.Addr.Zip;
fileRow["Address2"] = " ";
fileRow["Zip4"] = " ";
fileRow["Match_File"] = File.Name.ToString();
_ComboDataTable.Rows.Add(fileRow);
}
}
ExportDataTable.Write(_ComboDataTable, HomeDir.Parent.FullName.ToString());
}
public void CreateDataTable()
{
_ComboDataTable = new DataTable();
_ComboDataTable.Columns.Add("First_Name", typeof(string));
_ComboDataTable.Columns.Add("Last_Name", typeof(string));
_ComboDataTable.Columns.Add("Address1", typeof(string));
_ComboDataTable.Columns.Add("Address2", typeof(string));
_ComboDataTable.Columns.Add("City", typeof(string));
_ComboDataTable.Columns.Add("State", typeof(string));
_ComboDataTable.Columns.Add("Zip", typeof(string));
_ComboDataTable.Columns.Add("Zip4", typeof(string));
_ComboDataTable.Columns.Add("Match_File", typeof(string));
}
}
}
The class Comp looks like this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace xmlCustomReformat
{
public class InsuredOrPrincipal
{
XElement self;
public InsuredOrPrincipal(XElement self) { this.self = self; }
public GeneralPartyInfo GeneralPartyInfo { get { return _GeneralPartyInfo ?? (_GeneralPartyInfo = new GeneralPartyInfo(self.Element("GeneralPartyInfo"))); } }
GeneralPartyInfo _GeneralPartyInfo;
public InsuredOrPrincipalInfo InsuredOrPrincipalInfo
{ get { return _InsuredOrPrincipalInfo ?? (_InsuredOrPrincipalInfo = new InsuredOrPrincipalInfo(self.Element("InsuredOrPrincipalInfo"))); } }
InsuredOrPrincipalInfo _InsuredOrPrincipalInfo;
}
public class GeneralPartyInfo
{
XElement self;
public GeneralPartyInfo(XElement self) { this.self = self; }
public NameInfo NameInfo { get { return _NameInfo ?? (_NameInfo = new NameInfo(self.Element("NameInfo"))); } }
NameInfo _NameInfo;
public Addr Addr { get { return _Addr ?? (_Addr = new Addr(self.Element("Addr"))); } }
Addr _Addr;
}
public class InsuredOrPrincipalInfo
{
XElement self;
public InsuredOrPrincipalInfo(XElement self) { this.self = self; }
public string InsuredOrPrincipalRoleCd
{
get { return (string)self.Element("InsuredOrPrincipalRoleCd"); }
}
}
public class NameInfo
{
XElement self;
public NameInfo(XElement self) { this.self = self; }
public PersonName PersonName { get { return _PersonName ?? (_PersonName = new PersonName(self.Element("PersonName"))); } }
PersonName _PersonName;
}
public class Addr
{
XElement self;
public Addr(XElement self) { this.self = self; }
public string Address1
{
get { return (string)self.Element("Addr1"); }
}
public string City
{
get { return (string)self.Element("City"); }
}
public string State
{
get { return (string)self.Element("StateProvCd"); }
}
public string Zip
{
get { return (string)self.Element("PostalCode"); }
}
}
public class PersonName
{
XElement self;
public PersonName(XElement self) { this.self = self; }
public string Surname
{
get { return (string)self.Element("Surname"); }
}
public string GivenName
{
get { return (string)self.Element("GivenName"); }
}
}
}
And Of course my export back to a text file for my append.
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.IO;
using System.Windows.Forms;
namespace xmlCustomReformat
{
public static class ExportDataTable
{
public static void Write(DataTable dt, string filePath)
{
int i = 0;
StreamWriter sw = null;
try
{
sw = new StreamWriter(filePath + "\\Acord_Combined.txt", false);
for (i = 0; i < dt.Columns.Count-1; i++)
{
sw.Write(String.Format("{0,-50}",dt.Columns[i].ColumnName));
}
sw.Write(dt.Columns[i].ColumnName);
sw.WriteLine();
foreach (DataRow row in dt.Rows)
{
object[] array = row.ItemArray;
for (i = 0; i < array.Length - 1; i++)
{
sw.Write(String.Format("{0,-50}",array[i].ToString()));
}
sw.Write(array[i].ToString());
sw.WriteLine();
}
sw.Close();
}
catch (Exception ex)
{
MessageBox.Show("Invalid Operation : \n" + ex.ToString(),
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
Now I still need to append data back into The same xml files after I do some processing. As well as I have to depersonalize the data. So I'm assuming I just need to do sets rather than Gets. Not sure of the syntax for this process yet. If you have suggestions to improve this please feel free to leave a comment.
I prefer creating objects for each node level. It is easier to debug and test.
Using this xml library.
You'd create classes for each part, like:
public class InsuredOrPrincipal
{
XElement self;
public InsuredOrPrincipal(XElement self) { this.self = self; }
public GeneralPartyInfo GeneralPartyInfo { get { return _GeneralPartyInfo ?? (_GeneralPartyInfo = new GeneralPartyInfo(self.GetElement("GeneralPartyInfo"))); } }
GeneralPartyInfo _GeneralPartyInfo;
public InsuredOrPrincipalInfo InsuredOrPrincipalInfo
{ get { return _InsuredOrPrincipalInfo ?? (_InsuredOrPrincipalInfo = new InsuredOrPrincipalInfo(self.GetElement("InsuredOrPrincipalInfo"))); } }
InsuredOrPrincipalInfo _InsuredOrPrincipalInfo;
}
public class GeneralPartyInfo
{
XElement self;
public GeneralPartyInfo(XElement self) { this.self = self; }
public NameInfo NameInfo { get { return _NameInfo ?? (_NameInfo = new NameInfo(self.GetElement("NameInfo"))); } }
NameInfo _NameInfo;
}
public class InsuredOrPrincipalInfo
{
XElement self;
public InsuredOrPrincipalInfo(XElement self) { this.self = self; }
public string InsuredOrPrincipalRoleCd
{
get { return self.Get("InsuredOrPrincipalRoleCd", string.Empty); }
}
}
public class NameInfo
{
XElement self;
public NameInfo(XElement self) { this.self = self; }
public PersonName PersonName { get { return _PersonName ?? (_PersonName = new PersonName(self.GetElement("PersonName"))); } }
PersonName _PersonName;
}
public class PersonName
{
XElement self;
public PersonName(XElement self) { this.self = self; }
public string Surname
{
get { return self.Get("Surname", string.Empty); }
set { self.Set("Surname", value, false); }
}
}
You would use it like this:
foreach (FileInfo File in AutoDir.GetFiles())
{
DataRow fileRow = AutoDataTable.NewRow();
XDocument xmlDoc = XDocument.Load(AutoDir + File.Name);
InsuredOrPrincipal[] insured = xmlDoc.Root
.Descendants("InsuredOrPrincipal")
.Select(x => new InsuredOrPrincipal(x))
.Where(ip => ip.InsuredOrPrincipalInfo.InsuredOrPrincipalRoleCd == "Insured")
.ToArray();
foreach(var person in insured)
{
string surname = person.GeneralPartyInfo.NameInfo.PersonName.Surname;
}
}
Depending on your needs you can expand or shrink the number of classes and information per class as you need, but this is the way I'd go about it, as it makes more sense to me.
Tested with this code:
XElement test = new XElement("test");
var ip = new InsuredOrPrincipal(test);
ip.GeneralPartyInfo.NameInfo.PersonName.Surname = "Surname";
test.Save(Path.Combine(Application.StartupPath, "insuredOrPrincipal.xml"));
Which gave me the expected output:
<?xml version="1.0" encoding="utf-8"?>
<InsuredOrPrincipal>
<GeneralPartyInfo>
<NameInfo>
<PersonName>
<Surname>Surname</Surname>
</PersonName>
</NameInfo>
</GeneralPartyInfo>
</InsuredOrPrincipal>