i get an empty Datatable when parsing xml file with xmlReader and import it into one DataTable , its necessary for me to save it into Data table so i can import it later into sql server with sqlbulkcopy
easily (i have huge number of lines),
what i try
using (XmlReader reader = XmlReader.Create(#"C:\Users\neyma\test/W.xml"))
{
DataTable dataTable = new DataTable();
dataTable.Columns.Add("EventID");
dataTable.Columns.Add("Computer");
dataTable.Columns.Add("TargetUserName");
dataTable.Columns.Add("TargetDomainName");
DataRow myDataRow;
myDataRow = dataTable.NewRow();
while (reader.Read())
{
if (reader.IsStartElement())
{
switch (reader.Name.ToString())
{
case "EventID":
myDataRow["EventID"] = reader.ReadInnerXml();
break;
case "Computer":
myDataRow["Computer"] = reader.ReadInnerXml();
break;
case "Data":
if (reader.GetAttribute("Name") == "TargetUserName")
myDataRow["TargetUserName"] = reader.ReadInnerXml();
else if (reader.GetAttribute("Name") == "TargetDomainName")
myDataRow["TargetDomainName"] = reader.ReadInnerXml();
break;
sample from xml
<eventxml>
<Event <EventID>36</EventID><Computer>NH</Computer><EventData><Data Name="TargetUserName">TER.go</Data><Data Name="TargetDomainName">%4</Data></EventData></Event>
<Event <EventID>51</EventID><Computer>NQ-RS1-.ov</Computer><EventData><Data Name="TargetUserName">TERMSRiv</Data><Data Name="TargetDomainName">%%4</Data></EventData></Event>
<Event <EventID>536</EventID><Computer>CRS1.ov</Computer><EventData><Data Name="TargetUserName">TERRov</Data><Data Name="TargetDomainName">%%144</Data></EventData></Event>
</eventxml>
Seems like this is going to be much easier to do with XDocument and LINQ
var xDoc = XDocument.Load(path);
var table = new DataTable { Columns = {
{"EventID", typeof(string)},
{"Computer", typeof(string)},
{"TargetUserName", typeof(string)},
{"TargetDomainName", typeof(string)},
} };
foreach (var node in xDoc.Root.Elements("Event"))
{
var data = node.Element("EventData");
table.Rows.Add(
node.Element("EventID").Value,
node.Element("Computer").Value,
data.Elements().FirstOrDefault(e => e.Attribute("Name").Value == "TargetUserName").Value,
data.Elements().FirstOrDefault(e => e.Attribute("Name").Value == "TargetDomainName").Value
);
}
dotnetfiddle
Another option is to pass the whole XML into SQL and parse it using XQuery.
Related
so I am working on my project and I want to write datagridview which is from a CSV file into XML file and I have achieved that but what I want to know if there is any way to sort the order view or change the outcome of XML what I want is to sort Alphabetical order from a specific column. this is my code for the saving XML file.
if (saveFileDialogXml.ShowDialog() == DialogResult.OK)
{
//Xml Alphabetical order code goes here
DataTable dst = new DataTable();
dst = (DataTable)Datagridview1.DataSource;
dst.TableName = "Data";
dst.WriteXml(saveFileDialogXml.FileName);
}
}
but the output of this is
<?xml version="1.0" standalone="yes"?>
<Item_x0020_Code>Item Code</Item_x0020_Code>
<Item_x0020_Description>Item Description</Item_x0020_Description>
<Current_x0020_Count>Current Count</Current_x0020_Count>
<On_x0020_Order>On Order</On_x0020_Order>
as you can see it even put the Hexadecimal and it just throws everything there, so I was wondering if i can reformat it the way I want it to display like removing the x0020. So I tried using LINQ to see if there was a problem with file, but I keep getting another error which says
System.Xml.XmlException: 'The ' ' character, hexadecimal value 0x20, cannot be included in a name.'
This is the LINQ code :
var xmlFile = new XElement("root",
from line in File.ReadAllLines(#"C:\\StockFile\stocklist.csv")
.Where(n => !string.IsNullOrWhiteSpace(n))
where !line.StartsWith(",") && line.Length > 0
let parts = line.Split(',')
select new XElement("Item Code",
new XElement("Test1", parts[0]),
new XElement("Test2", parts[1])
)
);
Also, I am new to C# and my first post here so please excuse the messy writing or placements.
Try following :
DataTable dst = new DataTable();
int startColumn = 5;
for(int i = dst.Columns.Count - 1; i >= startColumn; i--)
{
dst = dst.AsEnumerable().OrderBy(x => dst.Columns[i]).CopyToDataTable();
}
Sorry for the late Reply I kinda figured it out so forgot to close or mark an answer anyway if any of you run to the same thing all I did was this
// Save file dialogue XML file.
if (saveFileDialogXml.ShowDialog() == DialogResult.OK)
{
//try block to catch exception and handle it.
try
{
//Changing Data Table name to stock.
string Stock = ((DataTable)Datagridview1.DataSource).TableName;
}
//Catching the exception and handling it.
catch (Exception)
{
string es = "Please Open The File Before Saving it";
string title = "Error";
MessageBox.Show(es, title);
}
// instatiate new DataTable.
DataTable dt = new DataTable
{
TableName = "Stock"
};
for (int i = 0; i < Datagridview1.Columns.Count; i++)
{
//if (dataGridView1.Columns[i].Visible) // Add's only Visible columns.
//{
string headerText = Datagridview1.Columns[i].HeaderText;
headerText = Regex.Replace(headerText, "[-/, ]", "_");
DataColumn column = new DataColumn(headerText);
dt.Columns.Add(column);
//}
}
foreach (DataGridViewRow DataGVRow in Datagridview1.Rows)
{
DataRow dataRow = dt.NewRow();
// Add's only the columns that I need
dataRow[0] = DataGVRow.Cells["Item Code"].Value;
dataRow[1] = DataGVRow.Cells["Item Description"].Value;
dataRow[2] = DataGVRow.Cells["Current Count"].Value;
dataRow[3] = DataGVRow.Cells["On Order"].Value;
dt.Rows.Add(dataRow); //dt.Columns.Add();
}
DataSet ds = new DataSet();
ds.Tables.Add(dt);
//Finally the save part:
XmlTextWriter xmlSave = new XmlTextWriter(saveFileDialogXml.FileName, Encoding.UTF8)
{
Formatting = Formatting.Indented
};
ds.DataSetName = "Data";
ds.WriteXml(xmlSave);
xmlSave.Close();
I'm processing different kind of Xlsx files. These files have multiples possibility of column eg 2 or 6 or even 7 Columns)
I read the Xml data inside using OpenXml and i would like to generate Json files from each worksheet.
Actually i'm able to read and to iterate through every worksheet but it seems weird when i try to convert it into Json format using Newtonsoft.Json
The Excel files is similare to this
Item 1 || Item 2 || Item 3
V1 || V2 || V3
V1 || V2 || V3
V1 || V2 || V3
But the generated JSON file is similare to this
[ [Item 1 ,Item 2 ,Item 3] [V1 ,V2 ,V3] [V1 ,V2 ,V3] [V1 ,V2 ,V3]]
And i would like to format it like this
{ {"Item 1":"V1" ,"Item 2":"V2" ,"Item 3":"V3"} {"Item 1":"V1" ,"Item 2":"V2" ,"Item 3":"V3"} {"Item 1":"V1" ,"Item 2":"V2" ,"Item 3":"V3"} }
Here is my code :
using (SpreadsheetDocument excelDocument = SpreadsheetDocument.Open(file, false))
{
var documentBody = excelDocument.WorkbookPart.Workbook;
var sheets = documentBody.Sheets.Cast<Sheet>().ToList();
sheets.ForEach(x => Console.WriteLine(String.Format("RelationshipId:{0}\n SheetName:{1}\n SheetId:{2}", x.Id.Value, x.Name.Value, x.SheetId.Value)));
SharedStringTablePart sstpart = excelDocument.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First();
SharedStringTable sst = sstpart.SharedStringTable;
Console.WriteLine("Worksheet count = {0}", documentBody.WorkbookPart.WorksheetParts.Count());
foreach (var worksheetPart in documentBody.WorkbookPart.WorksheetParts)
{
DocumentFormat.OpenXml.Spreadsheet.Worksheet sheet = worksheetPart.Worksheet;
var cells = sheet.Descendants<Cell>();
var rows = sheet.Descendants<Row>();
Console.WriteLine("Row count = {0}", rows.LongCount());
Console.WriteLine("Cell count = {0}", cells.LongCount());
var list = new List<string[]>();
foreach (Row row in rows)
{
Console.WriteLine("Row number: {0}", row.RowIndex);
list.Add(row.Elements<Cell>().Select(x => x.InnerText).ToArray());
foreach (Cell c in row.Elements<Cell>())
{
if (c.CellValue != null)
{
Console.WriteLine("Cell contents: {0}", c.CellValue.Text);
}
}
}
var i = JsonConvert.SerializeObject(list, Newtonsoft.Json.Formatting.Indented);
}
}
To convert an XML node contained in string xml into a JSON string
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);
To convert JSON text contained in string json into an XML node
XmlDocument doc = JsonConvert.DeserializeXmlNode(json);
Documentation here: Click Here for Documentation
OR Try this below Code there i have used dictionary
class Program
{
static void Main()
{
var xml =
#"<Columns>
<Column Name=""key1"" DataType=""Boolean"">True</Column>
<Column Name=""key2"" DataType=""String"">Hello World</Column>
<Column Name=""key3"" DataType=""Integer"">999</Column>
</Columns>";
var dic = XDocument
.Parse(xml)
.Descendants("Column")
.ToDictionary(
c => c.Attribute("Name").Value,
c => c.Value
);
var json = new JavaScriptSerializer().Serialize(dic);
Console.WriteLine(json);
}
}
In your case I recommend to use List of ExpandoObject instead of List of string[].
It's a dynamic object generated as a IDictionnary
var list = new List<ExpandoObject>();
var expandoObject = new ExpandoObject();
var dict = (IDictionary<string, Object>)expandoObject;
dict.Add("NewProp", "prop value");
dict.Add("SecondProp", 58);
list.add(expandoObject);
Hi i am reading the RSS feed and creating an XML using the DataTable. This is my code
try
{
DataTable tbl = new DataTable();
tbl.Columns.Add("id");
tbl.Columns.Add("product_name");
tbl.Columns.Add("description");
//Extra Nodes
tbl.Columns.Add("brand");
tbl.Columns.Add("condition");
tbl.Columns.Add("product_type");
XmlDocument doc = new XmlDocument();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(s);
XmlNodeList itemNodes = xmlDoc.SelectNodes("//rss/channel/item");
foreach (XmlNode itemNode in itemNodes)
{
DataRow row = tbl.NewRow();
XmlNode idNode = itemNode.SelectSingleNode("id");
XmlNode product_nameNode = itemNode.SelectSingleNode("product_name");
XmlNode descriptionNode = itemNode.SelectSingleNode("description");
//extra nodes
XmlNode brandNode = itemNode.SelectSingleNode("brand");
XmlNode conditionNode = itemNode.SelectSingleNode("condition");
XmlNode product_typeNode = itemNode.SelectSingleNode("product_type");
if (idNode != null && product_nameNode != null && descriptionNode != null )
{
row[0] = idNode.InnerText;
row[1] = product_nameNode.InnerText;
row[2] = descriptionNode.InnerText;
//extra nodes
if (brandNode == null)
row[3] = "";
else
row[3] = brandNode.InnerText;
if (conditionNode==null)
row[4] = "";
else
row[4] = conditionNode.InnerText;
if (product_typeNode==null)
row[5] = "";
else
row[5] = product_typeNode.InnerText;
}
tbl.Rows.Add(row);
// tbl.Rows.Add(row);
}
}
}
catch (Exception ex)
{
// Console.WriteLine(ex.Message);
// Console.Read();
}
This is working fine without any issue but i want to make my code more efficient. Is this the good way to read the Rss and add into the datatable ? I am making a SSIS project on VS 2008 so i can not use SyndicationFeed .
You can use this code below ans use as example.
using System;
using System.ServiceModel.Syndication;
using System.Xml;
namespace RSSFeed
{
public class Program
{
static void Main(string[] args)
{
// URL from the site you need (RSS Feed in XML please).
String url = "http://www.medicalnewstoday.com/rss/abortion.xml";
// Create XML Reader.
using (XmlReader xmlReader = XmlReader.Create(url, new XmlReaderSettings() { DtdProcessing = DtdProcessing.Ignore }))
{
// Load The Feed.
SyndicationFeed syndicationFeed = SyndicationFeed.Load(xmlReader);
// through the list.
foreach (SyndicationItem item in syndicationFeed.Items)
{
// You can use a lot of information here todo what you need.
// TODO...
// Examples
String subject = item.Title.Text;
String summary = item.Summary.Text;
}
xmlReader.Close();
}
}
}
}
I have XML file like below
<?xml version="1.0" standalone="yes"?>
<ShippersDataSet xmlns="http://www.tempuri.org/ShippersDataSet.xsd">
<Shippers>
<ShipperID>1</ShipperID>
<CompanyName>Speedy Express</CompanyName>
<Phone>(503) 555-9831</Phone>
</Shippers>
<Shippers>
<ShipperID>2</ShipperID>
<CompanyName>United Package</CompanyName>
<Phone>(503) 555-3199</Phone>
</Shippers>
<Shippers>
<ShipperID>3</ShipperID>
<CompanyName>Federal Shipping</CompanyName>
<Phone>(503) 555-9931</Phone>
</Shippers>
</ShippersDataSet>
I have following input for XML data :
string XMLpath, string query
Query :
<Query>
<ElementPath> Shippers</ElementPath>
</Query>
I need to add
Like following , ( I have achieved in SQL) same way I need to add for XML data
var list = new List<Myclassdef>();
using (var con = new SqlConnection(Settings.Default.ConnectionString))
{
using (var cmd = new SqlCommand("SELECT ... WHERE Col1=#param1", con))
{
cmd.Parameters.AddWithValue("#param1", "value1");
// ...
con.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Myclassdef data = new Myclassdef();
data.Data = new Dictionary<string, object>();
for (int i = 0; i < reader.FieldCount; i++)
{
data.Data.Add(reader.GetName(i), reader[i]);
}
list.Add(data);
}
}
}
}
I have following input for XML data :
string XMLpath, string query
Query :
<Query><ElementPath> Shippers</ElementPath></Query>
Try this:
class Program
{
static void Main(string[] args)
{
var list = new List<Myclassdef>();
var query = XDocument
.Parse("<Query><ElementPath> Shippers</ElementPath></Query>");
var doc = XDocument.Parse(File.ReadAllText("xml.xml"));
doc.Descendants(
XName.Get(
query.Root.Value.Trim(),
doc.Root.GetDefaultNamespace().NamespaceName))
.ToList()
.ForEach(e =>
{
var data = new Myclassdef();
data.Data = e
.Elements()
.Select(c => new
{
Name = c.Name.LocalName,
Value = (object)c.Value
})
.ToDictionary(c => c.Name, c => c.Value);
list.Add(data);
});
}
}
You can use Linq to XML for that (namespace System.Xml.Linq):
XDocument document = XDocument.Load(stream); // load the xml into an XDocument from a stream
// select the first of a specific element
IEnumerable<XElement> elements = from shippers in document.Descendants("Shippers") select shippers;
XElement element = (XElement)elements.First().FirstNode;
// loop through all the elements inside that element
foreach (XNode node in elements.First().Nodes())
{
// do something with elements
}
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.