Convert Xml to Dictionary

I have a XML document that has many nodes, with children nodes and grandchildren nodes. I need to output all nodes into a NameValueCollection or Dictionary using C#.

The Xml looks like this:

<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<ePolicy>
   <company_code>555</company_code>
   <details>
      <name>John</name>
   </details>
   <owner_info>
      <owners_name>
         <first>Edward</first>
         <last>Smith</last>
      </owners_name>
   </owner_info>
</ePolicy>

The following seems to work for nodes that are direct children of the root node (ePolicy), but for grandchild nodes, it just combines them all into a single value.

Here's the output I'm getting:

company_code, 555
details, John
owner_info, EdwardSmith

The above XML is a sample from URLstring variable below:

qsCollection = new System.Collections.Specialized.NameValueCollection();
            XmlTextReader reader = new XmlTextReader(URLstring);
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(reader);

            XmlNodeList nodeList = xmlDoc.SelectNodes("ePolicy");

            foreach (XmlElement node in xmlDoc.DocumentElement)
            {
                qsCollection.Add(node.Name, node.InnerText);
            }

Open in new window

LVL 8
pzozulkaAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Fernando SotoRetiredCommented:
In the XML you showed in your question is that the extent of the XML document or are there many company_code and this is just one of them. Will the XML document always represent one entity?
pzozulkaAuthor Commented:
It will always represent one entity.
Fernando SotoRetiredCommented:
Hi pzozulka;

Seeming there is only one entity in the XML why don't you create a class to hold the parsed XML values. like shown below.

using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;

XmlTextReader reader = new XmlTextReader(URLstring);
XDocument xdoc = XDocument.Load(reader);

XElement root = xdoc.Root;
 
EPolicy epolicy = new EPolicy()
{
    CompanyCode = root.XPathSelectElement("./company_code").Value,
    DetailName = root.XPathSelectElement("./details/name").Value,
    OwnerFirstName = root.XPathSelectElement("owner_info/owners_name/first").Value,
    OwnerLastName = root.XPathSelectElement("owner_info/owners_name/last").Value
};

// A class to hold the parsed data from the XML data
public class EPolicy
{
    public string CompanyCode { get; set; }
    public string DetailName { get; set; }
    public string OwnerFirstName { get; set; }
    public string OwnerLastName { get; set; }
}

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Become a Certified Penetration Testing Engineer

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

pzozulkaAuthor Commented:
Primarily because it is a lot of work because the XML file has over 50 elements, and to populate them all manually would be a lot of work.

Plus, there exists an entire mechanism in place that handles a lot of stuff, only if I pass it a NameValueCollection.
louisfrCommented:
You don't want the child nodes to be combined into a single value. How do you want them to be handled?
pzozulkaAuthor Commented:
I would like each and every mode, whether it's a parent, chikd, or grandchild node to be treated all the same and just be loaded into a collection.
pzozulkaAuthor Commented:
So for this XML below, one possible collection can be:

ePolicy, <company_code>...</owner_info>
company_code, 555
details, <name>John</name>
name, John
owner_info, <first>Edw...</owner_info>
owners_name, <first>Edwar...</owners_name>
first, Edward
last, Smith

<ePolicy>
   <company_code>555</company_code>
   <details>
      <name>John</name>
   </details>
   <owner_info>
      <owners_name>
         <first>Edward</first>
         <last>Smith</last>
      </owners_name>
   </owner_info>
</ePolicy>
pzozulkaAuthor Commented:
Another possible solution that I thought of could be to do this recursively. In other words, call a method called printNode, inside check if node has children, if so, call printNode method on child nodes all the way till you reach the final child nodes. Then recurse your way out.

I just figured there would be some existing way to print out all nodes.

My goal is to later on be able to use my collection to retrieve any mode from the original XML doc, even child nodes.
louisfrCommented:
Your first possibility :

ePolicy, <company_code>...</owner_info>
company_code, 555
details, <name>John</name>
name, John
owner_info, <first>Edw...</owner_info>
owners_name, <first>Edwar...</owners_name>
first, Edward
last, Smith

That's the easiest:
qsCollection = new System.Collections.Specialized.NameValueCollection();
XmlTextReader reader = new XmlTextReader(URLstring);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(reader);

XmlNodeList nodeList = xmlDoc.SelectNodes("//*");

foreach (XmlElement node in nodeList)
{
    qsCollection.Add(node.Name, node.InnerXml);
}

Open in new window

louisfrCommented:
Second possibility, recursive:
static Dictionary<string, object> GetNodes(XmlNode e)
{
    Dictionary<string, object> newdic = new Dictionary<string, object>();
    foreach (XmlNode child in e.ChildNodes)
    {
        var text = child.FirstChild as XmlText;
        if (text == null)
            newdic.Add(child.Name, GetNodes(child));
        else
            newdic.Add(child.Name, text.Value);
    }
    return newdic;
}

Open in new window

You call this like that:
XmlTextReader reader = new XmlTextReader(URLstring);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(reader);
qsCollection = GetNodes(xmlDoc.DocumentElement);

Open in new window

pzozulkaAuthor Commented:
If using the easiest way, what if my entity has to XML elements that are the same element name. For example, <street> below. How do you retrieve it from the collection? Perhaps this question is the same for all the solutions listed above, not just the easiest.

<ePolicy>
        <residence_address>
            <street>123 Main St</street>
            <city>New York</city>
            <state>NY</state>
            <zip>12345</zip>
      </residence_address>
      <alternate_mailing_address>
            <street>21 Jump St</street>
            <city>New York</city>
            <state>NY</state>
            <zip>55555</zip>
      </alternate_mailing_address>
</ePolicy>
louisfrCommented:
The NameValueCollection handles duplicate keys by concatenating all the values, separating them with commas.
Your "street" value would be "123 Main St,21 Jump St"
Fernando SotoRetiredCommented:
Hi pzozulka;

If you pull the data out of the XML document there will be no mapping between the value and which <street> it belongs to. If it were still part of the XML then you could ask the <street> node who its parent is and it would respond with either  <alternate_mailing_address> or <residence_address> depending on which part of the XML it belongs to.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.