XML to List - Unable to add all nodes to list

Viewed 60

I have two XML documents:

XmlDocument languagesXML = new XmlDocument();
languagesXML.LoadXml(
       @"<languages>
           <language>
           <name>English</name>
           <country>8</country>
           <country>9</country>
           <country>3</country>
           <country>12</country>
          </language>
          <language>
            <name>French</name>
            <country>1</country>
            <country>3</country>
            <country>7</country>
            <country>13</country>
           </language>
         </languages>");

        XmlDocument productsXML = new XmlDocument();
        productsXML.LoadXml(@"<products>
              <product>
                <name>Screws</name>
                <country>3</country>
                <country>12</country>
                <country>29</country>
              </product>
              <product>
                <name>Hammers</name>
                <country>1</country>
                <country>13</country>
              </product>
            </products>");

I am trying to add the relative information, such as name and country of each language and product, to a list as I want to compare the two and group the languages that correspond to a certain language. For example, taking the above into account, my goal is to have an output similar to this:

Screws -> English, French
Hammers -> French

English and French correspond to Screws as they all share a common country value. Same with Hammers. (The above XML is just a snapshot of the entire XML).

I have tried using How to read a XML file and write into List<>? and XML to String List. While this piece of code:

var languages = new List<string>();
XmlNode xmlNode;

foreach(var node in languagesXML.LastChild.FirstChild.ChildNodes)
{
     xmlNode = node as XmlNode;
     languages.Add(xmlNode.InnerXml);
}

languages.ForEach(Console.WriteLine);

works, it will only add "English", "8", "9", "3", and "12" to the list. The rest of the document seems to be ignored. Is there a better way of doing what I'm trying to achieve? Would I even be able to compare and attain an output like what I need even if I got everything adding to a list? Would Muenchian grouping be something I should be looking at?

1 Answers

This is a job for LINQ to XML. Eg

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace ConsoleApp18
{
    static class EnumerableUtils
    {
        public static HashSet<T> ToHashSet<T>(this IEnumerable<T> col)
        {
            return new HashSet<T>(col);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            XDocument languagesXML = XDocument.Parse(
                   @"<languages>
           <language>
           <name>English</name>
           <country>8</country>
           <country>9</country>
           <country>3</country>
           <country>12</country>
          </language>
          <language>
            <name>French</name>
            <country>1</country>
            <country>3</country>
            <country>7</country>
            <country>13</country>
           </language>
         </languages>");

            var languages = languagesXML.Root
                                        .Elements("language")
                                        .Select(e =>
                                           new
                                           {
                                               Name = (string)e.Element("name"),
                                               Countries = e.Elements("country").Select(c => (int)c).ToHashSet()
                                           })
                                        .ToList();



            XDocument productsXML = XDocument.Parse(@"<products>
              <product>
                <name>Screws</name>
                <country>3</country>
                <country>12</country>
                <country>29</country>
              </product>
              <product>
                <name>Hammers</name>
                <country>1</country>
                <country>13</country>
              </product>
            </products>");

            var products = productsXML.Root
                                      .Elements("product")
                                      .Select(e =>
                                       new
                                       {
                                           Name = (string)e.Element("name"),
                                           Countries = e.Elements("country").Select(c => (int)c).ToHashSet()
                                       })
                                      .ToList();
            var q = from p in products
                    from l in languages
                    where p.Countries.Overlaps(l.Countries)
                    let pl = new { p, l, }
                    group pl by p.Name into byProductName
                    select new
                    {
                        ProductName = byProductName.Key,
                        Languages = byProductName.Select(e => e.l.Name).ToList()
                    };

            foreach (var p in q.ToList())
            {
                Console.WriteLine($"Product: {p.ProductName} is available in languages: {String.Join(",", p.Languages.ToArray())}");
            }



        }
    }
}

outputs

Product Screws is available in languages English,French
Product Hammers is available in languages French
Related