Extracting XML values in multidimensional array c# - c#

I have an xml file as below, and I need to extract values and put them inside a multidimensional array. The idea is, when I have more than one tag <string> per root element <Etiquette>, I need to repeat the same other values with each different value of the tag <string>
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfEtiquette xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Etiquette>
<BgColor>#8075D1C5</BgColor>
<BorderColor>#FF4E5B6F</BorderColor>
<AssociatedAffaireId>
<string>d4689f33-5600-47fe-883d-efcbf5e469c2</string>
<string>1bae35dd-d501-4d87-bdd4-147fc0ba29d2</string>
</AssociatedAffaireId>
<Label>Ouverte</Label>
</Etiquette>
<Etiquette>
<BgColor>#80949CA8</BgColor>
<BorderColor>#FF155E70</BorderColor>
<AssociatedAffaireId>
<string>203cc4a8-8c24-4a2d-837c-29c7c1f73007</string>
</AssociatedAffaireId>
<Label>Fermée</Label>
</Etiquette>
</ArrayOfEtiquette>
Desired result:
{"#8075D1C5","#FF4E5B6F","d4689f33-5600-47fe-883d-efcbf5e469c2","Ouverte"}
{"#8075D1C5","#FF4E5B6F","1bae35dd-d501-4d87-bdd4-147fc0ba29d2","Ouverte"}
{"#80949CA8","#FF155E70","203cc4a8-8c24-4a2d-837c-29c7c1f73007","Fermée"}
Regards,

Using Xml Linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication157
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var results = doc.Descendants("Etiquette")
.SelectMany(x => x.Descendants("string")
.Select(y => new { BgColor = (string)x.Element("BgColor"), BorderColor = (string)x.Element("BorderColor"), UID = (string)y }))
.ToList();
}
}
}
I you want just an array instead of anonymous type use :
new string[] { (string)x.Element("BgColor"), (string)x.Element("BorderColor"), (string)y }

You can try with XDocument
XDocument xdoc = XDocument.Load("XMLFile7.xml");
var mdAarray = xdoc.Descendants("Etiquette")
.SelectMany(etiquette =>
etiquette.Descendants("string")
.Select(associatedaffaire => new string[] {
etiquette.Element("BgColor").Value.ToString(),
etiquette.Element("BorderColor").Value.ToString(),
associatedaffaire.Value.ToString(),
etiquette.Element("Label").Value.ToString() }))
.ToArray();
Console.WriteLine(JsonConvert.SerializeObject(mdAarray));
OUTPUT
[
["#8075D1C5","#FF4E5B6F","d4689f33-5600-47fe-883d-efcbf5e469c2","Ouverte"],
["#8075D1C5","#FF4E5B6F","1bae35dd-d501-4d87-bdd4-147fc0ba29d2","Ouverte"],
["#80949CA8","#FF155E70","203cc4a8-8c24-4a2d-837c-29c7c1f73007","Fermée"]
]

you only need to iterate first on Etiquette then iterate again on AssociatedAffaireId
Each time you can insert inside the array or list (I will use list for simplicity)
XDocument xdoc = XDocument.Load("pathToXml.xml");
// iterate all Etiquette elements
foreach (var etiquette in xdoc.Root.Elements("Etiquette"))
{
// store common values
string bgColor = etiquette.Element("BgColor").Value;
string borderColor = etiquette.Element("BorderColor").Value;
string label = etiquette.Element("Label").Value;
// iterate all AssociatedAffaireId.string elements and add to list
var associatedAffaireIdEl = etiquette.Element("AssociatedAffaireId");
foreach (var associatedAffaireId in associatedAffaireIdEl.Elements("string"))
{
string aaid = associatedAffaireId.Value;
listOfArray.Add(new string[]{bgColor, borderColor, aaid, label});
}
}
I hope this could help.
Sorry I found some errors. Check out my fiddle here.

Related

Get Each Value on an XML Node

I have an XML that looks like this:
<HiddenTopicsValues TopicCodes="TopicValues">
<Topic>
<Code>topic_aboutme</Code>
<Value>1</Value>
</Topic>
<Topic>
<Code>topic_aboutyou</Code>
<Value>1</Value>
</HiddenTopicsValues>
My goal is to create a Dictionary that lets the <Code> act as the Key, and <Value> as the Value (of the Dictionary). I declared the dictionary as shown below:
Dictionary<string,int> dictionary_topics = new Dictionary<string,int>();
And used a for loop to iterate all the values in the XML:
// Load XML Document
XmlDocument xmlTopics = new XmlDocument();
xmlTopics.Load(path);
// Get All Hidden Topics
XmlNodeList ndTopics = xmlTopics.GetElementsByTagName("Topic");
for (int i = 0; i < ndTopics.Count; i++)
{
string _topicCode = ndTopics[i].InnerText[0].ToString();
int _topicValue = ndTopics[i].InnerText[1].ToString();
// Add Topic to Dictionary
dictionary_topics.Add(_topicCode, _topicValue);
}
I thought that this: ndTopics[i].InnerText[0] would return this: topic_aboutme
And this: ndTopics[0].InnerText[1] would return this: 1
Based on the given XML.
I tried displaying ndTopics[0].InnerText and it shows this:
topic_aboutme1
How can I separate the topic_aboutme(<Code>) and 1(<Value>)?
Forgive my naiveness, I'm not really used in utilising XML.
Real easy in 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);
Dictionary<string, string> dict = doc.Descendants("Topic")
.GroupBy(x => (string)x.Element("Code"), y => (string)y.Element("Value"))
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
}
}
}

Selecting the value of XML elements

I don't have much experience with XML files but I'm trying to append a tutorial I found online to suite my needs and I'm not getting the results I would expect.
https://support.microsoft.com/en-us/help/307548/how-to-read-xml-from-a-file-by-using-visual-c
I've searched around but everything I've found doesn't make sense to me.
My XML looks like this for the most part:
<US>
<!-- Kentucky Start -->
<State>Kentucky KY
<City>Newport
<Street>Pavilion Parkway<Number>130<PostalCode>41071</PostalCode></Number></Street>
</City>
<City>Corbin
<Street>Highway 90<Number>7351<PostalCode>40701</PostalCode></Number></Street>
</City>
</State>
</US>
I'm trying to populate a listbox with the value of each state but my code either returns white space or just the text within the XML tag
e.g.
State..
State..
repeated for each element.
while (reader.Read()) {
switch (reader.NodeType) {
case XmlNodeType.Element: // The node is an element.
// Skip over root element
if (reader.Name.Equals("US")) {
reader.MoveToNextAttribute();
}
else {
if(reader.Name.Equals("State")) {
lbState.Items.Add(reader.Name);
lbState.Items.Add(reader.Value);
}
}
break;
reader.Name returns "State"
reader.Value returns "Whitespace"
I don't understand why reader.Value does not return Kentucky KY...
I've seen other examples that use string builder, is this a bad approach?
Use reader.ReadString() instead of reader.Value
Try xml linq :
sing System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication2
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var results = doc.Descendants("State").Select(x => new {
cities = x.Elements("City").Select(y => new {
state = (string)x,
city = (string)y,
streets = y.Elements("Street").Select(z => (string)z).ToList()
}).ToList()
}).SelectMany(x => x.cities).ToList();
}
}
}
You can use XmDocument (see: https://msdn.microsoft.com/en-us/library/system.xml.xmldocument(v=vs.110).aspx) and then use an xpath expression to get the right elements from your document:
Also it is better to encapsulate the name of the state (that is, if you own the xml document) like this:
<name>Kentucy KY</name>
So you can do the following:
var items = new List<string>();
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml("yourxml");
var xmlNodes = xmlDocument.SelectNodes("//State/Name");
foreach (XmlNode node in xmlNodes)
{
items.Add(xmlNode.Value);
}

Deserialize XML containing a Dictionary

I have an XML file containing identifiers that I would like Get, the xml look like
<Dictionary
x:TypeArguments="x:String, x:Object"
xmlns="clr-namespace:System.Collections.Generic;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<List x:TypeArguments="x:Int32" x:Key="key" Capacity="4">
<x:Int32>60371408</x:Int32>
<x:Int32>60371409</x:Int32>
</List>
</Dictionary>
The identifiers that I want to get is 60371408, 60371409
I just found a solution :
Thank you for your reaction :D
Create an XmlSerializer:
var serializer = new XmlSerializer(typeof(Dictionary<string, object>));
...then deserialize. You haven't specified what form this XML is in, whether you have a string or a stream, for example. Here's how you'd deserialize an XML string:
var reader = new StringReader(xml);
var dict = serializer.Deserialize(reader);
Now you have your Dictionary<string, object>, but since values are plain objects, you'll need to cast the values:
var list = (List<int>)dict["key"];
Try xml linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
public class Program
{
const string FILENAME = #"c:\temp\test.xml";
public static void Main()
{
XDocument doc = XDocument.Load(FILENAME);
XElement dictionary = doc.Descendants().Where(x => x.Name.LocalName == "Dictionary").FirstOrDefault();
XNamespace xNs = dictionary.GetNamespaceOfPrefix("x");
var results = dictionary.Descendants(xNs + "Int32").Select(x => (int)x).ToList();
}
}
}

Unable to get list from xml using xPathNavigator

List<string> list = new List<string>();
foreach (XPathNavigator node in nav.Select("configuration/company/work/worktime"))
{
string day = getAttribute(node, "day");
string time = getAttribute(node, "time");
string worktype = ?? // how to get worktype attribute valuefrom parent node
list.Add(day,time,worktype); // add to list
}
</configuration>
<company>
<work worktype="homeWork">
<worktime day="30" time="10:28"></worktime>
<worktime day="25" time="10:50"></worktime>
</work>
<work worktype="officeWork">
<worktime day="12" time="09:28"></worktime>
<worktime day="15" time="12:28"></worktime>
</work>
</company>
</configuration>
need output as :
list[0] = homeWork,30,10:28
list[1] = homeWork,25,10:50
list[2] = officeWork,12,09:28
list[3] = officeWork,15,12:28
I am trying to get the list from XML but failed to get output like given above (using xpath navigator, how can I access parent node to get worktype attribute, and other remaining inner node attribute?
I'd suggest using LINQ to XML over XPath, but if you must use XPathNavigator then you need to iterate each work element followed by each of its worktime child elements. This way you can use the worktype from the parent context:
foreach (XPathNavigator work in nav.Select("configuration/company/work"))
{
var workType = work.GetAttribute("worktype", string.Empty);
foreach (XPathNavigator worktime in work.Select("worktime"))
{
var day = worktime.GetAttribute("day", string.Empty);
var time = worktime.GetAttribute("time", string.Empty);
list.Add($"{workType}, {day}, {time}");
}
}
See this fiddle for a working demo.
Use a nested loop. Initially retrieve the work nodes with configuration/company/work. Retrieve the worktype attribute and store in a variable. Then loop through the child worktype nodes and add a string to the list for each one
Use Net Library enhanced xml (linq xml)
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);
var results = doc.Descendants("work").Select(x => new {
worktype = (string)x.Attribute("worktype"),
worktime = x.Elements("worktime").Select(y => new {
day = (int)y.Attribute("day"),
time = (DateTime)y.Attribute("time")
}).ToList()
}).ToList();
}
}
}

How to get an element that has : in its name?

I need to get the CountryName from this XML: http://api.hostip.info/?ip=12.215.42.19
The response XML is:
<HostipLookupResultSet version="1.0.1"
xmlns:gml="http://www.opengis.net/gml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.hostip.info/api/hostip-1.0.1.xsd">
<gml:description>This is the Hostip Lookup
Service</gml:description>
<gml:name>hostip</gml:name>
<gml:boundedBy>
<gml:Null>inapplicable</gml:Null>
</gml:boundedBy>
<gml:featureMember>
<Hostip>
<ip>12.215.42.19</ip>
<gml:name>Sugar Grove, IL</gml:name>
<countryName>UNITED STATES</countryName>
<countryAbbrev>US</countryAbbrev>
<!-- Co-ordinates are available as lng,lat -->
<ipLocation>
<gml:pointProperty>
<gml:Point srsName="http://www.opengis.net/gml/srs/epsg.xml#4326">
<gml:coordinates>-88.4588,41.7696</gml:coordinates>
</gml:Point>
</gml:pointProperty>
</ipLocation>
</Hostip>
</gml:featureMember>
</HostipLookupResultSet>
Problem is I can't include : in the Descendants method because it throws:
XmlException: The ':' chracater,
hexadecimal value 0x3A, cannot be
included in a name.
Thanks
try this
var descendants = from i in XDocument.Load(xml).Descendants("Hostip")
select i.Element("countryName");
Update
complete code for downloading the xml and finding the name of countryName
string xml;
using(var web = new WebClient())
{
xml = web.DownloadString("http://api.hostip.info/?ip=12.215.42.19");
}
var descendants = from i in XDocument.Parse(xml).Descendants("Hostip")
select i.Element("countryName");
A small example on how to apply namespaces in LINQ to XML:
XElement doc = XElement.Load("test.xml");
XNamespace ns = "http://www.opengis.net/gml";
var firstName = doc.Descendants(ns + "name").First().Value;
You need to reference the gml namespace; once you've done that you should be able to navigate using the tag names that appear to the right of "gml:"
UPDATE
I'm not sure what context you're applying this to, but here's a sample console app that works:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace LinqToXmlSample
{
class Program
{
static void Main(string[] args)
{
XElement x = XElement.Load("http://api.hostip.info/?ip=12.215.42.19");
foreach (XElement hostip in x.Descendants("Hostip"))
{
string country = Convert.ToString(hostip.Element("countryName").Value);
Console.WriteLine(country);
}
Console.ReadLine();
}
}
}
var gml = (XNamespace)"http://www.opengis.net/gml";
var doc = XDocument.Load(...) or XDocument.Parse(...);
var name = doc.Descendants(gml + "featureMember").Descendants("countryName").First().Value;
Or you could go brute force and strip all the namespaces:
void RemoveNamespace(XDocument xdoc)
{
foreach (XElement e in xdoc.Root.DescendantsAndSelf())
{
if (e.Name.Namespace != XNamespace.None)
{
e.Name = XNamespace.None.GetName(e.Name.LocalName);
}
if (e.Attributes().Any(a => a.IsNamespaceDeclaration || a.Name.Namespace != XNamespace.None))
{
e.ReplaceAttributes(e.Attributes().Select(a => a.IsNamespaceDeclaration ? null : a.Name.Namespace != XNamespace.None ? new XAttribute(XNamespace.None.GetName(a.Name.LocalName), a.Value) : a));
}
}
}

Categories

Resources