<?xml version="1.0" standalone="yes"?>
<Subject>
<Book>
<Name>ASP.NET</Name>
<Author>ABC</Author>
<Published>2018</Published>
<Price>$100</Price>
</Book>
</Subject>
The above is xml file i have . I want to Store those xml nodes and values in Dictionary and also i need to access the values by using corresponding nodes.
Then only it will works ..
What i have tried is:
XmlTextReader reader = new XmlTextReader("myxmlfile.xml");
Dictionary<string, string> dict = new Dictionary<string, string>();
string field = "";
string strlayer = "";
bool Name = false;
int count = 0;
while (reader.Read())
{
XmlNodeType nt = reader.NodeType;
switch (reader.NodeType)
{
case XmlNodeType.Element:
switch (reader.Name)
{
case "Subject":
count = 1;
break;
case "Book":
count = 1;
break;
case "Name":
if (count == 1)
{
strlayer = reader.Value;
MessageBox.Show(strlayer);
}
else
Name = true;
break;
}
break;
}
}
Am trying the code but its not working.Anyone's help is appreciable ....
i just want to store for that value to that Particular node That's it....
you can use this code:
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load("YOUR_PATH");
Dictionary<string, string> dict = new Dictionary<string, string>();
foreach (XmlElement item in xmlDocument.SelectSingleNode("Subject/Book"))
{
dict.Add(item.Name, item.InnerText);
}
if you have only one "Book" element this code help you. but if you have several Book item so you can not use a dictionary to save them.
Using Xml Linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq ;
namespace ConsoleApplication48
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Dictionary<string, string> dict = doc.Descendants("Book").FirstOrDefault().Elements()
.GroupBy(x => x.Name.LocalName, y => (string)y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
}
}
}
Related
I have an XML as below, I couldn't have multiple data files to be given in app.config and get it moved to the bin/Debug folder during the build. Hence I'm trying to have the test data in one XML file itself.
<?xml version="1.0" encoding="UTF-8"?>
<AppTestData>
<Contact>
<Name>Abe</Name>
<Age>33</Age>
<City>York</City>
...
</Contact>
<Agent>
<Code>A103S</Code>
<Region>North</North>
<Resp>Service</Resp>
....
</Agent>
<Product>
<Cat>Electronics</Cat>
...
</Product>
</AppTestData>
My code will give whether its a Contact / Agent / Product ... and I need the elements below that to be a Dictionary.
XDocument doc = XDocument.Load(new XmlTextReader(xmlName));
Dictionary<string, string> appData = ParseTestDataXML.GetRecordData(<file_path>), "Contact");
foreach (XElement element in doc.Descendants("Contact").Where(p => !p.HasElements))
{
int keyInt = 0;
string keyName = element.Name.LocalName;
while (keyValuePairs.ContainsKey(keyName))
{
keyName = $"{element.Name.LocalName}_{keyInt++}";
}
keyValuePairs.Add(keyName, element.Value);
}
But it adds every other element node and value from other parents like Agent.
I did it, here is the code
Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
XElement root = XElement.Load(filePath);
IEnumerable<XElement> xElements =
from element in root.Elements("Contact") select element;
foreach (XElement el in xElements.Descendants().Where(p => !p.HasElements))
{
int keyInt = 0;
string keyName = el.Name.LocalName;
while (keyValuePairs.ContainsKey(keyName))
{
keyName = $"{el.Name.LocalName}_{keyInt++}";
}
keyValuePairs.Add(keyName, el.Value);
}
Using xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
//using a list
Dictionary<string, List<XElement>> appData1 = doc.Root.Elements()
.GroupBy(x => x.Name.LocalName, y => y)
.ToDictionary(x => x.Key, y => y.ToList());
//not using a list
Dictionary<string, XElement> appData2 = doc.Root.Elements()
.GroupBy(x => x.Name.LocalName, y => y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
}
}
}
At the moment I convert XmlDocument as string List but this is not a good solution becouse if I display it in ListBox this recive me inline string with all parameters and I need to display only of table then when it's checked send it Sql Server
I can't create helper class with properties because parameters can be added/delete dynamically. I don't know what the exact parameters will be in file
Here is example XML
<TechnologyTables>
<Tables>
<TA_ID>3102</TA_ID>
<TA_Name>AL000-01.50M-N2-S0</TA_Name>
<TA_MaterialID>1</TA_MaterialID>
<TA_ThicknessID>4</TA_ThicknessID>
<TA_IsActive>1</TA_IsActive>
<TA_ArchiveID>100</TA_ArchiveID>
<TA_IsArchive>0</TA_IsArchive>
<CL_IsActive>1</CL_IsActive>
<MP_Lens>200</MP_Lens>
<MP_Nozzle>4.0</MP_Nozzle>
<MP_Focal>-0.6</MP_Focal>
<MP_NozzleDist>1.5000000e+000</MP_NozzleDist>
<MP_GasStabilization>1</MP_GasStabilization>
<MP_SensitiveSensor>1</MP_SensitiveSensor>
<MP_SensitiveArea>2.5000000e+001</MP_SensitiveArea>
<GA_ID>1</GA_ID>
<GP_ID>0</GP_ID>
<GP_FlushOn>1</GP_FlushOn>
<GP_FlushTime>2000</GP_FlushTime>
<GP_FlushPressure>1.0000000e+001</GP_FlushPressure>
<GP_FeedbackOn>1</GP_FeedbackOn>
<GP_FeedbackTime>0</GP_FeedbackTime>
<GP_FeedbackPressure>1.0000000e-001</GP_FeedbackPressure>
<GP_MaxPressure>1.0000000e+001</GP_MaxPressure>
<GP_ContinueOn>0</GP_ContinueOn>
<GP_ContinueTime>0</GP_ContinueTime>
<TA_Jerk>100</TA_Jerk>
<TA_Acceleration>100</TA_Acceleration>
<TA_CuttingTechID>3</TA_CuttingTechID>
<TA_FlyCut>1</TA_FlyCut>
<TA_HeadID>1</TA_HeadID>
<TA_MachineID>3</TA_MachineID>
<TA_TypeID>1</TA_TypeID>
<TT_HeadPowerID>7</TT_HeadPowerID>
<TA_CreateDate>2019-08-26T17:10:59.810</TA_CreateDate>
<Description>AL1.5 CATLINE</Description>
<TA_HeadTypeID>2</TA_HeadTypeID>
<CatlineFolder>1</CatlineFolder>
<NozzleNameID>10</NozzleNameID>
<LaserTypeID>1</LaserTypeID>
</Tables>
</TechnologyTables>
Some code when importing file
private async void _ImportTechTables()
{
var open = new OpenFileDialog();
var TableXml = new XmlDocument();
open.Filter = "xml files |*.xml";
if (open.ShowDialog() == DialogResult.OK)
{
TableXml.Load(open.FileName);
}
RSA rsaKey = GetKey();
DecryptXML(TableXml, rsaKey, "XmlKey");
if (TableXml != null)
{
var import = new TechnologyTableImportViewModel();
List<string> xmlNodeLists = new List<string>();
XmlNodeList node = TableXml.SelectNodes("TechnologyTables/Tables");
foreach (XmlNode nodes in node)
{
xmlNodeLists.Add(nodes.InnerXml);
}
import.List = xmlNodeLists;
And element in list look like this:
<Tables><TA_ID><Tables><TA_ID>3102</TA_ID><TA_Name>AL000-01.50M-N2<TA_Name>
I like using a dictionary and create dictionary using xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication137
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Dictionary<string, string> dict = doc.Descendants("Tables").FirstOrDefault().Elements()
.GroupBy(x => x.Name.LocalName, y => (string)y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
}
}
}
If you have multiple tables then use following :
List<Dictionary<string, string>> dict = doc.Descendants("Tables").Select(t => t.Elements()
.GroupBy(x => x.Name.LocalName, y => (string)y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault())
).ToList();
You can save the fields to a list this way, although I recommend using a dictionary for this kind of format.
var doc = XDocument.Parse(yourXmlFile);
var table = doc.XPathSelectElement("TechnologyTables/Tables");
var dict = new Dictionary<string, string>();
foreach (var element in table.Elements())
{
dict.Add(element.Name.LocalName, element.Value);
}
I have below XML.
<subscription>
<subscription_add_ons type="array">
<subscription_add_on>
<add_on_code>premium_support</add_on_code>
<name>Premium Support</name>
<quantity type="integer">1</quantity>
<unit_amount_in_cents type="integer">15000</unit_amount_in_cents>
<add_on_type>fixed</add_on_type>
<usage_percentage nil="true"></usage_percentage>
<measured_unit_id nil="true"></measured_unit_id>
</subscription_add_on>
</subscription_add_ons>
My XMLParse function
public XNode GetXmlNodes(XElement xml, string elementName)
{
List<string> addOnCodes= new List<string>();
//elementName = "subscription_add_ons ";
var addOns = xml.DescendantNodes().Where(x => x.Parent.Name == elementName).FirstOrDefault();
foreach (XNode addOn in addOns)
{
//Needed to do something like this
/*var len = "add_on_code".Length + 2;
var sIndex = addOn.ToString().IndexOf("<add_on_code>") + len;
var eIndex = addOn.ToString().IndexOf("</add_on_code>");
var addOnCode = addOn.ToString().Substring(sIndex, (eIndex - sIndex)).Trim().ToLower();
addOnCodes.Add(addOnCode);*/
}
As mentioned in comments by #JonSkeet, I updated my snippet as below.
var addOns = xml.Descendants(elementName).Single().Elements();
foreach (XNode addOn in addOns)
{
/*addon = {<subscription_add_on>
<add_on_code>premium_support</add_on_code>
<name>Premium Support</name>
<quantity type="integer">1</quantity>
<unit_amount_in_cents type="integer">15000</unit_amount_in_cents>
<add_on_type>fixed</add_on_type>
<usage_percentage nil="true"></usage_percentage>
<measured_unit_id nil="true"></measured_unit_id>
</subscription_add_on>} */
//how to get the addOnCode node value ?
var addOnCode = string.Empty;
addOnCodes.Add(addOnCode);
}
But what I need is from the passed XML, get all the nodes of type subscription_add_on then get the value contained in add_on_code & add it to string collection.
Or in general get the value of node by passing type ? Tried with the available methods coming from VS Intellisense but not getting the exact method that can do this?
Thanks!
Here is solution with Xml Linq (XDOCUMENT) :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication107
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var results = doc.Descendants("subscription_add_on").Select(x => new
{
add_on_code = (string)x.Element("add_on_code"),
name = (string)x.Element("name"),
quantity = (int)x.Element("quantity"),
amount = (int)x.Element("unit_amount_in_cents"),
add_on_type = (string)x.Element("add_on_type")
}).ToList();
}
}
}
I have dozend of XML filed in the following format (short sample):
<namespace name="Colors">
<green>
<en>Green</en>
<de>Gruen</de>
</green>
<blue>
<en>Blue</en>
<de>Blau</de>
</blue>
<namespace name="Subcolors">
<perlwhite>
<en>Perl White</en>
<de>Perlweis</de>
</perlwhite>
<racingblack>
<en>Racing Black</en>
<de>Rennschwarz</de>
</racingblack>
</namespace>
</namespace>
And i have to extract all the language tags and output them into a csv file in this format:
en;de;
Green;Gruen;
Blue;Blau;
Perl White;Perlweiß;
Racing Black;Renn Schwarz;
Then, I give this CSV file away for translation. After translation, there is a new language added to the CSV file, french for example:
en;de;fr;
Green;Gruen;Vert;
Blue;Blau;Bleu;
Perl White;Perlweiß;Perl Blanc;
Racing Black;Rennschwarz;Courses Noir;
Then i need to read this csv file in again, and append all tags to all the corresponding xml-files, like so:
<namespace name="Colors">
<green>
<en>Green</en>
<de>Gruen</de>
<fr>Vert</fr>
</green>
<blue>
<en>Blue</en>
<de>Blau</de>
<fr>Bleu</fr>
</blue>
<namespace name="Subcolors">
<perlwhite>
<en>Perl White</en>
<de>Perlweis</de>
<fr>Perl Blanc</fr>
</perlwhite>
<racingblack>
<en>Racing Black</en>
<de>Renn Schwarz</de>
<fr>Courses Noir</fr>
</racingblack>
</namespace>
</namespace>
And namespaces or other nodes(not listed here, like "multicolor", "colored" and many more) can be nested more then once. Not every file contains every node. And not every node is nested the same way in each xml file. Thats different from file to file. But at the end, each branch ends with couple of language tags. And these need to be read and updated.
So an xml file can look like this:
<namespace name="Colors">
<green>
<en>Green</en>
<de>Gruen</de>
</green>
<blue>
<en>Blue</en>
<de>Blau</de>
</blue>
<namespace name="Subcolors">
<perlwhite>
<en>Perl White</en>
<de>Perlweis</de>
</perlwhite>
<racingblack>
<en>Racing Black</en>
<de>Rennschwarz</de>
</racingblack>
<colored>
<namespace name="Misc">
<fruits>
<apple>
<de>Apfel</de>
<en>Apple</en>
</apple>
<orange>
<de>Orange</de>
<en>Orange</en>
</orange>
</fruits>
<vegetables>
<cucumber>
<en>Cucumber</en>
<de>Gurke</de>
</cucumber>
</vegetables>
<namespace name="Other">
<othertag>
<entry>
<en>Entry</en>
<de>Eintrag</de>
</entry>
</othertag>
</namespace>
</namespace>
</colored>
</namespace>
</namespace>
So not every xml file is the same, and there are different nodes with different tag names differenty nested. But every branch ends with language tags.
Can somebody help me to do this in a simple way with C#?. Maybe two simple functions like Import(readCsvPath, appendXmlPath) and Export(readXmLPath, writeCsvPath).
The code basically work with issues. The original xml has perlwhite, but the new csv has Perl-White. How do you know where to put the dash. I converted the small p to upper P but do not know where to put the dash.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication103
{
class Program
{
const string INPUT_XML = #"c:\temp\test.xml";
const string OUTPUT_CSV = #"c:\temp\test.csv";
const string INPUT_CSV = #"c:\temp\test2.csv";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(INPUT_XML);
var colorsWithDuplicates = doc.Descendants("namespace")
.SelectMany(ns => ns.Elements()
.SelectMany(color => color.Elements().Select(y => new {color = color.Name.LocalName, language = y.Name.LocalName, value = (string)y}))
).ToList();
var colors = colorsWithDuplicates.GroupBy(x => new object[] { x.color, x.language }).Select(x => x.First()).ToList();
var sortedAndGrouped = colors.OrderBy(x => x.language).ThenBy(x => x.color).GroupBy(x => x.color).ToList();
List<string> countries = sortedAndGrouped.FirstOrDefault().Select(x => x.language).ToList();
StreamWriter writer = new StreamWriter(OUTPUT_CSV, false, Encoding.Unicode);
writer.WriteLine(string.Join(",",countries));
foreach (var color in sortedAndGrouped)
{
writer.WriteLine(string.Join(";",color.Select(x => x.value)));
}
writer.Flush();
writer.Close();
StreamReader reader = new StreamReader(INPUT_CSV);
List<string> newCountries = reader.ReadLine().Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();
string line = "";
Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>();
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
List<string> splitLine = line.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();
dict.Add(splitLine[0], splitLine);
}
//now replace colors
foreach (XElement xNs in doc.Descendants("namespace"))
{
string name = (string)xNs.Attribute("name");
if((name == "Colors") || (name == "Subcolors"))
{
foreach (XElement xColor in xNs.Elements())
{
if (xColor.Name.LocalName != "namespace")
{
string checkColor = xColor.Name.LocalName;
checkColor = (string)xColor.Element("en"); // use english name
if (checkColor != null)
{
List<string> inputColors = dict[checkColor];
for (int index = 0; index < inputColors.Count; index++)
{
XElement country = xColor.Element(newCountries[index]);
if (country == null)
{
xColor.Add(new XElement(newCountries[index], inputColors[index]));
}
}
}
}
}
}
else
{
foreach (XElement group in xNs.Elements())
{
foreach(XElement xColor in group.Elements())
{
string checkColor = xColor.Name.LocalName;
checkColor = char.ToUpper(checkColor[0]) + checkColor.Substring(1);
if (checkColor != null)
{
List<string> inputColors = dict[checkColor];
for (int index = 0; index < inputColors.Count; index++)
{
XElement country = xColor.Element(newCountries[index]);
if (country == null)
{
xColor.Add(new XElement(newCountries[index], inputColors[index]));
}
}
}
}
}
}
}
}
}
}
For importing an XML to CSV file you can use folloiwng code, which is not long and easy:
XmlDocument xml = new XmlDocument();
// xmlContent contains your XML file
xml.LoadXml(xmlContent);
// get collections of nodes representing translations in particular languages
var enNodes = xml.GetElementsByTagName("en");
var deNodes = xml.GetElementsByTagName("de");
string[] lines = new string[enNodes.Count];
for (int i = 0; i < enNodes.Count; i++)
lines[i] = $"{enNodes[i].InnerText},{deNodes[i].InnerText}";
File.WriteAllLines(#"path to text file", lines);
The other way, CSV to XML require much more coding as you will have to detect every node to translate and add another node representing new language. This requires much more coding and is too broad for an answer - you have to write some code yourself first, then come back with more precise question about problem you would have.
Good luck.
Here is a piece of code:
XNamespace z = "#SomeSchema";
var listCols = new HashSet<Col>();
var colNameList = new List<string>(..some values..);
var xElementList = doc.Descendants(z + "row");
return new HashSet<Row>(xElementList .Select(x=> new Row
{
Col= new List<Col>(listCols).Select(col =>
{
col.Value= (string)x.Attribute(colNameList.First(colName=> colName == col.Name));
return col;
}).ToList()
}));
What is wrong is that, the return value contains a List of Row, but all of these rows have the exact same value (for the Col Value).
Ex, Row[1].Col[1].Value == Row[2].Col[2].Value
And these values should be completly different. I am obtaining those values from an Xml file. When I debug the xElementList, values are différents, but when I try to create rows with them, all rows are the same.
Actually, the Rows have the same Columns list, which is the last record of the xElementList.
Am I doing something wrong?
Thank you.
See code below. I read the xml twice. Once to get the columns names and add columns to table. Then read xml 2nd time to get row data.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
DataTable dt = new DataTable();
StreamReader sReader = new StreamReader(FILENAME, Encoding.GetEncoding(1252));
XmlReader reader = XmlReader.Create(sReader);
Dictionary<string, string> colDict = new Dictionary<string, string>();
while (!reader.EOF)
{
if (reader.Name != "FIELD")
{
reader.ReadToFollowing("FIELD");
}
if (!reader.EOF)
{
XElement field = (XElement)XElement.ReadFrom(reader);
string attrname = (string)field.Attribute("attrname");
string fieldtype = (string)field.Attribute("fieldtype");
switch (fieldtype)
{
case "string":
dt.Columns.Add(attrname, typeof(string));
break;
case "i4":
dt.Columns.Add(attrname, typeof(int));
break;
}
colDict.Add(attrname, fieldtype);
}
}
reader.Close();
sReader = new StreamReader(FILENAME, Encoding.GetEncoding(1252));
reader = XmlReader.Create(sReader);
while (!reader.EOF)
{
if (reader.Name != "ROW")
{
reader.ReadToFollowing("ROW");
}
if (!reader.EOF)
{
XElement row = (XElement)XElement.ReadFrom(reader);
DataRow newRow = dt.Rows.Add();
foreach (XAttribute attrib in row.Attributes())
{
string colName = attrib.Name.LocalName;
if (colDict.ContainsKey(colName))
{
switch (colDict[colName])
{
case "string":
newRow[colName] = (string)attrib;
break;
case "i4":
newRow[colName] = (int)attrib;
break;
}
}
}
}
}
}
}
}