C# extract - XML Child Node Attributes - c#

Sample of XML File
<NvM_DataManager_Blocks
AlignmentConstraint="ManagedBy_DataManager"
GenerateBlockAccessAPI="Yes" UseProtectedSections="Yes" UseRteForDataManagerInterface="No">
<DATA_MANAGER_EEPROM_BLOCK Block_Crc_Type="NVM_CRC16"
Block_Priority="255" Block_Type="NVM_BLOCK_NATIVE"
ErrorCallback="" FeeOrEa_BlockId=""
Name="DataManager_Block_01"
Project_specific_information=""
Resistant_To_Changed_SW="No" Storage_In="Fee" Write_Only_At_WriteAll="No">
<DATA_ELEMENT CreateCommitedApi="Yes" DataSize=""
DataSize_bit="" Data_type="uint8" Default_Value="66"
Header_file="" Name="DataManager_DataElement_01"
Number_Of_Planned_Writes="255" VariantInit="No"/>
<DATA_ELEMENT CreateCommitedApi="Yes" DataSize=""
DataSize_bit="" Data_type="uint32"
Default_Value="255" Header_file=""
Name="DataManager_DataElement_02"
Number_Of_Planned_Writes="363" VariantInit="No"/>
</DATA_MANAGER_EEPROM_BLOCK>
This is my code.
//Load xml
XDocument xdoc = XDocument.Load("C:\\Users\\John\\Desktop\\Program\\file.xml");
var blocks2 = (from r in xdoc.Descendants("DATA_MANAGER_EEPROM_BLOCK")
select new
{
Name = r.Attribute("Name").Value,
//This line below does not the produce what is req. I need some help on how to fix this.
Sub_Elements = xdoc.Descendants("DATA_MANAGER_EEPROM_BLOCK").Descendants("DATA_ELEMENT")
}).ToList();
However, I have some issue to extract the sub elements : DataManager_DataElement_01 & DataManager_DataElement_02 and their attributes.

Try following
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("CrC_Type", typeof(string));
dt.Columns.Add("Priority", typeof(int));
dt.Columns.Add("Type", typeof(string));
dt.Columns.Add("Block_Name", typeof(string));
dt.Columns.Add("Data_Type", typeof(string));
dt.Columns.Add("Default_Value", typeof(int));
dt.Columns.Add("Element_Name", typeof(string));
dt.Columns.Add("Planned_Writes", typeof(int));
XDocument doc = XDocument.Load(FILENAME);
foreach (XElement block in doc.Descendants("DATA_MANAGER_EEPROM_BLOCK"))
{
string crcType = (string)block.Attribute("Block_Crc_Type");
int blockPriority = (int)block.Attribute("Block_Priority");
string blockType = (string)block.Attribute("Block_Type");
string blockName = (string)block.Attribute("Name");
foreach(XElement element in block.Elements("DATA_ELEMENT"))
{
string dataType = (string)element.Attribute("Data_type");
int defaultValue = (int)element.Attribute("Default_Value");
string elementName = (string)element.Attribute("Name");
int plannedWrites = (int)element.Attribute("Number_Of_Planned_Writes");
dt.Rows.Add(new object[] {
crcType,
blockPriority,
blockType,
blockName,
dataType,
defaultValue,
elementName,
plannedWrites
});
}
}
}
}
}

Related

How to show full xml file in datagirdview c#

So I have a directory with many XML files. I tried to show dataset in datagirdview but not enough content, someone please help me show all the content in the file
Below is the code and XML I used.
<?xml version="1.0" encoding="UTF-8"?>
<ns1:BoardTestXMLExport numberOfIndictedComponents="4" testerTestStartTime="2021-01-18T07:46:32.000+07:00" testTime="2021-01-18T07:46:24.000+07:00" repairStationId="VNHCMING100" testStatus="Repaired" testerTestEndTime="2021-01-18T07:46:37.000+07:00" xmlns:ns1="http://tempuri.org/BoardTestXMLExport.xsd" numberOfIndictedPins="0" numberOfComponentsTested="320" numberOfJointsTested="0" numberOfDefects="4" repairStatus="Repaired">
<ns1:BoardXML imageId="3" serialNumber="21017227600" assemblyRevision="ING-296269012AC-A-B" boardType="ING-296269012AC-A-B" boardRevision="1610927415000"/>
<ns1:StationXML testerName="HCMINGAOI02" stage="V510"/>
<ns1:RepairEventXML numberOfVariationOkDefects="0" numberOfFalseCalledPins="0" numberOfRepairedComponents="2" numberOfVariationOkPins="0" numberOfRepairedPins="0" numberOfRepairLaterPins="0" numberOfFalseCalledDefects="2" numberOfActiveDefects="0" numberOfVariationOkComponents="0" repairEndTime="2021-01-18T07:49:24.000+07:00" repairStartTime="2021-01-18T07:49:10.000+07:00" numberOfRepairLaterDefects="0" repairOperator="c_admin" numberOfRepairLaterComponents="0" numberOfActiveComponents="0" numberOfActivePins="0" numberOfRepairedDefects="2" numberOfFalseCalledComponents="2"/>
<ns1:TestXML name="3:hp1400">
<ns1:IndictmentXML algorithm="u192036979" indictmentType="Wrong Polarity">
<ns1:RepairActionXML repairOperator="c_admin" repairTime="2021-01-18T07:49:11.000+07:00" repairActionType="-" indictmentType="Wrong Polarity" comment="-" repairStatus="False Call"/>
<ns1:ComponentXML packageId="192036979" partId="192036979" designator="3:hp1400"/>
</ns1:IndictmentXML>
</ns1:TestXML>
<ns1:TestXML name="3:d506">
<ns1:IndictmentXML algorithm="u192027714" indictmentType="Wrong Polarity">
<ns1:RepairActionXML repairOperator="c_admin" repairTime="2021-01-18T07:49:11.000+07:00" repairActionType="-" indictmentType="Wrong Polarity" comment="-" repairStatus="False Call"/>
<ns1:ComponentXML packageId="192027714" partId="192027714" designator="3:d506"/>
</ns1:IndictmentXML>
</ns1:TestXML>
<ns1:TestXML name="3:j1201">
<ns1:IndictmentXML algorithm="u192030753" indictmentType="Skewed">
<ns1:RepairActionXML repairOperator="c_admin" repairTime="2021-01-18T07:49:17.000+07:00" repairActionType="-" indictmentType="Skewed" comment="-" repairStatus="Repaired"/>
<ns1:ComponentXML packageId="192030753" partId="192030753" designator="3:j1201"/>
</ns1:IndictmentXML>
</ns1:TestXML>
<ns1:TestXML name="3:u2101">
<ns1:IndictmentXML algorithm="u192028597" indictmentType="Tombstoned">
<ns1:RepairActionXML repairOperator="c_admin" repairTime="2021-01-18T07:49:24.000+07:00" repairActionType="-" indictmentType="Tombstoned" comment="-" repairStatus="Repaired"/>
<ns1:ComponentXML packageId="192028597" partId="192028597" designator="3:u2101"/>
</ns1:IndictmentXML>
</ns1:TestXML>
</ns1:BoardTestXMLExport>
Code:
foreach (string FILE_PATH in Directory.EnumerateFiles(#"Test", "*.xml"))
{
//Create xml reader
XmlReader xmlFile = XmlReader.Create(FILE_PATH, new XmlReaderSettings());
DataSet dataSet = new DataSet();
//Read xml to dataset
dataSet.ReadXml(xmlFile);
//Pass empdetails table to datagridview datasource
dataGridView1.DataSource = dataSet.Tables["BoardTestXMLExport"];
//Close xml reader
xmlFile.Close();
xmlFile.Close();
}
Try following xml linq :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
const string FOLDER = #"c:\temp\";
public Form1()
{
InitializeComponent();
DataTable dt = new DataTable();
dt.Columns.Add("filename", typeof(string));
dt.Columns.Add("numberOfIndictedComponents", typeof(int));
dt.Columns.Add("testerTestStartTime", typeof(DateTime));
dt.Columns.Add("testTime", typeof(DateTime));
dt.Columns.Add("repairStationId", typeof(string));
dt.Columns.Add("testStatus", typeof(string));
dt.Columns.Add("testerTestEndTime", typeof(DateTime));
dt.Columns.Add("imageId", typeof(string));
dt.Columns.Add("serialNumber", typeof(string));
dt.Columns.Add("assemblyRevision", typeof(string));
dt.Columns.Add("boardType", typeof(string));
dt.Columns.Add("boardRevision", typeof(string));
dt.Columns.Add("testerName", typeof(string));
dt.Columns.Add("stage", typeof(string));
dt.Columns.Add("name", typeof(string));
dt.Columns.Add("algorithm", typeof(string));
dt.Columns.Add("indictmentType", typeof(string));
dt.Columns.Add("repairOperator", typeof(string));
dt.Columns.Add("repairTime", typeof(DateTime));
dt.Columns.Add("repairActionType", typeof(string));
dt.Columns.Add("comment", typeof(string));
dt.Columns.Add("repairStatus", typeof(string));
dt.Columns.Add("packageId", typeof(string));
dt.Columns.Add("partId", typeof(string));
dt.Columns.Add("designator", typeof(string));
string[] filenames = Directory.GetFiles(FOLDER,"*.xml");
foreach (string filename in filenames)
{
XDocument doc = XDocument.Load(filename);
XElement BoardTestXMLExport = doc.Root;
XNamespace ns1 = BoardTestXMLExport.GetNamespaceOfPrefix("ns1");
int numberOfIndictedComponents = (int)BoardTestXMLExport.Attribute("numberOfIndictedComponents");
DateTime testerTestStartTime = (DateTime)BoardTestXMLExport.Attribute("testerTestStartTime");
DateTime testTime = (DateTime)BoardTestXMLExport.Attribute("testTime");
string repairStationId = (string)BoardTestXMLExport.Attribute("repairStationId");
string testStatus = (string)BoardTestXMLExport.Attribute("testStatus");
DateTime testerTestEndTime = (DateTime)BoardTestXMLExport.Attribute("testerTestEndTime");
XElement BoardXML = BoardTestXMLExport.Element(ns1 + "BoardXML");
int imageId = (int)BoardXML.Attribute("imageId");
string serialNumber = (string)BoardXML.Attribute("serialNumber");
string assemblyRevision = (string)BoardXML.Attribute("assemblyRevision");
string boardType = (string)BoardXML.Attribute("boardType");
string boardRevision = (string)BoardXML.Attribute("boardRevision");
XElement StationXML = BoardTestXMLExport.Element(ns1 + "StationXML");
string testerName = (string)StationXML.Attribute("testerName");
string stage = (string)StationXML.Attribute("stage");
foreach (XElement TestXML in doc.Descendants(ns1 + "TestXML"))
{
DataRow newRow = dt.Rows.Add();
newRow["filename"] = filename;
newRow["numberOfIndictedComponents"] = numberOfIndictedComponents;
newRow["testerTestStartTime"] = testerTestStartTime;
newRow["testTime"] = testTime;
newRow["repairStationId"] = repairStationId;
newRow["testStatus"] = testStatus;
newRow["testerTestEndTime"] = testerTestEndTime;
newRow["imageId"] = imageId;
newRow["serialNumber"] = serialNumber;
newRow["assemblyRevision"] = assemblyRevision;
newRow["boardType"] = boardType;
newRow["boardRevision"] = boardRevision;
newRow["boardType"] = boardType;
newRow["testerName"] = testerName;
newRow["stage"] = stage;
newRow["name"] = (string)TestXML.Attribute("name");
XElement IndictmentXML = TestXML.Element(ns1 + "IndictmentXML");
newRow["algorithm"] = (string)IndictmentXML.Attribute("algorithm");
newRow["indictmentType"] = (string)IndictmentXML.Attribute("indictmentType");
XElement RepairActionXML = TestXML.Descendants(ns1 + "RepairActionXML").FirstOrDefault();
newRow["repairOperator"] = (string)RepairActionXML.Attribute("repairOperator");
newRow["repairTime"] = (DateTime)RepairActionXML.Attribute("repairTime");
newRow["repairActionType"] = (string)RepairActionXML.Attribute("repairActionType");
newRow["comment"] = (string)RepairActionXML.Attribute("comment");
newRow["repairStatus"] = (string)RepairActionXML.Attribute("repairStatus");
XElement ComponentXML = TestXML.Descendants(ns1 + "ComponentXML").FirstOrDefault();
newRow["packageId"] = (string)ComponentXML.Attribute("packageId");
newRow["partId"] = (string)ComponentXML.Attribute("partId");
newRow["designator"] = (string)ComponentXML.Attribute("designator");
}
}
dataGridView1.DataSource = dt;
}
}
}

Reading XML with different names to Combobox C#

looks like a very simple task by i'm very new to c# and can't seem to find the right answer for this
i have the below xml structure (elements vary in quantity)
<config>
<extras>
<dir_update>C:\extension\update.exe</dir_update>
</extras>
<connection_MAIN>
<ip>LOCALHOST,1433</ip>
<bd>DATA</bd>
<user>sa</user>
<password>gzqs=</password>
</connection_MAIN>
<connection_LOBBY>
<ip>10.0.0.2,1433</ip>
<bd>DATA</bd>
<user>sa</user>
<password>I/wqqZIgzqs=</password>
<caixa>5yIz5GPu80s=</caixa>
<printer>cARrmGLQlztLiUDxIJqoPkvJabIiyI9ye4H7t+4muYk=</printer>
</connection_LOBBY>
<connection_FRONT>
<ip>10.0.0.5,1433</ip>
<bd>FIELDS</bd>
<user>sa</user>
<password>I/wqqZIgzqs=</password>
</connection_FRONT>
</config>
I'm already getting the elements that start with "connection_" in my combobox and i want the values inside the <ip>, <bd>, <user> and <password> when i select the connection on the combobox.
The problem i'm getting is that it's returning the word itself not the value inside on the code below
private void Form1_Load(object sender, EventArgs e)
{
using(DataSet ds = new DataSet())
{
ds.ReadXml(textBox1.Text);
foreach(DataTable dt in ds.Tables)
{
if (dt.ToString().Contains("conection_"))
{
comboBox1.Items.Add(dt.ToString().Replace("conection_", ""));
}
}
comboBox1.SelectedIndex = 0;
}
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
using(DataSet ds = new DataSet())
{
ds.ReadXml(textBox1.Text);
string v = comboBox1.Text.ToString();
string ip = ds.Tables[$"conection_{v}"].Columns[0].ToString();
}
}
Variable ip is getting the value "ip" and i want "LOCALHOST,1433" when i select the first option on my combobox in this example.
Also i want to search for column value by the name ("ip", "bd"), but i seem to only get results when using Columns[0], Columns[1].
I've followed some guides that i've looked around, but they seem to not work on this format of xml or i'm looking at it the wrong way.
Any help is appreciated.
There is no need to use DataSet and DataTable data types. The best API to handle XML is LINQ to XML.
Check it out below.
c#
void Main()
{
const string MAIN = "connection_MAIN";
string IP = string.Empty;
string bd = string.Empty;
string user = string.Empty;
string password = string.Empty;
XElement xml = XElement.Parse(#"<config>
<extras>
<dir_update>C:\extension\update.exe</dir_update>
</extras>
<connection_MAIN>
<ip>LOCALHOST,1433</ip>
<bd>DATA</bd>
<user>sa</user>
<password>gzqs=</password>
</connection_MAIN>
<connection_LOBBY>
<ip>10.0.0.2,1433</ip>
<bd>DATA</bd>
<user>sa</user>
<password>I/wqqZIgzqs=</password>
<caixa>5yIz5GPu80s=</caixa>
<printer>cARrmGLQlztLiUDxIJqoPkvJabIiyI9ye4H7t+4muYk=</printer>
</connection_LOBBY>
<connection_FRONT>
<ip>10.0.0.5,1433</ip>
<bd>FIELDS</bd>
<user>sa</user>
<password>I/wqqZIgzqs=</password>
</connection_FRONT>
</config>");
// get needed connection fragment
IEnumerable<XElement> fragment = xml.Descendants(MAIN);
// get all needed elements one by one
IP = fragment.Elements("ip")?.FirstOrDefault().Value;
bd = fragment.Elements("bd")?.FirstOrDefault().Value;
user = fragment.Elements("user")?.FirstOrDefault().Value;
password = fragment.Elements("password")?.FirstOrDefault().Value;
}
Using Xml Linq I put results in to a datatable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("name", typeof(string));
dt.Columns.Add("ip", typeof(string));
dt.Columns.Add("bd", typeof(string));
dt.Columns.Add("user", typeof(string));
dt.Columns.Add("password", typeof(string));
XDocument doc = XDocument.Load(FILENAME);
foreach(XElement connection in doc.Descendants().Where(x => x.Name.LocalName.StartsWith("connection_")))
{
dt.Rows.Add(new object[] {
((string)connection.Name.LocalName).Substring(((string)connection.Name.LocalName).IndexOf("_") + 1),
(string)connection.Element("ip"),
(string)connection.Element("bd"),
(string)connection.Element("user"),
(string)connection.Element("password")
});
}
Dictionary<string, DataRow> dict = dt.AsEnumerable()
.GroupBy(x => x.Field<string>("name"), y => y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
string ip = dict["LOBBY"].Field<string>("ip");
}
}
}

XML whit multi node to datatable in c#

is there a way to map the import of an xml file into a dataset?
For example in my case I would like to import only "DatiAnagrafici" and add the "DataNascita" sub-nodes and "indirizzo" to the same table.
xml tree
Using Xml Linq the code would look something like this :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("Giorno", typeof(int));
dt.Columns.Add("Mese", typeof(int));
dt.Columns.Add("Anno", typeof(int));
dt.Columns.Add("Via", typeof(string));
dt.Columns.Add("Comune", typeof(string));
dt.Columns.Add("Provincia", typeof(string));
dt.Columns.Add("Cap", typeof(int));
XDocument doc = XDocument.Load(FILENAME);
List<XElement> datiAnagraficis = doc.Descendants("DatiAnagrafici").ToList();
foreach(XElement datiAnagrafici in datiAnagraficis)
{
int giorno = (int)datiAnagrafici.Descendants("Giorno").FirstOrDefault();
int mese = (int)datiAnagrafici.Descendants("Mese").FirstOrDefault();
int anno = (int)datiAnagrafici.Descendants("Anno").FirstOrDefault();
string via = (string)datiAnagrafici.Descendants("Via").FirstOrDefault();
string comune = (string)datiAnagrafici.Descendants("Comune").FirstOrDefault();
string provincia = (string)datiAnagrafici.Descendants("Provincia").FirstOrDefault();
int cap = (int)datiAnagrafici.Descendants("Cap").FirstOrDefault();
dt.Rows.Add(new object[] { giorno, mese, anno, via, comune, provincia, cap });
}
}
}
}

XML to DataTable (list item)

Here is my schema of xml.
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfResultstring xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Resultstring>
<Key>Blablabla : </Key>
<Values>
<string>79,0441326460292</string>
<string>76,0959542079328</string>
<string>74,3061819154758</string>
<string>78,687039788779</string>
</Values>
<Type>list</Type>
</Resultstring>
<Resultstring>
<Key>Blablabla : </Key>
<Values>
<string>87,7110395931923</string>
</Values>
<Type>double</Type>
</Resultstring>
</ArrayOfResultstring>
I need read this XML file and fill the datatable.
I'm trying with DataSet.
DataSet ds = new DataSet();
ds.ReadXml(path);
DataTable dt = ds.Tables[0];
And my output datatable is like.
I need to show my items on table. Is there any way to read properly ?
Try following xml linq which creates a separate row for each string :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Data;
namespace ConsoleApplication51
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("KEY", typeof(string));
dt.Columns.Add("RESULTING_ID", typeof(string));
dt.Columns.Add("TYPE", typeof(string));
XDocument doc = XDocument.Load(FILENAME);
XElement root = doc.Root;
XNamespace ns = root.GetDefaultNamespace();
foreach (XElement resultingString in doc.Descendants(ns + "Resultstring"))
{
string key = (string)resultingString.Element("Key");
string type = (string)resultingString.Element("Type");
string ids = string.Join(";", resultingString.Descendants("string").Select(x => (string)x));
dt.Rows.Add(new object[] { key, ids, type });
}
}
}
}
Code to put each string in a separate column
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Data;
namespace ConsoleApplication51
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement root = doc.Root;
XNamespace ns = root.GetDefaultNamespace();
int maxString = doc.Descendants(ns + "Resultstring").Select(x => x.Descendants("string").Count()).Max();
DataTable dt = new DataTable();
dt.Columns.Add("KEY", typeof(string));
dt.Columns.Add("TYPE", typeof(string));
for (int i = 0; i < maxString; i++)
{
dt.Columns.Add("RESULTING_ID_" + (i + 1).ToString(), typeof(string));
}
foreach (XElement resultingString in doc.Descendants(ns + "Resultstring"))
{
string key = (string)resultingString.Element("Key");
string type = (string)resultingString.Element("Type");
List<string> row = resultingString.Descendants("string").Select(x => (string)x).ToList();
row.Insert(0, key);
row.Insert(1, type);
dt.Rows.Add(row.ToArray());
}
}
}
}
With Cinchoo ETL - an open source library, you can easily convert Xml file to DataTable with few lines of code.
For your sample xml file, you can extract the data into datatable as below
using (var p = new ChoXmlReader(** YOUR XML FILE **)
.WithField("Key")
.WithField("Value", xPath: "/Values/string")
)
{
var dt = p.SelectMany(r => ((Array)r.Value).OfType<string>().Select(r1 => new { Key = r.Key, Value = r1})).AsDataTable();
}
Output:
Hope it helps.
your Resultstring xml node is repeating. Below code is working for me
<Resultstring>
<Key>Blablabla : </Key>
<Values>
<string>79,0441326460292</string>
<string>76,0959542079328</string>
<string>74,3061819154758</string>
<string>78,687039788779</string>
</Values>
<Type>list</Type>
<Key>Blablabla : </Key>
<Values>
<string>87,7110395931923</string>
</Values>
<Type>double</Type>
</Resultstring>
Dataset code
DataSet ds = new DataSet();
ds.ReadXml(path);
DataTable dtKey = ds.Tables[0];
DataTable dtValues = ds.Tables[1];
DataTable dtstring = ds.Tables[2];
DataTable dtType = ds.Tables[3];

c# bind DataGridView to IEnumerable<XElement> from LINQ to XML filtered results

My XML looks like this
<root>
<record>
<Object_Number> 1</Object_Number>
<Object_Level> 1</Object_Level>
<Object_Heading> Introduction</Object_Heading>
<Object_Text> </Object_Text>
<Milestones> </Milestones>
<Unique_ID> </Unique_ID>
<Field_type> Info</Field_type>
<SG_attribute> </SG_attribute>
<Object_Identifier>1</Object_Identifier>
<Object_URL>doors://D1DDBAPP04:36677/?version=2&prodID=0&view=0000001a&urn=urn:telelogic::1-432aa0956f684cff-O-1-00028f60</Object_URL>
</record>
...
records...
...
</root>
Is it possible bind a IEnumerable result to a DatgridView and automatic detect columns?
Initially, I've done this
ds = new DataSet();
ds.ReadXml(myXml);
Then, convert to a DataTable
dt = ds.Tables["record"]
And this can directly populate DGV
dgvDoors.DataSource = dt;
But now, I realize that it's more easily to manipulate data directly in XML (with LINQ) and need somehow to display that (filtered) results in DataGridView
IEnumerable<XElement> elements = xdoc.Element("root").Elements("record");
Now is it possible to display 'elements' to DataGridView and detect columns such in original XML?
Thank you,
PS.
var bs = new BindingSource { DataSource = elements};
dgvDoors.DataSource = bs;
This is not working correctly since instead of records, DGV will display some other columns such as
FirstAttribute
HasAttributes
HasElements
...
To make it working properly I would recommend converting your xml data to strongly typed View Models.
public class RecordViewModel
{
public string Number { get; set; }
public string Level { get; set; }
public string Heading { get; set; }
public string Milestones { get; set; }
}
Below implementation, please let know if it works as you expect:
var elements = xdoc.Element("root").Elements("record")
.Select(e => new RecordViewModel
{
Number = e.Element("Object_Number").Value,
Level = e.Element("Object_Level").Value,
Heading = e.Element("Object_Heading").Value,
Milestones = e.Element("Milestones").Value,
});
var bs = new BindingSource
{
DataSource = elements
};
dgvDoors.DataSource = bs;
The conversion between Xml Data and ViewModels above is not checking for nulls, so you can move the implementation to some mapper, where the logic of converting Xml data to ViewModel would be more complex.
Try following which matches your request
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication49
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
string[] columnNames = doc.Descendants("record").FirstOrDefault().Elements().Select(x => x.Name.LocalName).ToArray();
DataTable dt = new DataTable();
foreach (string col in columnNames)
{
dt.Columns.Add(col, typeof(string));
}
foreach (XElement record in doc.Descendants("record"))
{
DataRow newRow = dt.Rows.Add();
foreach (string columnName in columnNames)
{
newRow[columnName] = (string)record.Element(columnName);
}
}
}
}
}

Categories

Resources