2

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?

HollowDev
  • 63
  • 5

1 Answers1

1

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
David Browne - Microsoft
  • 80,331
  • 6
  • 39
  • 67
  • So I get the following error: 'IEnumerable' does not contain a definition for 'ToHashSet' and no accessible extension method 'ToHashSet' accepting a first argument of type 'IEnumerable' could be found (are you missing a using directive or an assembly reference?) on "...e.Elements("country").Select(p => (int)p).ToHashSet()" – HollowDev Jan 15 '21 at 11:31
  • I using .NET 3.5, btw - Mighn't be available in this version? – HollowDev Jan 15 '21 at 11:45
  • I do not thing xml linq (XDocument) library is in Net 3.5. – jdweng Jan 15 '21 at 13:17
  • LINQ to XML is available in .NET 3.5 https://learn.microsoft.com/en-us/dotnet/api/system.xml.linq.xdocument?view=netframework-3.5 `Enumerable.ToHashSet()` is newer. – David Browne - Microsoft Jan 15 '21 at 14:48
  • 1
    See updated answer for a .NET 3.5 compatible version. – David Browne - Microsoft Jan 15 '21 at 14:54