I have a dictionary containg a string as TKey and a class "Component" as TValue.
My problem is that a want to add database values and xml values into the class fields.
This is my class Component:
public class Component
{
public string ComponentNr { get; set; }
public string Omschrijving { get; set; }
public int Aantal { get; set; }
public int Pos { get; set; }
}
I already have filled the fields ComponentNr and Pos with xml attribute values and now i want to get the "Aantal" and "Omschrijving" from the database where Database value "artcode" is ComponentNr
the query:
SqlCommand dgCommand = new SqlCommand("select g.artcode, i.Description, sum(g.aantal*-1) as aantal " +
"from gbkmut g " +
"join Items i on g.artcode = i.ItemCode " +
"where 1=1 and g.project=#projectnr and g.reknr=3000 and g.bud_vers='MRP' and g.operation='VOORSMD' and g.artcode !='H MAN' and i.Description not like 'pcb %' " +
"group by g.artcode, i.Description, g.aantal ", conn);
This is what i have at the moment to fill the Dictionary with xml attribute value:
Dictionary<string, Component> resultaten = componenten;
List<string> files = fileList;
string file;
file = files.Find(x => x.Contains(faberNr));
XDocument xdoc = XDocument.Load(file);
List<Component> components = xdoc.Descendants("Part").Select(x => new Component()
{
ComponentNr = (string)x.Elements().Where(y => y.Attribute("PartsName") != null)
.Select(y => (string)y.Attribute("PartsName")).FirstOrDefault(),
Pos = (int)x.Descendants().Where(y => y.Attribute("Setno") != null)
.Select(y => (int)y.Attribute("Setno")).FirstOrDefault()
}).ToList();
resultaten = components.GroupBy(x => x.ComponentNr, y => y).ToDictionary(x => x.Key, y => y.FirstOrDefault());
return resultaten;
Example:
My expected output is:
Key = 38292000
Value = Component
Aantal = 16
ComponentNr = 38292000
Omschrijving = Omschrijving123
Pos = 12
My actual output is:
Key = 38292000
Value = Component
Aantal = 0
ComponentNr = 38292000
Omschrijving = null
Pos = 12
So, step 1 is to populate a Dictionary<string, Component> from xml. Then step 2 is to run a database query to finish filling out the Component objects that are stored in the Dictionary?
ComponentNr is the key into the Dictionary, and you have ComponentNr from your database query in the "artcode" field, so you would just look up the value from the Dictionary using "artcode" then modify it.
// reader is an instance of SqlDataReader you got from the SqlCommand.
// resultaten is the Dictionary<string, Component> that you populated earlier.
// If these columns can be null in the database, don't forget to check them for DBNull.Value.
string componentNr = Convert.ToString(reader["artcode"]);
if (resultaten.TryGetValue(componentNr, out Component value))
{
value.Aantal = Convert.ToInt32(reader["aantal"]);
value.Omschrijving = Convert.ToString(reader["Description"]);
}
else
{
// Component exists in the database but not in the Dictionary.
}
Good day! Im trying to parse XML subchild using dataset. The thing is its not reading the "SiteCode" when it has multiple value.
for example:
string filePath = #"" + _clsPathIntervalSttngs.localPath + "/" + "hehe.xml";
DataSet dataSet = new DataSet()
dataSet.ReadXml(filePath, XmlReadMode.InferSchema);
// Then display informations to test
foreach (DataTable table in dataSet.Tables)
{
Console.WriteLine(table);
for (int i = 0; i < table.Columns.Count; ++i)
{
Console.Write("\t" + table.Columns[i].ColumnName.Substring(0, Math.Min(6, table.Columns[i].ColumnName.Length)));
Console.WriteLine();
}
foreach (var row in table.AsEnumerable())
{
for (int i = 0; i < table.Columns.Count; ++i)
{
Console.Write("\t" + row[i]);
}
Console.WriteLine();
}
}
this is what it is returning.
Its returning a 0 value and selecting the Product instead of sitecode.
Where did i go wrong?
You might have to check the code because I just took something similar I had lying around and changed it to look at your document hierarchy. I also didn't use a DataSet. Consider the following code:
var filePath = "<path to your file.xml>";
var xml = XDocument.Load(filePath);
var items = from item in xml.Descendants("Product").Elements()
select item.Value;
Array.ForEach(items.ToArray(), Console.WriteLine);
That should show you the values of each element under product. If you want the whole element, remove the .Value in the select clause of the LINQ query.
Update
I'm now projecting to an anonymous type. You'll get one of these for each Product element in the file.
var items = from item in dataset.Descendants("Product")
select new
{
RefCode = item.Element("RefCode").Value,
Codes = string.Join(", ", item.Elements("SiteCode").Select(x => x.Value)),
Status = item.Element("Status").Value
};
Array.ForEach(items.ToArray(), Console.WriteLine);
I have flattened the codes to a comma separated string but you can keep the IEnumerable or ToList it as you wish.
Using xml Linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication51
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XElement doc = XElement.Load(FILENAME);
List<Product> products = doc.Descendants("Product").Select(x => new Product()
{
refCode = (string)x.Element("RefCode"),
siteCode = x.Elements("SiteCode").Select(y => (int)y).ToArray(),
status = (string)x.Element("Status")
}).ToList();
}
}
public class Product
{
public string refCode { get; set; }
public int[] siteCode { get; set; }
public string status { get; set; }
}
}
This is my first time posting so I apologize for any ignorance or failed use of examples.
I have a console app project to create where I have been given a fair few CSV files and I need to create some kind of Parent/Child/Grandchild relationship out of them (XML? maybe? - then I can use that to do the uploads and writes to the DMS with minimal calls - I don't want to be querying if a folder exists over and over)
I am a little out of my depth on this one
I need to know the best way to do this without 3rd party library dependencies, pure C#, using the OLEDB JET provider is most likely required as it will handle the parsing required, there is no order to the CSV files in regards to date, previous years could appear down the list and vice versa.
Here's an example of the CSV output
"DESCRIPTION1","8, 5/8\" X 6.4MM","STRING","filename001.pdf","2016-09-19","1"
"DESCRIPTION2","12, 3/4\" X 6.4MM","STRING","filename001.pdf","2016-09-19","1"
"DESCRIPTION3","12, 3/4\" X 6.4MM","STRING","filename001.pdf","2016-09-19","1"
"another description 20# gw","1","388015","Scan123.pdf","2015-10-24","1"
"another description 20# gw","3","385902","Scan456.pdf","2015-04-14","1"
"STRINGVAL1","273.10 X 9.27 X 6000","45032-01","KHJDWNEJWKFD9101529.pdf","2012-02-03","1"
"STRINGVAL2","273.10 X 21.44 X 6000","7-09372","DJSWH68767681540.pdf","2017-02-03","1"
The end output will be (YEAR/MONTH/FILENAME + (Attributes for each file - these are for eventually updating columns inside a DMS))
Year and Month retrieved from the column with the date
If the YEAR alread exists then it will not be created again
If the month under that year exists it will not be created again
If the filename already exists under that YEAR/MONTH it will not be created again BUT the additional ATTRIBUTES for that FileName will be added to the attributes - "line seperated?"
Required Output:
I have attempted a Linq query to begin to output the possible required XML for me to progress but it outputs every row and does no grouping, I am not familiar with Linq at the moment.
I also ran into issues with the basic escaping on the .Split(',') doing it this way (see original CSV examples above compared to me using TAB separation in my test file and example below) which is why I want the Oledb provider to handle it.
string[] source = File.ReadAllLines(#"C:\Processing\In\mockCsv.csv");
XElement item = new XElement("Root",
from str in source
let fields = str.Split('\t')
select new XElement("Year", fields[4].Substring(0, 4),
new XElement("Month", fields[4].Substring(5, 2),
new XElement("FileName", fields[3]),
new XElement("Description",fields[0]),
new XElement("Length", fields[1]),
new XElement("Type", fields[2]),
new XElement("FileName", fields[3]),
new XElement("Date", fields[4]),
new XElement("Authorised", fields[5]))
)
);
I also need to log every step of the process so I have setup a Logger class
private class Logger
{
private static string LogFile = null;
internal enum MsgType
{
Info,
Debug,
Error
}
static Logger()
{
var processingDetails = ConfigurationManager.GetSection(SECTION_PROCESSINGDETAILS) as NameValueCollection;
LogFile = Path.Combine(processingDetails[KEY_WORKINGFOLDER],
String.Format("Log_{0}.txt", StartTime.ToString("MMMyyyy")));
if (File.Exists(LogFile))
File.Delete(LogFile);
}
internal static void Write(string msg, MsgType msgType, bool isNewLine, bool closeLine)
{
if (isNewLine)
msg = String.Format("{0} - {1} : {2}", DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss"), msgType, msg);
if (closeLine)
Console.WriteLine(msg);
else
Console.Write(msg);
if (String.IsNullOrEmpty(LogFile))
return;
try
{
using (StreamWriter sw = new StreamWriter(LogFile, true))
{
if (closeLine)
sw.WriteLine(msg);
else
sw.Write(msg);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
Used as such
Logger.Write(String.Format("Reading records from csv file ({0})... ",
csvFile), Logger.MsgType.Info, true, false);
Try following. If you are reading from a file use StreamReader instead of StringReader :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
using System.Text.RegularExpressions;
namespace ConsoleApplication74
{
class Program
{
static void Main(string[] args)
{
string input =
"\"DESCRIPTION1\",\"8, 5/8 X 6.4MM\",\"STRING\",\"filename001.pdf\",\"2016-09-19\",\"1\"\n" +
"\"DESCRIPTION2\",\"12, 3/4 X 6.4MM\",\"STRING\",\"filename001.pdf\",\"2016-09-19\",\"1\"\n" +
"\"DESCRIPTION3\",\"12, 3/4 X 6.4MM\",\"STRING\",\"filename001.pdf\",\"2016-09-19\",\"1\"\n" +
"\"another description 20# gw\",\"1\",\"388015\",\"Scan123.pdf\",\"2015-10-24\",\"1\"\n" +
"\"another description 20# gw\",\"3\",\"385902\",\"Scan456.pdf\",\"2015-04-14\",\"1\"\n" +
"\"STRINGVAL1\",\"273.10 X 9.27 X 6000\",\"45032-01\",\"KHJDWNEJWKFD9101529.pdf\",\"2012-02-03\",\"1\"\n" +
"\"STRINGVAL2\",\"273.10 X 21.44 X 6000\",\"7-09372\",\"DJSWH68767681540.pdf\",\"2017-02-03\",\"1\"\n";
string pattern = "\\\"\\s*,\\s*\\\"";
string inputline = "";
StringReader reader = new StringReader(input);
XElement root = new XElement("Root");
while ((inputline = reader.ReadLine()) != null)
{
string[] splitLine = Regex.Split(inputline,pattern);
Item newItem = new Item() {
description = splitLine[0].Replace("\"",""),
length = splitLine[1],
type = splitLine[2],
filename = splitLine[3],
date = DateTime.Parse(splitLine[4]),
authorized = splitLine[5].Replace("\"", "") == "1" ? true : false
};
Item.items.Add(newItem);
}
foreach(var year in Item.items.GroupBy(x => x.date.Year).OrderBy(x => x.Key))
{
XElement newYear = new XElement("_" + year.Key.ToString());
root.Add(newYear);
foreach(var month in year.GroupBy(x => x.date.Month).OrderBy(x => x.Key))
{
XElement newMonth = new XElement("_" + month.Key.ToString());
newYear.Add(newMonth);
newMonth.Add(
month.OrderBy(x => x.date).Select(x => new XElement(
x.filename,
string.Join("\r\n", new object[] {
x.description,
x.length,
x.type,
x.date.ToString(),
x.authorized.ToString()
}).ToList()
)));
}
}
}
}
public class Item
{
public static List<Item> items = new List<Item>();
public string description { get; set; }
public string length { get; set; }
public string type { get; set; }
public string filename { get; set; }
public DateTime date { get; set; }
public Boolean authorized { get; set; }
}
}
im reprogramming the tf2 tradebot by JesseCar 96 for CS:go. Im trying to get the items stored in a list array and I can't figure out how to access it. The instantiation and item data works like this:
public class TradeUserAssets : IEquatable<TradeUserAssets>, IComparable<TradeUserAssets>
{
/// <summary>Inventory type</summary>
public long contextid { get; private set; }
/// <summary>itemid</summary>
public ulong assetid { get; private set; }
public int appid { get; private set; }
public int amount { get; private set; }
public TradeUserAssets(int appid, long contextid, ulong assetid, int amount = 1)
{
this.appid = appid;
this.contextid = contextid;
this.assetid = assetid;
this.amount = amount;
}}
It is instantiated through:
private List<TradeUserAssets> otherOfferedItems;
otherOfferedItems = new List<TradeUserAssets>();
But when I use this foreach loop to get the data
foreach (long contextid in Trade.OtherOfferedItems.ToString())
{
Console.WriteLine(contextid);
}
The bot crashes. I've tried using a for loop and using the index number after .ToString()[i] like this but I can't get any of the data out. If I do anything other than .ToString() after OtherOfferedItems it won't build. Any help is really appreciated!
EDIT: This is my userHandler.cs
string tradeid;
if (myItems.Count == 0)
{
offer.Accept(out tradeid);
Log.Success("Accepted trade offer successfully : Trade ID: " + tradeid);
foreach (asset in Trade.OtherOfferedItems)
{
Console.WriteLine(asset);
}
using (var connection = new MySqlConnection("Server=localhost;Database=skindump;Uid=USERNAME;Pwd=PASSWORD;"))
{
var time = DateTime.Now.TimeOfDay;
var date = DateTime.Now;
date.ToString();
connection.Open();
MySqlCommand cmd = new MySqlCommand("INSERT INTO trades (tradeID, tradeUsed, tradeDate, steamID) VALUES (" + tradeid + ", 1, '" + date + "', '" + OtherSID.ConvertToUInt64() + "');");
cmd.Connection = connection;
cmd.ExecuteNonQuery();
Console.WriteLine("ServerVersion: {0}", connection.ServerVersion);
Console.WriteLine(date);
connection.Close();
}
}
Line 201 is the open squiggly bracket after the mysql connection (var connection = new mysql connection etc...). When I comment out the foreach loop it runs fine without crashing so thats definitely the issue.
You probably want to access a property inside of each object of your list. But what you are doing is just converting the Trade.OtherOfferedItems list to a string and then looping over that. You probably want to do something like this instead:
foreach (TradeUserAssets asset in Tade.OtherOfferedItems)
{
Console.WriteLine(asset.contextid);
}
You're trying to access the contextid by using ToString(), which is the wrong way to do it.
Instead, iterate through the collection of TradeUserAssets, and access the property inside the loop.
foreach (var asset in Trade.OtherOfferedItems)
{
Console.WriteLine(asset.contextid);
}
The reason your current code compiles is because it's returning the ascii value for each character in the string that ToString() returns (which is just the class name of the collection). Even if it didn't crash the app at runtime, it wouldn't be what you want.
The sample below is parsing an XML document then looping through the members and storing them in a list of objects (The data ultimately ends up in an SQL database):
public static void Parse(XDocument xml)
{
XNamespace ns = "http://somenamespace.com/ns";
var Locations =
from Continents in xml.Descendants(ns + "Continent")
from Countries in Continents.Elements(ns + "Country")
select new
{
Continent1 = (string) Continents.Element(ns + "Europe"),
Country1 = (string) Countries.Element(ns + "United_Kingdom"),
Cities = from Cities in Countries.Elements(ns + "City")
select new
{
City1 = (string) Cities.Element(ns + "London")
}
};
List<Location> locationColl = new List<Location>();
loc_Entity_FrameworkContainer context = new loc_Entity_FrameworkContainer();
var i = 0;
foreach (var location in Locations)
{
Location l = new Location();
locationColl.Add(l);
locationColl[i].Continent = (string) location.Continent1;
locationColl[i].Country = (string) location.Country1;
locationColl[i].City = (string) location.City1; // Can't access "City1"
context.Location.Add(locationColl[i]);
i++;
}
context.SaveChanges();
}
The statement: locationColl[i].City = (string)location.City1;
doesn't find "City1". (This is the issue, I can't access all the members from "Locations" in one loop)
Location Class:
namespace locationProject
{
using System;
using System.Collections.Generic;
public partial class Location
{
public string Continent { get; set; }
public string Country { get; set; }
public string City { get; set; }
}
}
XML Example:
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns:ns="http://somenamespace.com/ns">
<ns:Continent>
<ns:Europe>21c99a56-4b3d-4571-802a-76cdb6b81a01</ns:Europe>
<ns:Country>
<ns:United_Kingdom>eb2e9eec-dc3b-4636-bcf5-dba0024e62f3</ns:United_Kingdom>
<ns:City>
<ns:London>109b48ec-d829-4a87-b200-4dc9a94db48c</ns:London>
</ns:City>
</ns:Country>
</ns:Continent>
<ns:Continent>
<ns:Europe>a11ed925-dc0d-4dfd-b1c2-52eb697ad689</ns:Europe>
<ns:Country>
<ns:United_Kingdom>a61d02ef-7b80-4390-926a-49c6d9af9634</ns:United_Kingdom>
<ns:City>
<ns:London>dbb9c5cc-b08f-4223-b32c-acb4ed9ce97c</ns:London>
</ns:City>
</ns:Country>
</ns:Continent>
</feed>
I'm trying to find a way of looping through all the elements (Continent1, Country1, City1) that doesn't involve multiple loops and doesn't break the nested structure of the LINQ statements.
There are questions on here similar to this one, but I haven't found one I understand well enough to integrate with my code.
Thanks a lot!
Your anonymous type contained in the Locations list has a .Cities property that contains a City1 member:
Cities = from Cities in Countries.Elements(ns + "City")
select new
{
City1 = (string) Cities.Element(ns + "London")
}
Try this:
var Locations =
from Continents in xml.Descendants(ns + "Continent")
from Countries in Continents.Elements(ns + "Country")
from Cities in Countries.Elements(ns + "City")
select new
{
Continent1 = (string) Continents.Element(ns + "Europe"),
Country1 = (string) Countries.Element(ns + "United Kingdom"),
City1 = (string) Cities.Element(ns + "London")
};