How to generate xml file with specific structure from datatables? - c#

Q :
According to some choices of the user, i will get set of Datatables from the database.
i have three datatabels:Teachers,Subjects,ClassRooms
and I want an xml file with the following structure:
<timetable importtype="database" options="idprefix:id">
<teachers options="" columns="id,name,short">
</teachers>
<subjects options="" columns="id,name,short">
</subjects>
<classrooms options="" columns="id,name,short">
</classrooms>
</timetable>
Now How to generate xml file with the previous structure and fill the xml file data from the data tables?
ex:
<teachers options="" columns="id,name,short">
<teacher id="a" name="jhon" short="jo"/>
<teacher id="b" name="philips" short="Ph"/>
<teacher id="c" name="sara" short="Sa"/>
</teachers>
From teacher datatable.
please details answer with sample example as possible.
EDIT :
private static void ConvertDataTableToXML(string schemaFile, DataTable dtTeacher, DataTable dtSubject, DataTable dtClassRoom)
{
XDocument doc = new XDocument();
//Read the teachers element from xml schema file
XElement teachers = XDocument.Load(schemaFile).Descendants("teachers").SingleOrDefault();
XElement subjects = XDocument.Load(schemaFile).Descendants("subjects").SingleOrDefault();
XElement classes = XDocument.Load(schemaFile).Descendants("classrooms").SingleOrDefault();
if (teachers != null)
{
foreach (DataRow row in dtTeacher.Rows)
{
XElement teacher = new XElement("teacher");
teacher.SetAttributeValue("id", row["id"]);
teacher.SetAttributeValue("name", row["name"]);
teacher.SetAttributeValue("short", row["name"].ToString().Substring(0, 2));
teachers.Add(teacher);
}
}
if (subjects != null)
{
foreach (DataRow row in dtSubject.Rows)
{
XElement subject = new XElement("subject");
subject.SetAttributeValue("id", row["num"]);
subject.SetAttributeValue("name", row["name"]);
subject.SetAttributeValue("short", row["name"].ToString().Substring(0, 2));
subjects.Add(subject);
}
}
if (classes != null)
{
foreach (DataRow row in dtClassRoom.Rows)
{
XElement cls = new XElement("classroom");
cls.SetAttributeValue("id", row["id"]);
cls.SetAttributeValue("name", row["name"]);
cls.SetAttributeValue("short", row["name"].ToString().Substring(0, 2));
classes.Add(cls);
}
}
XElement xml = new XElement("timetable",
new XAttribute("importtype", "database"),
new XAttribute("options", "idprefix:id"),teachers,subjects,classes
);
doc.Add(xml);
string dirPath = System.Web.HttpContext.Current.Server.MapPath("~/import");
string targetFileName = Path.Combine(dirPath, "import.xml");
int counter = 1;
while (System.IO.File.Exists(targetFileName))
{
counter++;
targetFileName = Path.Combine(dirPath,
"import" + counter.ToString() + ".xml");
}
doc.Save(targetFileName);
}

You may try to read and update XML document using Linq-XML.
Have a look at sample:
//Read the teachers element from xml schema file
XElement teachers = XDocument.Load(schemaFile).Descendants("teachers").SingleOrDefault();
if (teachers != null)
{
DataTable dt = new DataTable();
dt.Columns.Add("id");
dt.Columns.Add("name");
dt.Rows.Add("1", "john");
dt.Rows.Add("2", "philips");
dt.Rows.Add("3", "sara");
XDocument doc = new XDocument();
foreach (DataRow row in dt.Rows)
{
XElement teacher = new XElement("teacher");
teacher.SetAttributeValue("id", row["id"]);
teacher.SetAttributeValue("name", row["name"]);
teacher.SetAttributeValue("short", row["name"].ToString().Substring(0,2));
teachers.Add(teacher);
}
doc.Add(teachers);
doc.Save(newFilename);
}

Related

Filling datatable based on custom XML nodes

i need to show my xml in a gridview using datatable.
My XML is composed in this way:
Click here to see the XML
Now i am getting data in this way:
XmlDocument doc = new XmlDocument();
doc.Load(#"path\MyXml.xml"); //Percorso file xml
DataTable dt = new DataTable();
foreach (XmlNode xns in doc.SelectSingleNode("Settembre"))
{
string tagName = xns.Name;
if (!dt.Columns.Contains(tagName))
{
dt.Columns.Add(tagName);
}
}
With this part of the code i add my columns based on the child tags of "Settembre" (e.g. "ven_01") and this works.
Then i am writing stuff (the innerText of the child tags of the child tags of "Settembre", e.g. "Mattina_Turno_1" in "ven_01") into the cells in this way
DataRow dr = dt.NewRow();
foreach (XmlNode xns in doc.SelectSingleNode("Settembre"))
{
dr[xns.Name] = xns.InnerText;
}
dt.Rows.Add(dr);
GridView1.DataSource = dt;
GridView1.DataBind();
And this works too but what i want to do is display a first columns made of the parent node of the innerText as rows name in first column first cell for each row (the max of them are 3, to explain better are the tag "Mattina_Turno1", "Mattina_Turno_2" and "Pomeriggio" , inside them can be some innerText)
This is what i have tried to do for a while.
Also since the rows name are only 3 and the columns name can be more than 3 i'd like to revert them, so, if it is possible, to display the rows name in the columns header(so "Mattina_Turno1", "Mattina_Turno_2" and "Pomeriggio" instead) and as rows name the "Settembre" child tags (e.g. "ven_01").
I hope i made me understandable
Please do not mark as duplicated because i searched a lot on the web and have not found a solution, so please do not downvote and mark as duplicated, it is not.
I found a solution by doing this:
DataTable dt = new DataTable();
dt.Columns.Add("Data");
foreach (XmlNode xns in doc.DocumentElement)
{
if (xns.Name == "Settembre") ///IMPLEMENTARE SELEZIONE AUTOMATICA DEL MESE IMPORTANTE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
foreach (XmlNode xn in xns)
{
string tagName = xn.Name;
var a = dt.Rows.Add(tagName);
// int index_of_a = dt.Rows.IndexOf(a);
}
}
dt.Columns.Add("Mattina Turno 1");
dt.Columns.Add("Mattina Turno 2");
dt.Columns.Add("Pomeriggio");
expo_days.DataSource = dt;
expo_days.DataBind();
foreach (XmlNode xns in doc.DocumentElement)
{
if (xns.Name == "Settembre") ///IMPLEMENTARE SELEZIONE AUTOMATICA DEL MESE IMPORTANTE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
foreach (XmlNode xn in xns)
{
string tagName = xn.Name;
var a = dt.Rows.Add(tagName);
// int index_of_a = dt.Rows.IndexOf(a);
DataRow[] rows = dt.Select("Data = '"+tagName+"'");
foreach (XmlNode xna in xn)
{ //sistemare le celle in base alla colonna della gridview
if(xna.Name == "Mattina_Turno_1") //here i specify in wich column is the "Mattina_Turno_1" and fill in that cell, and so on
expo_days.Rows[dt.Rows.IndexOf(rows[0])].Cells[3].Text = xna.InnerText;
if (xna.Name == "Mattina_Turno_2")
expo_days.Rows[dt.Rows.IndexOf(rows[0])].Cells[4].Text = xna.InnerText;
if (xna.Name == "Pomeriggio")
expo_days.Rows[dt.Rows.IndexOf(rows[0])].Cells[5].Text = xna.InnerText;
}
}
}

Saving xml Document into DataTable

Ive got an asp.net page in which im using c# to read an xml document and add each entry into a listview.
I then have the function for the user to add a new entry to the list view but i cant figure out how to save it on a button event.
This is what I have to load the document.
protected void Button6_Click(object sender, EventArgs e)
{
XmlDocument xmlDocument = new XmlDocument();
using (DataTable tabListView1 = new DataTable())
{
tabListView1.Columns.Add("value", Type.GetType("System.String"));
xmlDocument.Load(AppDomain.CurrentDomain.BaseDirectory + "/XmlFile/ListView1.xml");
XmlNodeList xmlNodeList = xmlDocument.SelectNodes("root/data[#open='1']");
foreach (XmlNode xmlNode in xmlNodeList)
{
DataRow dr = tabListView1.NewRow();
dr["value"] = xmlNode.InnerText;
tabListView1.Rows.Add(dr);
}
ListView1.DataSource = tabListView1;
ListView1.DataBind();
}
TextBox3.Text = "Microsoft";
}
How can i make it save changes back to ListView1.xml? Thanks!
Assuming you can get your datasource back as a DataTable from the control you are managing it with, this should help.
private static void SaveXml(string pathAndFileName, DataTable source)
{
XmlDocument xmlDoc = new XmlDocument();
var root = xmlDoc.CreateElement("root");
xmlDoc.AppendChild(root);
foreach (DataRow row in source.Rows)
{
var dataElement = xmlDoc.CreateElement("data");
var openAttribute = xmlDoc.CreateAttribute("open");
openAttribute.Value = "1";
dataElement.Attributes.Append(openAttribute);
dataElement.InnerText = row["value"].ToString();
root.AppendChild(dataElement);
}
xmlDoc.Save(pathAndFileName);
}

converting xml document to data table in C#

I'm trying to read a simple webservice (REST) and populate a drop down box in my C# desktop application. I;m using .net 2.0
Following is my web service return xml
<sections type="array">
<section>
<name>Standing</name>
<created-at type="datetime">2011-10-23T23:17:54+05:30</created-at>
<updated-at type="datetime">2011-10-23T23:17:54+05:30</updated-at>
<id type="integer">1</id>
<status type="integer">1</status>
<service-charge type="float">0.0</service-charge>
</section>
<section>
<name>VIP</name>
<created-at type="datetime">2011-10-30T11:27:05+05:30</created-at>
<updated-at type="datetime">2011-10-30T11:27:05+05:30</updated-at>
<id type="integer">2</id>
<status type="integer">1</status>
<service-charge type="float">10.0</service-charge>
</section>
and in the following code I'm trying to convert the xml document to a data table
public DataTable getSections() {
String url = "http://<site_url>/sections.xml";
DataTable t = new DataTable();
HttpHandler handle = new HttpHandler();
StreamReader sr = handle.executeGET(url);
String xml = "";
while (sr.Peek() >= 0)
{
xml += sr.ReadLine();
}
XmlDataDocument doc = new XmlDataDocument();
doc.LoadXml(xml);
XmlReader xmlReader = new XmlNodeReader(doc);
DataSet ds = new DataSet();
ds.ReadXml(xmlReader);
t = ds.Tables[0];
return t;
}
and in the last segment I'm trying to bind it to my drop down box (cmbSections)
DataTable t = sec.getSections();
cmbSections.DataSource = t;
cmbSections.DisplayMember = "name";
cmbSections.ValueMember = "id";
But I'm getting the following error
Cannot bind to the new display member.
Parameter name: newDisplayMember
What am i missing here, please help, I'm new to C# world
Use extension method to support conversion of XElement to Datatable. You can add this method to any of your utility classes. Make sure the class is static.
public static class XElementExtensions
{
public static DataTable ToDataTable(this XElement element)
{
DataSet ds = new DataSet();
string rawXml = element.ToString();
ds.ReadXml(new StringReader(rawXml));
return ds.Tables[0];
}
public static DataTable ToDataTable(this IEnumerable<XElement> elements)
{
return ToDataTable(new XElement("Root", elements));
}
}
How to use
//Add logic to store xml data in file or string & read accordingly here.
string file = Server.MapPath("~/Data.xml");
XDocument document = XDocument.Load(file);
var query = from b in document.Elements("sections").Elements("section")
select b;
DataTable table = query.ToDataTable();
Simple way to convert XML to DataSet:
StringReader strr = new StringReader(strXML);
XmlTextReader xtr = new XmlTextReader(strr);
YourTypeDataSet dstest = new YourTypeDataSet();
dstest.ReadXml(xtr);
if (dstest.Tables.Count > 0) ...
for correct conversion, you replace your type DataSet in place of:
DataSet dstest = new DataSet();
;)
I got it working with the following code, but I'm not quit sure if this is the correct way to do it
(This parse the above same xml)
public DataTable getSections() {
String url = "http://<site_url>/sections.xml/sections.xml";
DataTable t = new DataTable();
t.Columns.Add("id", typeof(String));
t.Columns.Add("name", typeof(String));
HttpHandler handle = new HttpHandler();
StreamReader sr = handle.executeGET(url);
String xml = "";
List<String> id = new List<string>();
List<String> name = new List<string>();
while (sr.Peek() >= 0)
{
xml += sr.ReadLine();
}
XmlDataDocument doc = new XmlDataDocument();
doc.LoadXml(xml);
XmlReader xmlReader = new XmlNodeReader(doc);
while (xmlReader.Read()){
if (xmlReader.IsStartElement()) {
String b = xmlReader.Name;
switch (xmlReader.Name) {
case "sections":
break;
case "section":
break;
case "id":
if (xmlReader.Read())
{
id.Add(xmlReader.Value.Trim());
}
break;
case "name":
if (xmlReader.Read())
{
name.Add(xmlReader.Value.Trim());
}
break;
}
}
}
int counter = 0;
foreach (String i in id) {
DataRow r = t.NewRow();
r["id"] = i;
r["name"] = name[counter];
t.Rows.Add(r);
counter += 1;
}
return t;
}
Thanks for the comments :D
Your valuable comments are always welcome

Write xml file output values to a dataset

This code is programmed to display some data values from alot of xml files is their anyway to alter it so that it write the values to a dataset/table?
static void Main(string[] args)
{
string[] fileEntries = Directory.GetFiles(#"c:\Sciclone UAC", "*.cfg*");
foreach (string fileName in fileEntries)
{
XDocument doc = XDocument.Load(fileName);
var query = from x in doc.Descendants("XAxisCalib")
select new
{
//Max1 = x.Attribute("Max").Value,
//Min2 = x.Attribute("Min").Value
MaxChild = x.Descendants("Max"),
MinChild = x.Descendants("Min")
};
foreach (var x in query)
{
foreach (var nextLevel in x.MaxChild)
{
Console.WriteLine("XMax: " + nextLevel.Value);
}
foreach (var nextLevel in x.MinChild)
{
Console.WriteLine("XMin: " + nextLevel.Value);
}
//Console.WriteLine("XAxisCalib");
}
var query2 = from y in doc.Descendants("YAxisCalib")
select new
{
//Max3 = x.Attribute("Max").Value,
//Min4 = x.Attribute("Min").Value
MaxChild = y.Descendants("Max"),
MinChild = y.Descendants("Min")
};
foreach (var y in query2)
{
foreach (var nextLevel in y.MaxChild)
{
Console.WriteLine("YMax: " + nextLevel.Value);
}
foreach (var nextLevel in y.MinChild)
{
Console.WriteLine("YMin: " + nextLevel.Value);
}
//Console.WriteLine("YAxisCalib");
var query3 = from z in doc.Descendants("ZAxisCalib")
select new
{
//Max5 = x.Attribute("Max").Value,
//Min6 = x.Attribute("Min").Value
MaxChild = z.Descendants("Max"),
MinChild = z.Descendants("Min")
};
foreach (var z in query3)
{
foreach (var nextLevel in z.MaxChild)
{
Console.WriteLine("ZMax: " + nextLevel.Value);
}
foreach (var nextLevel in z.MinChild)
{
Console.WriteLine("ZMin: " + nextLevel.Value);
}
//Console.WriteLine("ZAxisCalib");
}
}
}
}
}
}
I don't know if I'm missing something, but what about the DataSet.ReadXml method?:
DataSet ds = new DataSet();
ds.ReadXml("myxmlfile.xml");
The ReadXml() method has an overload for passing in XmlReadMode, which provides various options handling the schema.
In your case, assuming that you want to read each XML file into it's own DataSet, you can do something like this:
string[] fileEntries = Directory.GetFiles(#"c:\Sciclone UAC", "*.cfg*");
foreach (string fileName in fileEntries)
{
DataSet ds = new DataSet();
ds.ReadXml(fileName, XmlReadMode.InferSchema);
}
To read the XML files into the same DataSet, you can do something like this:
DataSet masterSet = new DataSet();
string[] fileEntries = Directory.GetFiles(#"c:\Sciclone UAC", "*.cfg*");
foreach (string fileName in fileEntries)
{
//initialize a new dataset and read the xml into it
DataSet tempSet = new DataSet();
tempSet.ReadXml(fileName, XmlReadMode.InferSchema);
//merge the tables from the temporary datset into the master dataset
foreach (DataTable table in tempSet.Tables)
masterSet.Merge(table);
}
Here's another way of doing the same thing, using the enumerable LINQ methods:
DataSet masterSet = new DataSet();
string[] fileEntries = Directory.GetFiles(#"c:\Sciclone UAC", "*.cfg*");
foreach (string fileName in fileEntries)
{
//initialize a new dataset and read the xml into it
DataSet tempSet = new DataSet();
tempSet.ReadXml(fileName, XmlReadMode.InferSchema);
//merge the tables from the temporary datset into the master dataset
tempSet.Tables.Cast<DataTable>().ToList().ForEach(table => masterSet.Merge(table));
}
One of the XmlReadMode enumerations should definitely suit your needs.
Auto
DiffGram
Fragment
IgnoreSchema
InferSchema
InferTypedSchema
ReadSchema
Here is a link on MSDN that explains what the different XmlReadMode enumerations do:
http://msdn.microsoft.com/en-us/library/system.data.xmlreadmode.aspx

Read from XML > Add to Listview

I have some problems getting the data that i read from XML split into seperate columns. Any help this new C# coder would get would be appreciated.
XDocument xmlDoc = XDocument.Load("emails.xml");
var t = from c in xmlDoc.Descendants("dt")
select (string)c.Element("name") + (string)c.Element("email");
foreach (string item in t)
{
listView.Items.Add(item);
}
XDocument xmlDoc = XDocument.Load("emails.xml");
var t = from c in xmlDoc.Descendants("dt")
select new
{
Name = e.Element("name").Value,
EMail = e.Element("email").Value,
};
foreach (var item in t)
{
var lvi = listView.Items.Add(item.Name);
lvi.SubItems.Add(item.EMail);
}

Categories