I have the XMLDocument and I extract the following xml tags I want using the xmlDocument.SelectSingleNode("./tag") into a string and I want to load it inside a DataTable.
I tried using the dataTable.ReadXML(); but the overloads for this function do not allow a string argument.
Is there a better way of doing this?
Edit : Adding Code
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(string_With_Xml);
DataTable accessTable = new DataTable();
accessTable.ReadXml();
I Hope this adds more context to the question.
You can try the following:
//Your xml
string TestSTring = #"<Contacts>
<Node>
<ID>123</ID>
<Name>ABC</Name>
</Node>
<Node>
<ID>124</ID>
<Name>DEF</Name>
</Node>
</Contacts>";
StringReader StringStream = new StringReader(TestSTring);
DataSet ds = new DataSet();
ds.ReadXml(StringStream);
DataTable dt = ds.Tables[0];
you can write extension like this:
public static someType ReadXml(this DataTable dt, string yourParam1, string yourParam2)
{
method body....
}
You can do the following approach, the byte array here can be loaded for a string using for example:
Encoding.UTF8.GetBytes(somestring)
Helper method to load the datatable, note fallback to DataSet's method ReadXml instead of Datatable ReadXml. This will not always be suitable in case your xml contains somehow several data tables, as this method always returns the first data table in the catch:
public DataTable Convert(byte[] bytes)
{
var text = bytes.ToStringUtf8();
if (string.IsNullOrWhiteSpace(text))
{
return null;
}
using (var stream = new MemoryStream(bytes))
{
try
{
var dt = new DataTable();
dt.ReadXml(stream);
return dt;
}
catch (InvalidOperationException ie)
{
Trace.WriteLine(ie);
var ds = new DataSet();
stream.Position = 0;
ds.ReadXml(stream);
if (ds.Tables.Count > 0)
{
return ds.Tables[0];
}
return null;
}
}
}
Related
I have
an old WCF SOAP service from my server,
an .NET Framework application.
an .NET Framework library.
I want to upgrade my library first to netstandard2.0.
Everything works well, i can regenerate WCF Client files.
However, DataTable have changed to ...TableResult with XmlElement.
So, i know how to change XmlElement to DataTable, but how do I change DataTable to XmlElement?
public static class Transform
{
public static DataTable ToDataTable(XmlElement xmlElement)
{
using var reader = new XmlNodeReader(xmlElement);
var datatable = new DataTable();
datatable.ReadXml(reader);
return datatable;
}
public static XmlElement ToXmlElement(DataTable datatable)
{
throw new NotImplementedException();
}
}
You have to use GroupBy to group the rows, then select the parts you want into XElements.
Here is an example:
var xml = new XElement(table.TableName, table.Rows.Cast<DataRow>()
.GroupBy(row => (string)row[0])
.Select(g =>
new XElement(table.Columns[0].ColumnName,
new XElement("label", g.Key),
g.GroupBy(row => (string)row[1])
.Select(g1 =>
new XElement(table.Columns[1].ColumnName,
new XElement("label", g1.Key),
new XElement(table.Columns[2].ColumnName,
g1.Select(row =>
new XElement("label", (string)row[2])
)
)
)
)
)
)
)
or you can use dataset
DataSet ds = new DataSet();
ds.Tables.Add(table);
XmlDocument XMLDoc = new XmlDocument();
Console.WriteLine(ds.GetXml().ToString());
// In your case:
return XMLDoc.DocumentElement;
You may use ds.Write.xml, this will have a Stream to put the output into. If you need it, try the method below:
public static class Extensions
{
public static string ToXml(this DataSet ds)
{
using (var memoryStream = new MemoryStream())
{
using (TextWriter streamWriter = new StreamWriter(memoryStream))
{
var xmlSerializer = new XmlSerializer(typeof(DataSet));
xmlSerializer.Serialize(streamWriter, ds);
return Encoding.UTF8.GetString(memoryStream.ToArray());
}
}
}
}
USAGE:
var xmlString = ds.ToXml();
Response.Write(ds.ToXml());
And you can check the docs for help.
I got a web application which contains a XML file for storing user data.I want to display entered data in grid view for that specific user only based on 'txtEmpid.Text'. I think the issue is with string reader. But I can't seem to figure out what as I am new to asp.net and this code gives me blank page.
Thanks for help
My XML file:
-<SkillSet>
-<SkillSets>
<Employee_ID>1</Employee_ID>
<Employee_Name>abc</Employee_Name>
<PL_Name>xyz</PL_Name>
<Skill_Name1>C# with Asp.NET</Skill_Name1>
<Skill_Type1>Programming</Skill_Type1>
<Skill_Proficiency1>Beginner</Skill_Proficiency1>
<Experience1>1</Experience1>
<Skill_Name2>FL Studio</Skill_Name2>
<Skill_Type2>Others</Skill_Type2>
<Skill_Proficiency2>Intermediate</Skill_Proficiency2>
<Experience2>2</Experience2>
<Skill_Name3>ms word</Skill_Name3>
<Skill_Type3>others</Skill_Type3>
<Skill_Proficiency3>Advance</Skill_Proficiency3>
<Experience3>3</Experience3>
<Skill_Name4>Camtasia</Skill_Name4>
<Skill_Type4>Others</Skill_Type4>
<Skill_Proficiency4>Professional</Skill_Proficiency4>
<Experience4>4</Experience4>
<Skill_Name5>MS excel</Skill_Name5>
<Skill_Type5>Programming</Skill_Type5>
<Skill_Proficiency5>Beginner</Skill_Proficiency5>
<Experience5>5</Experience5>
<Comments>fgfdgdf</Comments>
</SkillSets>
</SkillSet>
and here is my C# file that has logic to bind data :
private void BindGrid()
{
try {
var xmlStr = File.ReadAllText(Server.MapPath("~/SkillSet.xml"));
var str = XElement.Parse(xmlStr);
var result = str.Elements("SkillSets").
Where(x => x.Element("Employee_ID").Value.Equals(txtEmpid.Text)).ToList();
StringReader theReader = new StringReader(result.ToString());
DataSet ds = new DataSet();
ds.ReadXml(theReader);
if (ds != null && ds.HasChanges())
{
grdxml.DataSource = ds;
grdxml.DataBind();
}
else
{
grdxml.DataBind();
}
}
catch(Exception ex)
{
lblerror.Text = ex.ToString();
}
Your LINQ query is good. The problem in your code is here:
StringReader theReader = new StringReader(result.ToString());
ds.ReadXml(theReader);
You're using result.ToString(), and the ToString() representation of a List of XElements is nothing you can read as XML. In fact, calling ToString() will result in this
"System.Collections.Generic.List`1[System.Xml.Linq.XElement]"
And as you can see, that's not XML
For your code to work, try something like this:
try {
var xmlStr = File.ReadAllText(Server.MapPath("~/SkillSet.xml"));
var str = XElement.Parse(xmlStr);
var result = str.Elements("SkillSets").
Where(x => x.Element("Employee_ID").Value.Equals(txtEmpid.Text)).ToList();
grdxml.DataSource = result.ToList();
grdxml.DataBind();
}
catch(Exception ex)
{
lblerror.Text = ex.ToString();
}
Also, remove the slashes on your XML
try this:
string filePath = "Complete path where you saved the XML file";
DataSet ds = new DataSet();
ds.ReadXml(filePath);
var skillSets = ds.Tables[0].AsEnumerable();
var query = from skillset in skillSets
where skillset.Field<string>("Employee_ID") == "1" // here you can get value from text box etc.
select skillset;
grdxml.DataSource = query.ToList();
grdxml.DataBind();
I am attempting to create a DataTable from an XML file. Here is my code:
DataSet ds = new DataSet();
DataTable sqlTable = new DataTable("SqlTable");
sqlTable.Columns.Add("Team");
ds.Tables.Add(sqlTable);
if (File.Exists(pathToXmlFile))
{
//sqlTable.Tables[0].TableName = "ServerXML";
//sqlTable.ReadXmlSchema(pathToXmlFile);
ds.ReadXml(pathToXmlFile);
foreach (DataColumn column in ds.Tables[0].Columns)
{
Console.WriteLine(column.ColumnName);
foreach (DataRow row in ds.Tables[0].Rows)
{
Console.WriteLine(row[column].ToString());
}
}
}
else
{
File.AppendAllText(pathToLogFile, Environment.NewLine + DateTime.Now + ": ServerXml.xml could not be found. A database table could not be created.");
}
}
The problem I have is, that the ds.ReadXml(pathToXmlFile) line is making multiple tables out of the XML. Here is the format of the XML file:
<?xml version="1.0" encoding="UTF-8"?>
<items found="132" limit="1000">
<sampleField>
<att1>18
</att1>
<att2>4343
</att2>
<att3>94007961
</att3>
<att4>Test
</att4>
<att5>Example
</att5>
</sampleField>
<sampleField>
<att1>40
</att1>
<att2>8945
</att2>
<att3>94089741
</att3>
<att4>Test2
</att4>
<att5>Example2
</att5>
</sampleField>
</items>
How can I achieve creating a single table, with the <sampleField> tags representing different entries?
create an entity class sampleField
public class sampleField
{
public string att1{get;set;}
public string att2{get;set;}
public string att3{get;set;}
public string att4{get;set;}
public string att5{get;set;}
}
Use this helper
public static sampleField ObjectToXML(string XmlOfAnObject, Type ObjectType) {
StringReader StrReader = new StringReader(XmlOfAnObject);
XmlSerializer serializer = new XmlSerializer(ObjectType);
XmlTextReader XmlReader = new XmlTextReader(StrReader);
try {
sampleField AnObject = serializer.Deserialize(XmlReader);
return AnObject;
} catch (Exception exp) {
//Handle Exception Code
} finally {
XmlReader.Close();
StrReader.Close();
}
}
I am making an application that stores data that user inputs.
http://i827.photobucket.com/albums/zz200/ArnasG/question_in_stackowerflow__zps4f7uy3l7.png
I have a bit of an issue because of my lack of experience, I want to save all the data user inputs in XML file and to load it when program starts next time. I had an idea to use dataset to read all the data from XML file and then work with the table[0] of that dataset(add/delete rows). It turn out that I can not make it to work properly. It loads some blank lines and lines that I created in previous tries, but there is only two lines that are actually saved in XML file. How could I make this work?
Thank you for your time :)
Actual XML file:
http://i827.photobucket.com/albums/zz200/ArnasG/question_in_stackowerflow_V2_zpshmwjnllr.png
DataSet ListOfTrades = new DataSet();
DataTable Lentele = new DataTable();
ListOfTrades.Tables.Add(Lentele);
// adding columns to the table
try
{
DataColumn Pair = new DataColumn("Pair", typeof(string));
Pair.AllowDBNull = false;
DataColumn Entry = new DataColumn("Entry", typeof(string));
Entry.AllowDBNull = false;
DataColumn StopLoss = new DataColumn("StopLoss", typeof(string));
StopLoss.AllowDBNull = false;
DataColumn TakeProfit = new DataColumn("TakeProfit", typeof(string));
TakeProfit.AllowDBNull = false;
DataColumn TakeProfit1 = new DataColumn("TakeProfit1", typeof(string));
TakeProfit1.AllowDBNull = false;
DataColumn TakeProfit2 = new DataColumn("TakeProfit2", typeof(string));
TakeProfit2.AllowDBNull = false;
DataColumn TakeProfit3 = new DataColumn("TakeProfit3", typeof(string));
TakeProfit3.AllowDBNull = false;
DataColumn LongShort = new DataColumn("LongShort", typeof(string));
LongShort.AllowDBNull = false;
DataColumn WinLoss = new DataColumn("WinLoss", typeof(string));
WinLoss.AllowDBNull = false;
data.Tables[0].Columns.AddRange(new DataColumn[] {
Pair, Entry, StopLoss, TakeProfit, TakeProfit1, TakeProfit2,
TakeProfit3, LongShort, WinLoss
});
}
catch(Exception Ex)
{
MessageBox.Show(Ex.Message);
}
// Adding new line to the table after user clicks save button
private void button1_Click(object sender, EventArgs e)
{
DataRow eilute = ListOfTrades.Tables[0].NewRow();
eilute[0] = comboBox1.Text.ToString();
eilute[1] = textBox1.Text.ToString();
eilute[2] = textBox2.Text.ToString();
eilute[3] = textBox3.Text.ToString();
eilute[4] = textBox4.Text.ToString();
eilute[5] = textBox5.Text.ToString();
eilute[6] = textBox6.Text.ToString();
if (radioButton1.Checked) { eilute[7] = "Long"; }
else { eilute[7] = "short"; }
if (radioButton1.Checked) { eilute[8] = "Win"; }
else { eilute[8] = "Loss"; }
ListOfTrades.Tables[0].Rows.Add(eilute);
ListOfTrades.Tables[0].WriteXml(DefaultPathToJournalXML);
dataGridView1.Update();
dataGridView1.Refresh();
}
Not getting duplicated. here is the xml
<?xml version="1.0" standalone="yes"?>
<NewDataSet>
<Table1>
<Pair>AUD/USD</Pair>
<Entry>0.00000</Entry>
<StopLoss>0.00000</StopLoss>
<TakeProfit>0.00000</TakeProfit>
<TakeProfit1>0.00000</TakeProfit1>
<TakeProfit2>0.00000</TakeProfit2>
<TakeProfit3>0.00000</TakeProfit3>
<LongShort>short</LongShort>
<WinLoss>loss</WinLoss>
</Table1>
<Table1>
<Pair>AUD/USD</Pair>
<Entry>0.00000</Entry>
<StopLoss>0.00000</StopLoss>
<TakeProfit>0.00000</TakeProfit>
<TakeProfit1>0.00000</TakeProfit1>
<TakeProfit2>0.00000</TakeProfit2>
<TakeProfit3>0.00000</TakeProfit3>
<LongShort>short</LongShort>
<WinLoss>Loss</WinLoss>
</Table1>
</NewDataSet>
Here is code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
DataSet ds = new DataSet();
ds.ReadXml(FILENAME);
}
}
}
Think object oriented, and think Linq.
For example, let's say you have this XML file:
<trades>
<trade>
<pair>some pair</pair>
<stop-loss>stop loss 1</stop-loss>
</trade>
<trade>
<pair>other pair</pair>
<stop-loss>stop loss 2</stop-loss>
</trade>
</trades>
You can create a Trade class to hold the data in the trade tags and then use a Linq query to populate the object given the XML file:
class Trade
{
public string Pair;
public string StopLoss;
// Other variables from trade tag would go here...
// Function that can load trade objects from XML file into a list of Trade objects (List<Trade>)
public static List<Trade> loadTrade(string xmlFilePath)
{
// Load your XML document given the path to the .xml file
var doc = XDocument.Load(xmlFilePath);
// For each trade element in the trades element
var trades = (from trade in doc.Element("trades").Elements("trade")
select new Trade
{
// For each element in the trade element, put value in class variable
Pair = trade.Element("pair").Value,
StopLoss = trade.Element("stop-loss").Value
}).ToList<Trade>();
return trades;
}
}
When you're ready to save to a file you basically do the opposite of the Linq query to create an XML file. It will look very similar.
On there other hand, read this article and consider if there's a better alternative.
My project requires a functionality to convert the input XML file into DataTable.
I am using the following code to do that.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
dataSourceFileStream.Seek(0, SeekOrigin.Begin);
ds.ReadXml(dataSourceFileStream);
dt = ds.Tables[0];
This works quiet right unless the input XML has duplicate elements, for eg, if the XML file is like below:
<?xml version="1.0" encoding="iso-8859-1"?>
<DocumentElement>
<data>
<DATE>27 September 2013</DATE>
<SCHEME>Test Scheme Name</SCHEME>
<NAME>Mr John</NAME>
<SCHEME>Test Scheme Name</SCHEME>
<TYPE>1</TYPE>
</data>
</DocumentElement>
As you can see above, the element SCHEME appears twice. when this kind of XML file comes ds.ReadXml(dataSourceFileStream); fails to return right data table.
Any better way to handle this?
Looks like you have to fix the XML first. You can do this by using the XDocument and associated classes. But first you need to create a EqualityComparer which compares two XElements based on their name:
public class MyEqualityComparer : IEqualityComparer<XElement>
{
public bool Equals(XElement x, XElement y)
{
return x.Name == y.Name;
}
public int GetHashCode(XElement obj)
{
return obj.Name.GetHashCode();
}
}
Now try this:
var comparer = new MyEqualityComparer();
XDocument.Load(dataSourceFileStream);
var doc = XDocument.Parse(data);
var dataElements = doc.Element("DocumentElement").Elements("data");
foreach (var dataElement in dataElements)
{
var childElements = dataElement.Elements();
var distinctElements = childElements.Distinct(comparer).ToArray();
if (distinctElements.Length != childElements.Count())
{
dataElement.Elements().Remove();
foreach (var item in distinctElements)
dataElement.Add(item);
}
}
using (var stream = new MemoryStream())
{
var writer = new StreamWriter(stream);
doc.Save(writer);
stream.Seek(0, 0);
var ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
var mode = ds.ReadXml(stream);
var dt = ds.Tables[0];
}
That would be a quick workaround to your problem. But i strongly suggest to encourage the data provider to fix the XML
Okay. as stated in my previous comment, you can create your own XmlTextReader which patches/ignores some elements. The idea is, that this reader checks if he has already read an element within the same depth. If it is the case, advance to the end element.
class MyXmlReaderPatcher : XmlTextReader
{
private readonly HashSet<string> _currentNodeElementNames = new HashSet<string>();
public MyXmlReaderPatcher(TextReader reader) : base(reader)
{ }
public override bool Read()
{
var result = base.Read();
if (this.Depth == 1)
{
_currentNodeElementNames.Clear();
}
else if (this.Depth==2 && this.NodeType == XmlNodeType.Element)
{
if (_currentNodeElementNames.Contains(this.Name))
{
var name = this.Name;
do {
result = base.Read();
if (result == false)
return false;
} while (this.NodeType != XmlNodeType.EndElement && this.Name != name);
result = this.Read();
}
else
{
_currentNodeElementNames.Add(this.Name);
}
}
return result;
}
}
All you have to do is to link the new reader in between your ds.ReadXml() and your file stream:
var myReader = new MyXmlReaderPatcher(dataSourceFileStream);
var ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
var mode = ds.ReadXml(myReader);
var dt = ds.Tables[0];