Parse generic XML string using C# - c#

suppose I have the following XML string:
<?xml version="1.0" encoding="utf-8" ?>
<items>
<item1>value1</item1>
<item2>value2</item2>
<item3>value3</item3>
<item4>value4</item4>
<item5>value5</item5>
<item6>value6</item6>
</items>
I need to parse it in a generic way as it may be updated later, and I don't need to modify my code accordingly.
So I have tried the following:
public static Dictionary<string, string> Parser(string xmlString)
{
Dictionary<string, string> parserDictionary = new Dictionary<string, string>();
using (StringReader stringReader = new StringReader(xmlString))
using (XmlTextReader reader = new XmlTextReader(stringReader))
{
// Parse the file and display each of the nodes.
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
parserDictionary.Add(reader.Name, reader.ReadString());
break;
}
}
}
return parserDictionary;
}
This code have 2 issues:
It parse the <items> element with null value, I don't need to
parse it
it ignores <item1>
please advise

Why not something like this:
var parserDictionary = XDocument.Create(xmlString)
.Descendants("items")
.Elements()
.Select(elem => new { Name = elem.Name.LocalName, Value = elem.Value })
.ToDictionary(k => k.Name, v => v.Value);
You could probably even do this:
var parserDictionary = XDocument.Create(xmlString)
.Descendants("items")
.Elements()
.ToDictionary(k => k.Name.LocalName, v => v.Value);

If you need to convert XML to an object representation than that's trivially easy
XDocument xDoc = XDocument.Parse(xmlString);
That's really all you need to do. Once you do that, you can query your xDoc with the Elements, Element, Attribute, Attributes and Descendants Properties.
For an example, here's some code that will print all of your values
XDocument xDoc = XDocument.Parse(xmlString);
foreach(XElement e in xDoc.Elements())
{
Console.WriteLine(e.Value);
}

Related

Convert XML String API response to a key-value Object C#

I am receiving a XML strings from and API, and would like to convert these to C# objects key-value in order to handle these values also apply some asserts.
The messages are of the form string format:
<?xml version="1.0" encoding="UTF-8"?>
<ReportData>
<ProjectName>Test Data</ProjectName>
<Unit>Unit 1</Unit>
<ReportLabel.Cost>394</ReportLabel.Cost>
</ReportData>
After i get the string API response i am trying to deserialize the XMl like this where responseAPI is the xml above:
XmlDocument doc = new XmlDocument();
using (var reader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(responseAPI), XmlDictionaryReaderQuotas.Max))
{
XElement xml = XElement.Load(reader);
doc.LoadXml(xml.ToString());
}
At this point i have and xml but i can not get a key-value object.
i am trying
var jsonText = JsonConvert.SerializeXmlNode(doc);
or
serializer = new XmlSerializer(typeof(Object));
using (TextReader reader = new StringReader(responseAPI))
{
var result = (Object)serializer.Deserialize(reader);
}
or
var response = JsonConvert.DeserializeObject<Dictionary<string, object>>(responseAPI);
I am new to with this kind of response in XML and am not sure the way to performing this. It is not as easy as JSON format.
You can use System.Xml.Linq for this task.
Here is one way to create a dictionary from the XML:
static void Main(string[] args)
{
// or use other overload of the Load() method if the XML is not comes from a file stream, uri etc...
var xmldoc = System.Xml.Linq.XDocument.Load("YOUR FILE PATH");
Dictionary<string, string> XMLKeyval = new Dictionary<string, string>();
foreach (var name in xmldoc.Descendants("ReportData").Elements()
.Select(x => new { Name = x.Name, Value = x.Value }).Distinct())
{
XMLKeyval.Add(name.Name.LocalName, name.Value);
}
// Output
foreach (KeyValuePair<string, string> itm in XMLKeyval)
{
Console.WriteLine(itm.Key + ": " + itm.Value);
}
Console.ReadLine();
}
You can not directly convert xml to a dict of key value pair, Instead we need to iterate through each node in xml and add it as a key value pair to a dict object.
please refer Converting an XML-document to a dictionary

Parsing XML element to get value of an element

I have the following XML
<?xml version="1.0" encoding="UTF-8"?> <i18nText><Country code="DE" language="de" text="nach Datum" /><Country code="US" language="en" text="by Date" /></i18nText>
I'm trying to get the value of the text element.There can be different values based on the language element.
How can i populate it into a dictionary ie: value of text for each language .
XmlDocument doc = new XmlDocument();
doc.LoadXml("<?xml version=\"1.0\" encoding=\"UTF-8\"?> <i18nText><Country code=\"DE\" language=\"de\" text=\"nach Datum\" /><Country code=\"US\" language=\"en\" text=\"by Date\" /></i18nText>");
XmlNodeList countries = xDoc.GetElementsByTagName("Country");
Dictionary<string, string> dict = new Dictionary<string, string>();
for (int i = 0; i < countries.Count; i++)
{
dict.Add(countries[i].Attributes["language"]?.InnerText, countries[i].Attributes["text"]?.InnerText);
}
var languageToText = XDocument
.Parse(content)
.Descendants("Country")
.Select(p => new
{
language = p.Attribute("language"),
text = p.Attribute("text")
})
.ToDictionary(
p => p.language,
p => p.text);
I would use Linq to Xml, it's more declarative and easier to read than using loops.
using System.Linq;
using System.Xml.Linq;
var xml = #"<?xml version=""1.0"" encoding=""UTF - 8""?> <i18nText><Country code=""DE"" language=""de"" text=""nach Datum"" /><Country code=""DE"" language=""de"" text=""nach Datum"" /><Country code=""US"" language=""en"" text=""by Date"" /></i18nText>";
var doc = XDocument.Parse(xml);
var dic = (from country in doc.Root.Elements()
select new { language=country.Attribute("language").Value, text=country.Attribute("text").Value }).
Distinct().
ToDictionary(country => country.language, country => country.text);

Convert Xml document to C# Dictionary

I make a request to a service and receive an xml response as shown below. However, I'm trying to store the response values in a Dictionary (or store the values returned in variables) and I can't seem to make it work.
Any help would be greatly appreciated.
xml response received:
<?xml version="1.0"?>
<ncresponse NCERRORPLUS="!" BRAND="ABC" PM="CC" currency="GBP" amount="10" STATUS="9" ACCEPTANCE="test123" NCERROR="0" NCSTATUS="0" PAYID="39409494" orderID="92E5CE91">
</ncresponse>
c# code:
try
{
// Write data
using (Stream postStream = request.GetRequestStream())
{
postStream.Write(byteData, 0, byteData.Length);
}
// Get response
Dictionary<string, string> respValues = new Dictionary<string, string>();
try
{
string body = String.Empty;
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("iso-8859-1"));
body += reader.ReadToEnd();
}
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(body);
XmlNodeList list = xmlDoc.GetElementsByTagName("ncresponse");
string xmlResponse = list[0].InnerText;
}
catch (WebException wex)
{
throw;
}
Use this:
using System.Xml.Linq; // required namespace for linq-to-xml
/* ... get xml into 'body' string */
XDocument doc = XDocument.Parse(body);
to load the XML file into an XDocument object.
Then, you can use Linq-to-XML to parse the XML and ToDictionary extension method to create a key / value pair for each attribue of the XML:
var output = doc.Element("ncresponse")
.Attributes()
.Select(c => new {
Key = c.Name,
Value = c.Value
})
.ToDictionary(k => k.Key, v => v.Value);
It seems I overcomplicated things (credit goes to #KyleW). This:
var output = doc.Element("ncresponse")
.Attributes()
.ToDictionary(k => k.Name, v => v.Value);
is equivalent to the inital linq query. Select is only necessary only in case some pre-processing of the values placed in the dictionary is required.
Ouput:
[0] = {[NCERRORPLUS, !]}
[1] = {[BRAND, ABC]}
[2] = {[PM, CC]}
... etc
I needed to solve a similar problem, but my issue was a bit more complicated. The XML document could have any number of child collections, and collections within collections. Each node was guaranteed to have a unique name. I used the following code to place it into a dictionary. A recursive function is used to parse each XElement into the dictionary, or parse any child elements it might have.
private static void RecParseXDoc(XElement element, Dictionary<string, string> xDict)
{
if (element.HasElements)
{
foreach (var childElement in element.Elements())
{
RecParseXDoc(childElement, xDict);
}
}
xDict.Add(element.Name.ToString(), element.Value);
}
We can then initiate the parse like so:
var outputDict = new Dictionary<string, string>();
foreach (var element in xDoc.Root.Elements())
{
RecParseXDoc(element, outputDict);
}
If your XML might have duplicate node names, you can do a .TryGetValue prior to adding the element to the dictionary.
I'm leaving this answer here on the chance others with the issue of child elements finds your question.

Get node property of XmlDocument in C#

I'm using this xml structure:
<park>
<car title="Ferrari" available="true">
<url>http://www.ferrari.com/</url>
</rss>
</park>
And this is my code in C#:
XmlDocument doc = new XmlDocument();
doc.Load("Settings.xml");
XmlNodeList list = doc.SelectNodes("/park/car");
foreach (XmlNode item in list)
{
string x = item["#title"].InnerText;
}
I just want to get "title" property but i can't get it working. I'm using "#" but without success.
Try this code:
string x = item.Attributes["title"].Value;
I suggest you to use LINQ to XML for parsing xml:
var xdoc = XDocument.Load("Settings.xml");
var titles = xdoc.XPathSelectElements("//park/car")
.Select(c => (string)c.Attribute("title"));
Or without XPath:
var titles = xdoc.Descendants("park")
.Elements("car")
.Select(c => (string)c.Attribute("title"));

How can I rewrite this Linq to XML query?

I am preferring LINQ to XML over XMLReader because it feels much easier to use. However, I know I'm doing it wrong somewhere. I'm not looking for faster execution or anything, just a cleaner rewrite. I can't tell if it'll fit cleanly into the from foo in bar where foo is some condition form, but there's got to be a cleaner way.
I am not using anonymous objects here and instead outputting as strings because I am excluding some code which will adapt the data into existing objects - however, it is kind of a messy structure currently which I need to refactor.
My XML looks like this.
<?xml version="1.0" encoding="utf-8" ?>
<entity name="Something">
<Component type="RenderComponent">
<Material type="string">fur</Material>
<Reflectiveness type="int">678</Reflectiveness>
</Component>
<Component type="HealthComponent">
<Sound type="int">60</Sound>
</Component>
</entity>
And my code:
static void Main(string[] args)
{
XDocument xdoc = XDocument.Load(#"..\..\XMLFile1.xml");
List<string> comNames = new List<string>();
Dictionary<string, string> paramValues = new Dictionary<string, string>();
List<string> paramTypes = new List<string>();
foreach (XElement e in xdoc.Root.Elements("Component"))
{
string type = e.Attribute("type").Value;
foreach(XElement param in e.Elements())
{
paramValues.Add(param.Name.LocalName, param.Value);
paramTypes.Add(param.Attributes().First().Value);
}
Console.WriteLine(" \n\n\n");
comNames.Add(type);
}
}
Giving outputs of:
comNames - RenderComponent, HealthComponent
paramValues - (Material, fur), (Reflectiveness, 678), (Sound, 60)
paramTypes - string, int, int
If it clears it up somewhat, the general layout of the file:
Root node entity with a name attribute (forgot in this example)
n Component nodes with type attributes
Each Component node has a number of child nodes which have names, a type attribute, and a value.
I think, you can do something like this:
XDocument xdoc = XDocument.Load(#"..\..\XMLFile1.xml");
var data =
xdoc.Root.Elements("Component")
.SelectMany(e => new
{
type = e.Attribute("type").Value,
paramValues = e.Elements()
.Select(x => new KeyValuePair<string,
string>
(x.Name.LocalName,
x.Value)),
paramType = e.Elements()
.Select(x => x.Attributes().First()
.Value)
});
List<string> comNames = data.Select(x => x.type).ToList();
List<string> paramTypes = data.Select(x => x.paramType).ToList();
Dictionary<string, string> paramValues = data.Select(x => x.paramValues)
.ToDictionary(x => x.Key,
x => x.Value);
But honestly, I think your original code is just fine.

Categories

Resources