Filling datatable based on custom XML nodes - c#

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;
}
}
}

Related

updating xmlnodes with foreach loop from datagridview

I'm trying to update an XML node with new data extracted from datagridview.
The issue is that the code below takes only the last values and update it.
For example, I have 2 rows in the grid with arg1 and arg.2 values. When I extract it and iterate/ update the xmlnode, only the last row (row-1) data get updated in the xmlfile and the first one is ignored. Please advise.
public void button2_Click(object sender, EventArgs e)
{
openFileDialog1.ShowDialog();
XmlDocument Newdoc = new XmlDocument();
Newdoc.Load(openFileDialog1.FileName);
int r = 0;
foreach (XmlNode updatenode in Newdoc.SelectNodes(".//event[#type='2VO']"))
{
Newdoc.SelectSingleNode(".//#Arg1").InnerText = dataGridView1.Rows[r].Cells["Arg1"].Value.ToString();
Newdoc.SelectSingleNode(".//#Arg2").InnerText = dataGridView1.Rows[r].Cells["Arg2"].Value.ToString();
r++;
}
Newdoc.Save(#"C:\Users\namokhtar\Desktop\updatednew.xml");
}

Trouble with parsing CSV files in C#

I'm trying to import a CSV file to my C# site and save it in the database. While doing research I learned about CSV parsing, I've tried to implement this but I've ran into some trouble. Here is a portion of my code so far:
string fileext = Path.GetExtension(fupcsv.PostedFile.FileName);
if (fileext == ".csv")
{
string csvPath = Server.MapPath("~/CSVFiles/") + Path.GetFileName(fupcsv.PostedFile.FileName);
fupcsv.SaveAs(csvPath);
// Add Columns to Datatable to bind data
DataTable dtCSV = new DataTable();
dtCSV.Columns.AddRange(new DataColumn[2] { new DataColumn("ModuleId", typeof(int)), new DataColumn("CourseId", typeof(int))});
// Read all the lines of the text file and close it.
string[] csvData = File.ReadAllLines(csvPath);
// iterate over each row and Split it to New line.
foreach (string row in csvData)
{
// Check for is null or empty row record
if (!string.IsNullOrEmpty(row))
{
using (TextFieldParser parser = new TextFieldParser(csvPath))
{
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
while (!parser.EndOfData)
{
//Process row
string[] fields = parser.ReadFields();
int i = 1;
foreach (char cell in row)
{
dtCSV.NewRow()[i] = cell;
i++;
}
}
}
}
}
}
I keep getting the error "There is no row at position -1" at " dtCSV.Rows[dtCSV.Rows.Count - 1][i] = cell;"
Any help would be greatly appreciated, thanks
You are trying to index rows that you have not created. Instead of
dtCSV.Rows[dtCSV.Rows.Count - 1][i] = cell;
use
dtCSV.NewRow()[i] = cell;
I also suggest you start indexing i from 0 and not from 1.
All right so it turns out there were a bunch of errors with your code, so I made some edits.
string fileext = Path.GetExtension(fupcsv.PostedFile.FileName);
if (fileext == ".csv")
{
string csvPath = Server.MapPath("~/CSVFiles/") + Path.GetFileName(fupcsv.PostedFile.FileName);
fupcsv.SaveAs(csvPath);
DataTable dtCSV = new DataTable();
dtCSV.Columns.AddRange(new DataColumn[2] { new DataColumn("ModuleId", typeof(int)), new DataColumn("CourseId", typeof(int))});
var csvData = File.ReadAllLines(csvPath);
bool headersSkipped = false;
foreach (string line in csvData)
{
if (!headersSkipped)
{
headersSkipped = true;
continue;
}
// Check for is null or empty row record
if (!string.IsNullOrEmpty(line))
{
//Process row
int i = 0;
var row = dtCSV.NewRow();
foreach (var cell in line.Split(','))
{
row[i] = Int32.Parse(cell);
i++;
}
dtCSV.Rows.Add(row);
dtCSV.AcceptChanges();
}
}
}
I ditched the TextFieldParser solution solely because I'm not familiar with it, but if you want to stick with it, it shouldn't be hard to reintegrate it.
Here are some of the things you got wrong:
Not calling NewRow() to create a new row or adding it to the table with AddRow(row)
Iterating through the characters in row instead of the fields you parsed
Not parsing the value of cell - it's value type is string and you are trying to add to an int column
Some other things worth noting (just to improve your code's performance and readability :))
Consider using var when declaring new variables, it takes a lot of the stress away from having to worry about exactly what type of variable you are creating
As others in the comments said, use ReadAllLines() it parses your text file into lines neatly, making it easier to iterate through.
Most of the times when working with arrays or lists, you need to index from 0, not from 1
You have to use AcceptChanges() to commit all the changes you've made

XML element not displaying for empty values

I am using an xml file to import into the database using the below code
CS:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(pathPMO + "Data.xml");
XmlNodeList nodeList = xmlDoc.DocumentElement.SelectNodes("/DocumentElement/Profile");
bool insertProfile = false;
foreach (XmlNode node in nodeList)
{
strYear = node.SelectSingleNode("Profile_x0020_Year").InnerText;
strID = node.SelectSingleNode("Profile_x0020_ID").InnerText;
strLead = node.SelectSingleNode("Profile_x0020_Leader").InnerText;
insertProfile = ImportProfile(strYear, strID, strLead);
}
For instance the profile leader values are empty for certain rows and when I try to insert them I get an error object not set to an instance of an object because of that particular element missing in few rows.
Can anyone suggest how to solve this?
You should ensure that each XmlNode object is not null. You can use a simple method like that:
private string GetXmlNodeString(string nodeName, XmlNode node)
{
if(String.IsNullOrWhiteSpace(nodeName))
return String.Empty;
var singleNode = node.SelectSingleNode(nodeName);
if(singleNode ==null)
return String.Empty;
return singleNode.InnerText;
}
then change your code like that:
foreach (XmlNode node in nodeList)
{
strYear = GetXmlNodeString("Profile_x0020_Year",node);
strID = GetXmlNodeString("Profile_x0020_ID",node);
strLead = GetXmlNodeString("Profile_x0020_Leader",node);
insertProfile = ImportProfile(strYear, strID, strLead);
}

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);
}

How to generate xml file with specific structure from datatables?

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);
}

Categories