Need advice on using XML as database C# - c#

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.

Related

How to read multiple node element from xml data in c#

I have xml like below. Here allowedSessionType can be multiple value sometime. Could anyone help me to read both and store it into data table c# gridview.
I tried but getting single value
<sessionManagementSubscriptionData>
<singleNssai>1-000001</singleNssai>
<dnnConfiguration>
<pduSessionTypes>
<defaultSessionType>IPV4</defaultSessionType>
<allowedSessionType>IPV4</allowedSessionType>
</pduSessionTypes>
<sscModes>
<defaultSscMode>SSC_MODE_1</defaultSscMode>
<allowedSscMode>SSC_MODE_1</allowedSscMode>
</sscModes>
</dnnConfiguration>
<dnnConfiguration>
<pduSessionTypes>
<defaultSessionType>IPV4</defaultSessionType>
<allowedSessionType>IPV4</allowedSessionType>
<allowedSessionType>IPV6</allowedSessionType>
</pduSessionTypes>
<sscModes>
<defaultSscMode>SSC_MODE_1</defaultSscMode>
<allowedSscMode>SSC_MODE_1</allowedSscMode>
</sscModes>
</dnnConfiguration>
</sessionManagementSubscriptionData>
DataTable dt1 = new DataTable();
dt1.Columns.Add("Allowed Session Type", typeof(string));
XmlNodeList nodeList1 = doc.SelectNodes("//sessionManagementSubscriptionData/dnnConfiguration");
foreach (XmlNode node1 in nodeList1)
{
DataRow dtrow1 = dt1.NewRow();
var SMSDDefaultSessionType = node1.SelectSingleNode("//defaultSessionType").InnerText;
dtrow1["Default Session Type"] = SMSDDefaultSessionType;
var SMSDallowedSessionType = node1.SelectSingleNode("//allowedSessionType").InnerText;
dtrow1["Allowed Session Type"] = SMSDallowedSessionType;
dt1.Rows.Add(dtrow1);
}
GridView2.DataSource = dt1;
GridView2.DataBind();
using System.Xml.Serialization;
XmlSerializer serializer = new XmlSerializer(typeof(SessionManagementSubscriptionData));
using (StringReader reader = new StringReader(xml))
{
var test = (SessionManagementSubscriptionData)serializer.Deserialize(reader);
//test.DnnConfiguration has your data
}
[XmlRoot(ElementName="pduSessionTypes")]
public class PduSessionTypes {
[XmlElement(ElementName="allowedSessionType")]
public List<string> AllowedSessionType;
}
[XmlRoot(ElementName="sscModes")]
public class SscModes {
[XmlElement(ElementName="defaultSscMode")]
public string DefaultSscMode;
[XmlElement(ElementName="allowedSscMode")]
public string AllowedSscMode;
}
[XmlRoot(ElementName="dnnConfiguration")]
public class DnnConfiguration {
[XmlElement(ElementName="pduSessionTypes")]
public PduSessionTypes PduSessionTypes;
[XmlElement(ElementName="sscModes")]
public SscModes SscModes;
}
[XmlRoot(ElementName="sessionManagementSubscriptionData")]
public class SessionManagementSubscriptionData {
[XmlElement(ElementName="singleNssai")]
public DateTime SingleNssai;
[XmlElement(ElementName="dnnConfiguration")]
public List<DnnConfiguration> DnnConfiguration;
}
Use this webiste to convert xml to c#
Here is results in a DataTable using Xml Linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication11
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("Default Session Type", typeof(string));
dt.Columns.Add("Allowed Session Type", typeof(string));
dt.Columns.Add("Default SSC Mode", typeof(string));
dt.Columns.Add("Allowed SSC Mode", typeof(string));
XDocument doc = XDocument.Load(FILENAME);
foreach (XElement dnnConfiguration in doc.Descendants("dnnConfiguration"))
{
string defaultSessionType = (string)dnnConfiguration.Descendants("defaultSessionType").FirstOrDefault();
string[] allowedSessionType = dnnConfiguration.Descendants("allowedSessionType").Select(x => (string)x).ToArray();
string defaultSscMode = (string)dnnConfiguration.Descendants("defaultSscMode").FirstOrDefault();
string[] allowedSscMode = dnnConfiguration.Descendants("allowedSscMode").Select(x => (string)x).ToArray();
dt.Rows.Add(new object[] { defaultSessionType, string.Join(",", allowedSessionType), defaultSscMode, string.Join(",", allowedSscMode) });
}
}
}
}

C# Reading CSV file with SQL conditions

I am using CsvHelper lib to read CSV file and I can successfully read the file with the lib. However I cannot use SQL condition to filter values. How can I do that without using SQL Server. I am really stuck on it.
It was very easy with Pandas and Pandasql libs in Python but it is being too hard in C#..
My Code:
public static void Main(string[] args)
{
var fileInfo = new FileInfo(#"filePath");
using (TextReader reader = fileInfo.OpenText())
using (var csvReader = new CsvReader(reader))
{
csvReader.Configuration.Delimiter = ",";
csvReader.Configuration.HasHeaderRecord = false;
csvReader.Configuration.IgnoreQuotes = true;
csvReader.Configuration.TrimFields = true;
csvReader.Configuration.WillThrowOnMissingField = false;
while (csvReader.Read())
{
var myStrinVar = csvReader.GetField<string>(0);
Console.Write(myStrinVar); //SELECT * FROM table...
}
}
}
I would suggest using LINQ to filter your results.
https://msdn.microsoft.com/en-us/library/bb397906.aspx
Say you have some class MyClass that you can serialize the lines in your file into.
For example:
public class MyClass
{
public int ID { get; set; }
}
var records = csv.GetRecords<MyClass>().ToList();
var filtered = records.Where(r => r.ID >= 10);
That example is a bit contrived but you can use any boolean expression you like in the where clause.
I know this is too late for OP, but the issue with the accepted answer is that you have to read in the entire result set to memory which may not be tenable for large files. Also, if you can extend this code below to get the top N rows without having to read the entire CSV if you find matches early in the file.
public static void Main(string[] args)
{
var fileInfo = new FileInfo(#"filePath");
var where = ""; //Code to set up where clause part of query goes here
using (TextReader reader = fileInfo.OpenText())
using (var csvReader = new CsvReader(reader))
{
csvReader.Configuration.Delimiter = ",";
csvReader.Configuration.HasHeaderRecord = false;
csvReader.Configuration.IgnoreQuotes = true;
csvReader.Configuration.TrimFields = true;
csvReader.Configuration.WillThrowOnMissingField = false;
DataTable dt = null;
while (csvReader.Read())
{
//Use the first row to initialize the columns.
if (dt == null)
{
dt = new DataTable();
for (var i = 0; i < csvReader.FieldCount; i++)
{
var fieldType = csvReader.GetFieldType(i);
DataColumn dc;
if (fieldType.IsNullableType())
{
dc = new DataColumn(csvReader.GetName(i), Nullable.GetUnderlyingType(fieldType));
dc.AllowDBNull = true;
}
else
dc = new DataColumn(csvReader.GetName(i), data.GetFieldType(i));
dt.Columns.Add(dc);
}
}
//Map DataReader to DataRow
var newRow = dt.Rows.Add();
foreach(DataColumn col in dt.Columns)
{
newRow[col.ColumnName] = csvReader[col.ColumnName];
}
//Create a temporary DataView and filter it with the where clause.
DataView dv = new DataView(dt);
dv.RowFilter = where;
var data = dv.Count > 0 ? dv[0] : null;
if(data != null)
{
//Row in here matches your where clause.
//Code to read this row or do something with it.
}
//Empty the temporary data table.
dt.Rows.Clear();
}
}
}

Reading XML and storing it in SQL Server. Getting duplicates

I am trying to read XML feed from the URL and store it in the database. The XML format looks like this:
<response version="2">
<totalresults>1249943</totalresults>
<results>
<result>
<jobtitle>Call Center </jobtitle>
<company>CVS Health</company>
<city>Work at Home</city>
</result>
<result>
<jobtitle>Java Programmer</jobtitle>
<company>Jonah Group</company>
<city>Toronto</city>
</result>
</results>
</response>
And I am trying to store job title, company, and city for all the jobs. There are millions of jobs. Here is my code in C#
public override void getJobsFromSource()
{
string url = #"http://api.indeed.com/ads/apisearch?publisher=5566998848654317&v=2&q=%22%22&filter=1%22%22&limit=25";
XmlDocument doc = new XmlDocument();
doc.Load(url);
int totalResults = int.Parse(doc.SelectSingleNode("response /totalresults").InnerText);
for (int i = 0; i < totalResults; i += 25)
{
string newUrl = $#"http://api.indeed.com/ads/apisearch?publisher=5566998848654317&v=2&q=%22%22&filter=1&limit=25&start={i}";
doc.Load(newUrl);
DataSet ds = new DataSet();
XmlNodeReader xmlReader = new XmlNodeReader(doc);
while (xmlReader.ReadToFollowing("results"))
{
ds.ReadXml(xmlReader);
}
if (ds.Tables.Count > 0)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = "data source=10.0.0.76;initial catalog=JobSearchDB;persist security info=True;user id=sa;password=bonddbl07;MultipleActiveResultSets=True;App=EntityFramework";
con.Open();
SqlBulkCopy sbc = new SqlBulkCopy(con);
sbc.DestinationTableName = "IndeedJob";
sbc.ColumnMappings.Clear();
sbc.ColumnMappings.Add("jobtitle", "jobtitle");
sbc.ColumnMappings.Add("company", "company");
sbc.ColumnMappings.Add("city", "city");
sbc.WriteToServer(ds.Tables[0]);
con.Close();
}
}
}
The problem is that while jobs are unique, I am getting many duplicates in my tables. Duplicates come in random numbers whenever I run the program. Where am going wrong?
The webpage definitely has duplicates. I verified with code below. The webpage doesn't appear to have well formed xml so I had to modify your code to be able to read webpage. Using Linq I was able to remove the duplicates.
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.Schema;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
DataSet ds = new DataSet("Jobs");
public Form1()
{
InitializeComponent();
getJobsFromSource();
DataTable dt = ds.Tables[0];
dt = dt.AsEnumerable().GroupBy(x => x.Field <string>("jobkey")).Select(x => x.FirstOrDefault()).OrderBy(y => y.Field<string>("jobkey")).CopyToDataTable();
dataGridView1.DataSource = dt;
}
public void getJobsFromSource()
{
string url = #"http://api.indeed.com/ads/apisearch?publisher=5566998848654317&v=2&q=%22%22&filter=1%22%22&limit=25";
XmlDocument doc = new XmlDocument();
doc.Load(url);
int totalResults = int.Parse(doc.SelectSingleNode("response /totalresults").InnerText);
for (int i = 0; i < totalResults; i += 25)
{
string newUrl = #"http://api.indeed.com/ads/apisearch?publisher=5566998848654317&v=2&q=%22%22&filter=1&limit=25&start={i}";
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.None;
settings.IgnoreWhitespace = true;
XmlReader xmlReader = XmlReader.Create(newUrl, settings);
while (!xmlReader.EOF)
{
if (xmlReader.Name != "result")
{
xmlReader.ReadToFollowing("result");
}
if(!xmlReader.EOF)
{
ds.ReadXml(xmlReader);
}
}
}
}
}
}
It seems like you are assuming that the results are not going to change while you are parsing the results, but this may not be the case. If a new posting comes in, it may appear at the beginning of the list, and push the rest of your results down one. This causes the last item on a page to be duplicated on the next page.
Also, there doesn't appear to be a firm order to the query you are making. It is possible the existing results are changing order while you are searching through. Again, if items shift around in the search, it may lead to either duplicates or skipped items.

Loading a DataTable with a XML string

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;
}
}
}

Dynamic linq to Dataset datarow based on collection property name

I'm working on a project that connects to Oracle. It Brings back data through a dataset. I use Linq to bind it to a collection and throw it back to be read by json. It works great but I can't help but think - there's got to be a better way to do this. Here's an example of what I do. I hope it helps others. Dsp is Dataset.
List<Information> lstSearch = null;
lstSearch = (from l in dsp.Tables[0].AsEnumerable()
select new Information
{
application_id = l["APPLICATION_ID"].ToString(),
hospital_name_1 = l["HOSPITAL_NAME_"].ToString(),
physical_address = l["PHYSICAL_ADDRESS"].ToString(),
// may have to add more here...
}).ToList<Information>();
// serialize and send back as a json string
System.Web.Script.Serialization.JavaScriptSerializer oSerializer =
new System.Web.Script.Serialization.JavaScriptSerializer();
string sJSON = oSerializer.Serialize(lstSearch.First());
Theoretically, yes works. The "information" collection matches the html "name" tag of each control on the page which provides a nice robust binding. My concern lies with having
to go through each field name in order to populate the List<> object.
Isn't there a specific where clause in where the collection (get/set) property matches the dataset column name thus populating the collection only if the column name (not the value) matches the data row column?
I'd recommend AutoMapper ... see this question.
Here's a very simple example. Make sure that your .NET type exactly mirrors the structure of your DB object or AutoMapper will not work as advertised:
namespace EnumerableDT
{
class Program
{
public class Information
{
public int APPLICATION_ID { get; set; }
public string HOSPITAL_NAME { get; set; }
public string PHYSICAL_ADDRESS { get; set; }
public string SOME_OTHER_FIELD { get; set; }
}
static DataSet dsp = new DataSet();
static void Main(string[] args)
{
dsp.Tables.Add(BuildDataTableStructure());
dsp.Tables[0].Rows.Add(BuildRow());
AutoMapper.Mapper.Reset();
AutoMapper.Mapper.CreateMap<IDataReader, Information>();
var il = AutoMapper.Mapper.Map<IDataReader, IList<Information>>(dsp.Tables[0].CreateDataReader());
Console.ReadLine();
}
static DataTable BuildDataTableStructure()
{
var dt = new DataTable();
var dc = new DataColumn("APPLICATION_ID", typeof(int));
dt.Columns.Add(dc);
dc = new DataColumn("HOSPITAL_NAME", typeof(string));
dt.Columns.Add(dc);
dc = new DataColumn("PHYSICAL_ADDRESS", typeof(string));
dt.Columns.Add(dc);
dc = new DataColumn("SOME_OTHER_FIELD", typeof(string));
dt.Columns.Add(dc);
return dt;
}
static DataRow BuildRow()
{
DataRow dr = dsp.Tables[0].NewRow();
dr["APPLICATION_ID"] = 1;
dr["HOSPITAL_NAME"] = "The Hospital";
dr["PHYSICAL_ADDRESS"] = "123 Main St.";
dr["SOME_OTHER_FIELD"] = "Some Other Data";
return dr;
}
}
}

Categories