Get list of row from a DataSet - c#

I have this dataset like this:
How can I get the string "TITLE" and "SUMMARY"?
I have this code:
string path = #"C:\Users\Pichau\Downloads\teste\data.xml";
XmlDocument x = new XmlDocument();
x.Load(path);
StringReader stream = new StringReader(x.InnerXml);
DataSet ds = new DataSet();
ds.ReadXml(stream);
foreach (var i in ds.Tables["col"].Columns)
{
Console.WriteLine(i.ToString());
}
Console.ReadLine();
But with this code I get the following output:
name
type
col_Text
row_Id
I want to access the value of "TITLE" in the "name" column

You will need to find the DataRow that corresponds to your TITLE and SUMMARY rows, and then access the values of the appropriate columns.
Try this:
foreach (DataRow row in ds.Tables["col"].Rows) {
if (row["name"] == "TITLE") {
Console.WriteLine(row["col_Text"]);
}
}

Related

Why do I get System.Data.DataRow? instead of datatable (I've retrieved a table from outlook as html body then I've parse it to a data table)

I've retrieved a table from outlook as html body then I've parse it to a datatable but when I run the code, all I get is System.Data.DataRow
static void Main(string[] args)
{
var mails = OutlookEmails.ReadMailItems();
foreach (var mail in mails)
{
StringBuilder builder = new StringBuilder();
builder.Append(mail.EmailBody.ToString());
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(builder.ToString());
var nodes = doc.DocumentNode.SelectNodes("//table//tr");
DataTable dataTable = new DataTable();
var headers = nodes[0]
.Elements("th")
.Select(th => th.InnerText.Trim());
foreach (var header in headers)
{
dataTable.Columns.Add(header);
}
var rows = nodes.Skip(1).Select(tr => tr
.Elements("td")
.Select(td => td.InnerText.Trim())
.ToArray());
foreach (var row in rows)
{
dataTable.Rows.Add(row);
}
Console.WriteLine(dataTable.Rows);
Console.ReadLine();
}
}
Because you are just printing out the type of the object.
What else did you expect?
If you want to print out every column for every row in your dataTable, you must specify it.
Try this:
foreach (DataRow row in dataTable.Rows)
{
Console.WriteLine();
foreach (DataColumn col in dataTable.Columns)
{
Console.Write(row[col] + " ");
}
}
For further information: MS DataTable Docs

Fill a datagridview with specific XML node from several XML files

I have to fill a datagridview with 3 specifics XML nodes data from several XML files.
Here it´s an example:
<?xml version='1.0' encoding='iso-8859-1'?>
<retorno>
<mensagem>
<codigo>00001 - Sucesso</codigo>
</mensagem>
<alerta>
</alerta>
<numero_nfse>641</numero_nfse>
<serie_nfse>1</serie_nfse>
<data_nfse>08/09/2020</data_nfse>
<hora_nfse>12:16:10</hora_nfse>
<arquivo_gerador_nfse>688569.xml</arquivo_gerador_nfse>
<cod_verificador_autenticidade>03379569</cod_verificador_autenticidade>
</retorno>
I need these get 3 tags - <numero_nfse>, <data_nfse>, <cod_verificador_autenticidade> - and load them into a datagridview.
However, there are more XML files, with the same tags and I would to load all of them at the same time into a datagridview.
I wrote the code bellow and as you can see, it´s not working.
string[] arquivos = Directory.GetFiles(#"D:\Documentos\retorno");
DataSet retorno = new DataSet();
for (int j = 0; j < arquivos.Length; j++)
{
FileInfo Xmls = new FileInfo(arquivos[j]);
string caminhoXmls = Convert.ToString(Xmls);
XmlDocument retornoXml = new XmlDocument();
retornoXml.Load(caminhoXmls);
XmlNodeList retornoTags = retornoXml.GetElementsByTagName("retorno");
foreach (XmlNode xn in retornoTags)
{
string XmlNumeroNfse = xn["numero_nfse"].InnerText;
string XmlDataNfse = xn["data_nfse"].InnerText;
string XmlHoraNfse = xn["hora_nfse"].InnerText;
string XmlCodigo = xn["cod_verificador_autenticidade"].InnerText;
}
retorno.ReadXml(caminhoXmls);
dgvDadosNota.DataSource = retorno.Tables[j];
}
To clarify: I want one column for each tag. So my datagridview would be with 3 columns and as many rows as there are files in the directory. There´s only one <retorno> in each XML file.
Can anyone help me?
You are loading your multiple XML files into a DataSet with one DataTable for each file, but as explained in How to bind Dataset to DataGridView in windows application you can only bind a single DataTable to a DataGridView.
Since you have only one <retorno> node in each file, it would make sense to load the files into a DataTable with 3 columns - one each for <numero_nfse>, <data_nfse>, and <cod_verificador_autenticidade> - and one row for each file.
The following code does this:
static DataTable CreateDataTableFromRetornoXML(IEnumerable<string> fileNames)
{
var columnNames = new []
{
"numero_nfse",
"data_nfse",
"cod_verificador_autenticidade",
};
var rootName = "retorno";
var table = new DataTable();
foreach (var name in columnNames)
table.Columns.Add(name, typeof(string));
foreach (var fileName in fileNames)
{
var row = table.NewRow();
var root = XElement.Load(fileName);
var retorno = root.DescendantsAndSelf(rootName).Single(); // There should be only one.
foreach (DataColumn column in table.Columns)
{
row[column] = retorno.Element(column.ColumnName)?.Value;
}
table.Rows.Add(row);
}
return table;
}
Note I have switch to the LINQ to XML API which is generally easier to work with than the old XmlDocument API.
Demo fiddle here.

C# Reading CSV to DataTable and Invoke Rows/Columns

i am currently working on a small Project and i got stuck with a Problem i currently can not manage to solve...
I have multiple ".CSV" Files i want to read, they all have the same Data just with different Values.
Header1;Value1;Info1
Header2;Value2;Info2
Header3;Value3;Info3
While reading the first File i Need to Create the Headers. The Problem is they are not splited in Columns but in rows (as you can see above Header1-Header3).
Then it Needs to read the Value 1 - Value 3 (they are listed in the 2nd Column) and on top of that i Need to create another Header -> Header4 with the data of "Info2" which is always placed in Column 3 and Row 2 (the other values of Column 3 i can ignore).
So the Outcome after the first File should look like this:
Header1;Header2;Header3;Header4;
Value1;Value2;Value3;Info2;
And after multiple files it sohuld be like this:
Header1;Header2;Header3;Header4;
Value1;Value2;Value3;Value4;
Value1b;Value2b;Value3b;Value4b;
Value1c;Value2c;Value3c;Value4c;
I tried it with OleDB but i get the Error "missing ISAM" which i cant mange to fix. The Code i Used is the following:
public DataTable ReadCsv(string fileName)
{
DataTable dt = new DataTable("Data");
/* using (OleDbConnection cn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\"" +
Path.GetDirectoryName(fileName) + "\";Extendet Properties ='text;HDR=yes;FMT=Delimited(,)';"))
*/
using (OleDbConnection cn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" +
Path.GetDirectoryName(fileName) + ";Extendet Properties ='text;HDR=yes;FMT=Delimited(,)';"))
{
using(OleDbCommand cmd = new OleDbCommand(string.Format("select *from [{0}]", new FileInfo(fileName).Name,cn)))
{
cn.Open();
using(OleDbDataAdapter adapter = new OleDbDataAdapter(cmd))
{
adapter.Fill(dt);
}
}
}
return dt;
}
Another attempt i did was using StreamReader. But the Headers are in the wrong place and i dont know how to Change this + do this for every file. the Code i tried is the following:
public static DataTable ReadCsvFilee(string path)
{
DataTable oDataTable = new DataTable();
var fileNames = Directory.GetFiles(path);
foreach (var fileName in fileNames)
{
//initialising a StreamReader type variable and will pass the file location
StreamReader oStreamReader = new StreamReader(fileName);
// CONTROLS WHETHER WE SKIP A ROW OR NOT
int RowCount = 0;
// CONTROLS WHETHER WE CREATE COLUMNS OR NOT
bool hasColumns = false;
string[] ColumnNames = null;
string[] oStreamDataValues = null;
//using while loop read the stream data till end
while (!oStreamReader.EndOfStream)
{
String oStreamRowData = oStreamReader.ReadLine().Trim();
if (oStreamRowData.Length > 0)
{
oStreamDataValues = oStreamRowData.Split(';');
//Bcoz the first row contains column names, we will poluate
//the column name by
//reading the first row and RowCount-0 will be true only once
// CHANGE TO CHECK FOR COLUMNS CREATED
if (!hasColumns)
{
ColumnNames = oStreamRowData.Split(';');
//using foreach looping through all the column names
foreach (string csvcolumn in ColumnNames)
{
DataColumn oDataColumn = new DataColumn(csvcolumn.ToUpper(), typeof(string));
//setting the default value of empty.string to newly created column
oDataColumn.DefaultValue = string.Empty;
//adding the newly created column to the table
oDataTable.Columns.Add(oDataColumn);
}
// SET COLUMNS CREATED
hasColumns = true;
// SET RowCount TO 0 SO WE KNOW TO SKIP COLUMNS LINE
RowCount = 0;
}
else
{
// IF RowCount IS 0 THEN SKIP COLUMN LINE
if (RowCount++ == 0) continue;
//creates a new DataRow with the same schema as of the oDataTable
DataRow oDataRow = oDataTable.NewRow();
//using foreach looping through all the column names
for (int i = 0; i < ColumnNames.Length; i++)
{
oDataRow[ColumnNames[i]] = oStreamDataValues[i] == null ? string.Empty : oStreamDataValues[i].ToString();
}
//adding the newly created row with data to the oDataTable
oDataTable.Rows.Add(oDataRow);
}
}
}
//close the oStreamReader object
oStreamReader.Close();
//release all the resources used by the oStreamReader object
oStreamReader.Dispose();
}
return oDataTable;
}
I am thankful for everyone who is willing to help. And Thanks for reading this far!
Sincerely yours
If I understood you right, there is a strict parsing there like this:
string OpenAndParse(string filename, bool firstFile=false)
{
var lines = File.ReadAllLines(filename);
var parsed = lines.Select(l => l.Split(';')).ToArray();
var header = $"{parsed[0][0]};{parsed[1][0]};{parsed[2][0]};{parsed[1][0]}\n";
var data = $"{parsed[0][1]};{parsed[1][1]};{parsed[2][1]};{parsed[1][2]}\n";
return firstFile
? $"{header}{data}"
: $"{data}";
}
Where it would return - if first file:
Header1;Header2;Header3;Header2
Value1;Value2;Value3;Value4
if not first file:
Value1;Value2;Value3;Value4
If I am correct, rest is about running this against a list file of files and joining the results in an output file.
EDIT: Against a directory:
void ProcessFiles(string folderName, string outputFileName)
{
bool firstFile = true;
foreach (var f in Directory.GetFiles(folderName))
{
File.AppendAllText(outputFileName, OpenAndParse(f, firstFile));
firstFile = false;
}
}
Note: I missed you want a DataTable and not an output file. Then you could simply create a list and put the results into that list making the list the datasource for your datatable (then why would you use semicolons in there? Probably all you need is to simply attach the array values to a list).
(Adding as another answer just to make it uncluttered)
void ProcessMyFiles(string folderName)
{
List<MyData> d = new List<MyData>();
var files = Directory.GetFiles(folderName);
foreach (var file in files)
{
OpenAndParse(file, d);
}
string[] headers = GetHeaders(files[0]);
DataGridView dgv = new DataGridView {Dock=DockStyle.Fill};
dgv.DataSource = d;
dgv.ColumnAdded += (sender, e) => {e.Column.HeaderText = headers[e.Column.Index];};
Form f = new Form();
f.Controls.Add(dgv);
f.Show();
}
string[] GetHeaders(string filename)
{
var lines = File.ReadAllLines(filename);
var parsed = lines.Select(l => l.Split(';')).ToArray();
return new string[] { parsed[0][0], parsed[1][0], parsed[2][0], parsed[1][0] };
}
void OpenAndParse(string filename, List<MyData> d)
{
var lines = File.ReadAllLines(filename);
var parsed = lines.Select(l => l.Split(';')).ToArray();
var data = new MyData
{
Col1 = parsed[0][1],
Col2 = parsed[1][1],
Col3 = parsed[2][1],
Col4 = parsed[1][2]
};
d.Add(data);
}
public class MyData
{
public string Col1 { get; set; }
public string Col2 { get; set; }
public string Col3 { get; set; }
public string Col4 { get; set; }
}
I don't know if this is the best way to do this. But what i would have done in your case, is to rewrite the CSV's the conventionnal way while reading all the files, then create a stream containing the new CSV created.
It would look like something like this :
var csv = new StringBuilder();
csv.AppendLine("Header1;Header2;Header3;Header4");
foreach (var item in file)
{
var newLine = string.Format("{0},{1},{2},{3}", item.value1, item.value2, item.value3, item.value4);
csv.AppendLine(newLine);
}
//Create Stream
MemoryStream stream = new MemoryStream();
StreamReader reader = new StreamReader(stream);
//Fill your data table here with your values
Hope this will help.

How to convert XElement object into a dataset or datatable?

I'm accessing a SharePoint(2007) list through a service reference of lists.asmx created in my console application. Console application is created in VS2012 and .Net 4.5 framework.
ListsSoapClient proxy1 = new ListsSoapClient();
proxy1.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
proxy1.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
string listName = "List_For_Test";
DataSet ds1 = new DataSet();
XElement ndQuery = new XElement("Query", "");
XElement ndViewFields = new XElement("ViewFields", "");
XElement ndQueryOptions = new XElement("QueryOptions", "");
XElement items = proxy1.GetListItems(listName, null, ndQuery, ndViewFields, null, ndQueryOptions, null);
ds1 = XElementToDataSet(items);
I need to convert the XML returned in items XElement to dataset/datatable and pass it to a stored procedure written in SQL Server 2008 R2.
I tried using following code but it gave me error
XElement setup = (from p in x.Descendants() select p).First();
foreach (XElement xe in setup.Descendants()) // build your DataTable
dt.Columns.Add(new DataColumn(xe.Name.ToString(), typeof(string)));
// on second iteration gave error that "'{#RowsetSchema}row'" column already existing.
This is the XML stream returned from GetListItems() webservice method call
<listitems xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"
xmlns="http://schemas.microsoft.com/sharepoint/soap/"> <rs:data
ItemCount="2"> <z:row
ows_ContentTypeId="0x01006B57C3DFF39626458A729755ABF3A370"
ows_Title="Item#1" ows_ListID="1.00000000000000"
ows_Loan_x0020_Number="1234.00000000000" ows_ID="2"
ows_ContentType="Item" ows_Modified="2014-04-01 10:06:38"
ows_Created="2014-04-01 10:06:38" ows_Author="7017;#, Khushi"
ows_Editor="7017;#, Khushi" ows_owshiddenversion="1"
ows_WorkflowVersion="1" ows__UIVersion="512"
ows__UIVersionString="1.0" ows_Attachments="0"
ows__ModerationStatus="0" ows_LinkTitleNoMenu="Item#1"
ows_LinkTitle="Item#1" ows_SelectTitle="2"
ows_Order="200.000000000000"
ows_GUID="{2832ED2B-A45D-4950-8E0E-EEB3E31199AF}" ows_FileRef="2;#
List_For_Test/2_.000" ows_FileDirRef="2;#/List_For_Test"
ows_Last_x0020_Modified="2;#2014-04-01 10:06:38"
ows_Created_x0020_Date="2;#2014-04-01 10:06:38" ows_FSObjType="2;#0"
ows_PermMask="0x7fffffffffffffff" ows_FileLeafRef="2;#2_.000"
ows_UniqueId="2;#{F3336392-74F7-45C2-A175-EF36DA219812}"
ows_ProgId="2;#"
ows_ScopeId="2;#{E9E1B331-7993-4586-93DC-3690EBEBAD9E}"
ows__EditMenuTableStart="2_.000" ows__EditMenuTableEnd="2"
ows_LinkFilenameNoMenu="2_.000" ows_LinkFilename="2_.000"
ows_ServerUrl="/ List_For_Test/2_.000"
ows_EncodedAbsUrl="Lists/List_For_Test/2_.000" ows_BaseName="2_"
ows_MetaInfo="2;#" ows__Level="1" ows__IsCurrentVersion="1" />
<z:row ows_ContentTypeId="0x01006B57C3DFF39626458A729755ABF3A370"
ows_Title="Item#2" ows_ListID="2.00000000000000"
ows_Loan_x0020_Number="5678.00000000000" ows_ID="3"
ows_ContentType="Item" ows_Modified="2014-04-01 10:06:53"
ows_Created="2014-04-01 10:06:53" ows_Author="7017;#Khushi"
ows_Editor="7017;#, Khushi" ows_owshiddenversion="1"
ows_WorkflowVersion="1" ows__UIVersion="512"
ows__UIVersionString="1.0" ows_Attachments="0"
ows__ModerationStatus="0" ows_LinkTitleNoMenu="Item#2"
ows_LinkTitle="Item#2" ows_SelectTitle="3"
ows_Order="300.000000000000"
ows_GUID="{8A6C6A66-A795-4054-B793-789B739EA881}" ows_FileRef="3;#
/List_For_Test/3_.000" ows_FileDirRef="3;# /List_For_Test"
ows_Last_x0020_Modified="3;#2014-04-01 10:06:53"
ows_Created_x0020_Date="3;#2014-04-01 10:06:53" ows_FSObjType="3;#0"
ows_PermMask="0x7fffffffffffffff" ows_FileLeafRef="3;#3_.000"
ows_UniqueId="3;#{434E5737-5591-4A02-91E5-B2C7A2EFF2B3}"
ows_ProgId="3;#"
ows_ScopeId="3;#{E9E1B331-7993-4586-93DC-3690EBEBAD9E}"
ows__EditMenuTableStart="3_.000" ows__EditMenuTableEnd="3"
ows_LinkFilenameNoMenu="3_.000" ows_LinkFilename="3_.000"
ows_ServerUrl="/List_For_Test/3_.000"
ows_EncodedAbsUrl="Lists/List_For_Test/3_.000" ows_BaseName="3_"
ows_MetaInfo="3;#" ows__Level="1" ows__IsCurrentVersion="1" />
</rs:data> </listitems>
Please check it here...
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));
}
}
Use it like this:
protected void Page_Load(object sender, EventArgs e) {
string xmlFile = Server.MapPath("~/Data.xml");
XDocument document = XDocument.Load(xmlFile);
var booksQuery = from b in document.Elements("NewDataSet").Elements("Table")
select b;
DataTable table = booksQuery.ToDataTable();
GridView1.DataSource = table;
GridView1.DataBind();
}
khushi,check this may be useful to you....
public static DataSet XElementToDataSet(XElement xeRecordsList)
{
DataTable dtRecordsList = new DataTable();
XElement setup = (from p in xeRecordsList.Descendants() select p).First();
// builds DataTable
foreach (XElement xe in setup.Descendants())
dtRecordsList.Columns.Add(new DataColumn(xe.Name.ToString(), typeof(string)));
// add columns to your dt
var all = from p in xeRecordsList.Descendants(setup.Name.ToString()) select p;
foreach (XElement xe in all)
{
DataRow dr = dtRecordsList.NewRow();
//adding the values
foreach (XElement xe2 in xe.Descendants())
{
bool boolColExists = false;
//Check for column exists in datatable
foreach (DataColumn col in dtRecordsList.Columns)
{
if (col.ColumnName == xe2.Name.ToString())
{
boolColExists = true;
break;
}
}
if (boolColExists)
dr[xe2.Name.ToString()] = xe2.Value;
}
dtRecordsList.Rows.Add(dr);
}
DataSet dstRecordsList = new DataSet("RECORDLIST");
dstRecordsList.Tables.Add(dtRecordsList);
dstRecordsList.Tables[0].TableName = "RECORD";
return dstRecordsList;
}
some references:
http://www.dotnetpickles.com/2014/02/aspnet-convert-xml-to-datatable-in-cnet.html

Loading XML String into datatable

string parseData= "<TEST xmlns:dt=\"urn:schemas-microsoft-com:datatypes\"><A dt:dt=\"string\">10</A><B dt:dt=\"string\">20</B></TEST>";
DataSet ds = new DataSet("Whatev");
TextReader txtReader = new StringReader(parseData);
XmlReader reader = new XmlTextReader(txtReader);
ds.ReadXml(reader);
DataTable ad = new DataTable("newT");
ad.ReadXml(reader);
For this I am getting empty table in ad, and three tables in ds.
What I am expecting is,
one table with two columns A and B, and one row with values 10 and 20.
What am I doing wrong?
You're simply not using it correctly. There's a number of problems:
You are reading from the same stream twice. In the first pass, the stream pointer is at the end of the stream. You attempt to read from it again when it's already at the end so nothing else is read. Either read into your data set or into your data table, not both. Or, at least seek back to the beginning of the stream if you really want to.
Your XML is not in the correct format. It has to be in the format:
<SomeRoot>
<TableName>
<ColumnName>ColumnValue</ColumnName>
</TableName>
<TableName>
<ColumnName>AnotherColumnValue</ColumnName>
</TableName>
</SomeRoot>
You won't be able to use that method with any arbitrary XML.
Your tables do not have a schema set. You need to either read in a schema or set it up beforehand.
var table = new DataTable("TEST");
table.Columns.Add("A", typeof(string));
table.Columns.Add("B", typeof(string));
table.ReadXml(xmlReader);
Try this instead:
var xmlStr = #"<Root>
<TEST>
<A>10</A>
<B>20</B>
</TEST>
</Root>";
var table = new DataTable("TEST");
table.Columns.Add("A", typeof(string));
table.Columns.Add("B", typeof(string));
table.ReadXml(new StringReader(xmlStr));
If you decide to parse that XML yourself, LINQ can help you out here.
public static DataTable AsDataTable(XElement root, string tableName, IDictionary<string, Type> typeMapping)
{
var table = new DataTable(tableName);
// set up the schema based on the first row
XNamespace dt = "urn:schemas-microsoft-com:datatypes";
var columns =
(from e in root.Element(tableName).Elements()
let typeName = (string)e.Element(dt + "dt")
let type = typeMapping.ContainsKey(typeName ?? "") ? typeMapping[typeName] : typeof(string)
select new DataColumn(e.Name.LocalName, type)).ToArray();
table.Columns.AddRange(columns);
// add the rows
foreach (var rowElement in root.Elements(tableName))
{
var row = table.NewRow();
foreach (var column in columns)
{
var colElement = rowElement.Element(column.ColumnName);
if (colElement != null)
row[column.ColumnName] = Convert.ChangeType((string)colElement, column.DataType);
}
table.Rows.Add(row);
}
return table;
}
Then to use it:
var xmlStr = #"<Root>
<TEST xmlns:dt=""urn:schemas-microsoft-com:datatypes"">
<A dt:dt=""string"">10</A>
<B dt:dt=""string"">20</B>
</TEST>
</Root>";
var root = XElement.Parse(xmlStr);
var mapping = new Dictionary<string, Type>
{
{ "string", typeof(string) },
};
var table = AsDataTable(root, "TEST", mapping);
There probably is a better way to get the associated .NET type for a datatype but I don't know how to do that at the moment, I'll update if I find that out.

Categories

Resources