C#, слияние двух XML

Grunch
Дата: 04.04.2014 14:40:07
Здравствуйте!
Есть задача объеденить две xml с одинаковой структурой
1:
+
<?xml version="1.0" ?>
<menu>
<game name="123" index="" images="">
<description>123</description>
<cloneof></cloneof>
<crc></crc>
<manufacturer>J-Wing</manufacturer>
<year>1996</year>
<genre></genre>
</game>
<game name="123" index="" images="">
<description>123</description>
<cloneof></cloneof>
<crc></crc>
<manufacturer>J-Wing</manufacturer>
<year>1996</year>
<genre></genre>
</game>
<game name="1qeee" index="" images="">
<description>qweqwe</description>
<cloneof></cloneof>
<crc></crc>
<manufacturer>J-Wing</manufacturer>
<year>1996</year>
<genre></genre>
</game>
</menu>

2:
<?xml version="1.0" ?>
<menu>
<game name="123" index="" images="">
<description>123</description>
<cloneof></cloneof>
<crc></crc>
<manufacturer>J-Wing</manufacturer>
<year>1996</year>
<genre></genre>
</game>
<game name="456" index="" images="">
<description>456</description>
<cloneof></cloneof>
<crc></crc>
<manufacturer>J-Wing</manufacturer>
<year>1996</year>
<genre></genre>
</game>
</menu>

При этом необходимо оставить только уникальные узлы. Уникальность определяется по атрибуту name

Сделал так:
    public class GameComparer : IEqualityComparer<XElement>
    {
        public bool Equals(XElement x, XElement y)
        {
            return x.Attribute("name").Value == y.Attribute("name").Value;
        }

        public int GetHashCode(XElement obj)
        {
            return (obj == null ? 0 : obj.GetHashCode());
        }
    }

    class XmlMerge
    {
        public static XmlDocument Merge(string xml1, string xml2)
        {
            XElement root1 = XElement.Parse(xml1);
            XElement root2 = XElement.Parse(xml2);

            StringBuilder s = new StringBuilder();

            IEnumerable<XElement> games1 = from a in root1.Elements("game") select a;
            IEnumerable<XElement> games2 = from b in root2.Elements("game") select b;
            IEnumerable<XElement> games = from g in games1.Union(games2).Distinct() select g;
            s.Append("<?xml version=\"1.0\"?>");
            s.Append("<menu>");
            foreach (XElement el in games)
            {
                s.Append(el);
            }
            s.Append("</menu>");
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(s.ToString());
            return doc;
        }
    }

В итоговом XML все равно присутствуют дубликаты, при отладке вообще не заходит в метод GameComparer.Equal
Что может быть не так, в каком направлении копать?
Grunch
Дата: 04.04.2014 14:43:03
IEnumerable<XElement> games = from g in games1.Union(games2).Distinct() select g;

читать как
IEnumerable<XElement> games = from g in games1.Union(games2).Distinct(new GameComparer()) select g;
petalvik
Дата: 04.04.2014 20:02:45
Grunch,

в Equal не заходит, потому что хэшкоды у элементов разные.

Нужно переписать метод GetHashCode:
public int GetHashCode(XElement obj)
{
    return obj.Attribute("name").Value.GetHashCode();
}


Сам код я бы тоже переписал. Зачем используется StringBuilder? Почему используются два разных API - XmlDocument и XElement?
var games1 = root1.Elements("game");
var games2 = root2.Elements("game");

var games = games1.Union(games2, new GameComparer());

var doc = new XDocument(new XElement("menu"));
doc.Root.Add(games);
Grunch
Дата: 04.04.2014 20:12:46
Спасибо! Заработало.
Код корявый, потому что только начал изучать C#, еще не все возможности языка знаю. За подсказки спасибо!
DMF84
Дата: 26.05.2015 16:00:40
Добрый день.
Понимаю, тема давно для вас не актуальна, но я сталкнулся с подобной же задачей. К сожалению, ваш пример в моём случае почему-то не работает. Может подскажите где я не прав.

VS выдаёт ошибку:
"System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>" не содержит определения для "Union" и не был найден метод расширения "Union", принимающий тип "System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>" в качестве первого аргумента (возможно, пропущена директива using или ссылка на сборку)
Grunch
Дата: 26.05.2015 16:41:32
DMF84,

Смотрите версию .Net. Метод Enumerable.Union появился, вроде, только в .Net 3.5