I am trying to get a xml file into a dataset and am using the following code:
DataSet ds = new DataSet(\"TestDataSet\");
ds.ReadXml(FileName);
In order for the ReadXml to function properly in this case, I think you need to specify a Schema in your XML file. Otherwise, the reader will not know what to do with the datatypes.
DataSet ds = new DataSet("Whatev");
DataTable catalog = ds.Tables.Add("Catalog");
DataColumn recCol = catalog.Columns.Add("Rec");
DataTable rec = ds.Tables.Add("Rec");
rec.Columns.AddRange(new DataColumn[] {
new DataColumn("ITEM", typeof(string)),
new DataColumn("QTY", typeof(string)),
new DataColumn("SUB", typeof(string)),
new DataColumn("CATALOG", typeof(string))
});
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
foreach (XmlNode recNode in doc.GetElementsByTagName("Rec"))
{
DataRow row = rec.Rows.Add(
recNode["ITEM"].InnerText,
recNode["QTY"].InnerText,
recNode["SUB"].InnerText,
recNode["CATALOG"].InnerText);
}
There ya go. Now there will be two tables, Catalog and Rec. I suspect you only want Rec though, because Catalog is useless. So just remove the catalog datatable code if that's the case, or add an id attribute each catalog row and link it to rec:
DataSet ds = new DataSet("Whatev");
DataTable catalog = ds.Tables.Add("Catalog");
DataColumn idCol = catalog.Columns.Add("Id");
DataTable rec = ds.Tables.Add("Rec");
rec.Columns.AddRange(new DataColumn[] {
new DataColumn("ITEM", typeof(string)),
new DataColumn("QTY", typeof(string)),
new DataColumn("SUB", typeof(string)),
new DataColumn("CATALOG", typeof(string))
});
catalog.ChildRelations.Add("catToRecRelation", idCol, rec.Columns["CATALOG"]);
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
foreach (XmlNode recNode in doc.GetElementsByTagName("Rec"))
{
// Create id in parent Catalog node, based on CATALOG value
catalog.Rows.Add(recNode["CATALOG"].InnerText);
DataRow row = rec.Rows.Add(
recNode["ITEM"].InnerText,
recNode["QTY"].InnerText,
recNode["SUB"].InnerText,
recNode["CATALOG"].InnerText);
}
var childRows = catalog.Rows[0].GetChildRows("catToRecRelation");
I use this code...
To generate the XML:
// you need to create a datatable, from a sql query, linq, your choice...
DataTable _dt = new DataTable();
// write the datatable with schema
dt.WriteXml("datatable.xml", XmlWriteMode.WriteSchema);
To read the XML:
DataTable dt = new DataTable ();
dt.Clear();
dt.ReadXml("datatable.xml", XmlReadMode.ReadSchema);
The result datatable can be complemented with these functions, this way you can convert it to IList
, you need to create an object with the same pattern of columns, it's really more practical this way:
public IList<T> toList<T>(DataTable table)
{
List<T> list = new List<T>();
T item;
Type listItemType = typeof(T);
for (int i = 0; i < table.Rows.Count; i++)
{
item = (T)Activator.CreateInstance(listItemType);
mapRow(item, table.Rows[i], listItemType);
list.Add(item);
}
return list;
}
private void mapRow(object vOb, System.Data.DataRow dr, Type type)
{
try
{
for (int col = 0; col < dr.Table.Columns.Count; col++)
{
var columnName = dr.Table.Columns[col].ColumnName;
var prop = type.GetProperty(columnName.ToUpper());
object data = dr[col];
prop.SetValue(vOb, data, null);
}
}
catch (Exception ex)
{
throw ex;
}
}
Actually, I'm working on an app that use XML generated from SQL tables. Basically, use the functions above, I create other small app (to support the first one) that scan the package of XML (XML per table) and create the layers business, access, object and a flow control for proper writing & reading of the XML.
As soon as you define your XML namespace used in the XML elements, you can easily import this - no problem.
You need to have your XML look something like this:
<Catalog xmlns:dt="some-xml-namespace-here">
<Rec>
<ITEM dt:dt="string"/>
<QTY dt:dt="string">1</QTY>
<SUB dt:dt="string">1</SUB>
<CATALOG dt:dt="string">ABC123</CATALOG>
</Rec>
.....
</Catalog>
After I do this, your two lines of code work like a charm and the data gets imported, no problem (into 5 tables inside the DataSet).
Marc
This will make it parseable. The dt namespace usually refers to xmlns:dt="urn:schemas-microsoft-com:datatypes". Something or someone messed up your XML, but if you must be able to import it, you can just modify the xmlns attributes on the catalog element as shown:
string xml = @"<Catalog xmlns=""dt"" xmlns:dt=""dt"">
<Rec>
<ITEM dt:dt=""string""/>
<QTY dt:dt=""string"">1</QTY>
<SUB dt:dt=""string"">1</SUB>
<CATALOG dt:dt=""string"">ABC123</CATALOG>
</Rec>
<Rec>
<ITEM dt:dt=""string""/>
<QTY dt:dt=""string"">1</QTY>
<SUB dt:dt=""string"">1</SUB>
<CATALOG dt:dt=""string"">ABC124</CATALOG>
</Rec>
<Rec>
<ITEM dt:dt=""string""/>
<QTY dt:dt=""string"">1</QTY>
<SUB dt:dt=""string"">1</SUB>
<CATALOG dt:dt=""string"">ABC125</CATALOG>
</Rec>
</Catalog>";
DataSet ds = new DataSet("Whatev");
TextReader txtReader = new StringReader(xml);
XmlReader reader = new XmlTextReader(txtReader);
ds.ReadXml(reader);
Debug.Assert(ds.Tables.Count ==5);
Debug.Assert((string)ds.Tables[2].Rows[0][0] == "string");
Debug.Assert((string)ds.Tables[3].Rows[0][1] == "1");
Also Marc is correct, but with the definition above you can generate a matching schema:
<xs:schema xmlns:dt="dt" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="dt" xmlns:xs="http://www.w3.org/2001/XMLSchema"><xs:element name="Catalog"><xs:complexType> <xs:sequence><xs:element maxOccurs="unbounded" name="Rec"><xs:complexType><xs:sequence><xs:element name="ITEM"><xs:complexType><xs:attribute ref="dt:dt" use="required" /></xs:complexType></xs:element><xs:element name="QTY"><xs:complexType>
<xs:simpleContent><xs:extension base="xs:unsignedByte"><xs:attribute ref="dt:dt" use="required" /></xs:extension></xs:simpleContent></xs:complexType>
</xs:element><xs:element name="SUB"><xs:complexType><xs:simpleContent><xs:extension base="xs:unsignedByte"><xs:attribute ref="dt:dt" use="required" /></xs:extension></xs:simpleContent></xs:complexType></xs:element><xs:element name="CATALOG"><xs:complexType><xs:simpleContent><xs:extension base="xs:string"><xs:attribute ref="dt:dt" use="required" /></xs:extension></xs:simpleContent></xs:complexType></xs:element></xs:sequence></xs:complexType></xs:element></xs:sequence></xs:complexType></xs:element><xs:attribute name="dt" type="xs:string" /></xs:schema>
The attribute "dt" is a reference attribute. So the xml cannot be valid against any schema without the xmlns="ds" declaration as well.