使用LINQ合并2个Xml文件

时间:2012-09-10 15:31:53

标签: c# xml linq merge

我需要将2个xml文件“合并”在一起,但要考虑两者中出现的元素和每个中不同的合并属性。这是我的意思的一个例子:

输入:Xml1

<?xml version="1.0"?>
<Style Width="1024" Height="768">
    <BaseStyle Width="1024" Height="768" BackgroundPath="./Images/BackgroundAAA.png"/>
    <Styles>
        <LabelStyle ID="Label1" Font="Tahoma" Bold="false" /> <!-- exists in both -->
        <LabelStyle ID="Label2" Font="Tahoma" Bold="false" /> <!-- exists in both -->
        <LabelStyle ID="Label3" Font="Tahoma" Bold="false" /> <!-- unique -->
  </Styles>
</Style>

输入:Xml2

<?xml version="1.0"?>
<Style Width="1024" Height="768">
    <BaseStyle Width="1024" Height="768" BackgroundPath="./Images/BackgroundBBB.png"/>
    <Styles>
        <LabelStyle ID="Label1" Font="Arial" Bold="true" /> <!-- exists in both -->
        <LabelStyle ID="Label2" Font="Arial" /> <!-- exists in both -->
        <LabelStyle ID="Label4" Font="Arial" Bold="false" /> <!-- unique -->
    </Styles>
</Style>

我需要输出以下内容: -

结果:Xml3

<?xml version="1.0"?>
<Style Width="1024" Height="768">
    <BaseStyle Width="1024" Height="768" BackgroundPath="./Images/BackgroundBBB.png"/> <!-- has overwritten Xml1 -->
    <Styles>
        <LabelStyle ID="Label1" Font="Arial" Bold="true" /> <!-- has merged Xml1 & Xml2 with Xml2 taking precedence -->
        <LabelStyle ID="Label2" Font="Arial" Bold="false" /> <!-- has merged Xml1 & Xml2 with Xml2 taking precedence (note Bold attribute is present) -->
        <LabelStyle ID="Label3" Font="Tahoma" Bold="false" /> <!-- unique -->
        <LabelStyle ID="Label4" Font="Arial" Bold="false" /> <!-- unique -->
    </Styles>
</Style>

你会从上面注意到任何唯一的东西都会合并,任何常见的东西(使用ID作为键)都会用Xml2值更新。

我一直在阅读有关如何使用LINQ合并2个xml文件的许多重要问题,但没有一个真正满足我的要求。他们似乎都在谈论采取A和B并以A + B结束。

使用LINQ有一种简单的方法吗?

提前致谢!

1 个答案:

答案 0 :(得分:2)

例如:

class Program {
    static void Main(string[] args) {
        StringReader sr = new StringReader("<?xml version=\"1.0\"?><Style Width=\"1024\" Height=\"768\"><BaseStyle Width=\"1024\" Height=\"768\" BackgroundPath=\"./Images/BackgroundBBB.png\"/><Styles><LabelStyle ID=\"Label1\" Font=\"Arial\" Bold=\"true\" /> <!-- exists in both --><LabelStyle ID=\"Label2\" Font=\"Arial\" /> <!-- exists in both --><LabelStyle ID=\"Label3\" Font=\"Arial\" Bold=\"false\" /> <!-- unique --></Styles></Style>"); 
        XDocument xdoc1 = XDocument.Load(sr);
        sr.Close();
        sr = new StringReader("<?xml version=\"1.0\"?><Style Width=\"1024\" Height=\"768\"><BaseStyle Width=\"1024\" Height=\"768\" BackgroundPath=\"./Images/BackgroundBBB.png\"/><Styles><LabelStyle ID=\"Label1\" Font=\"Arial\" Bold=\"true\" /> <!-- exists in both --><LabelStyle ID=\"Label2\" Font=\"Arial\" /> <!-- exists in both --><LabelStyle ID=\"Label4\" Font=\"Arial\" Bold=\"false\" /> <!-- unique --></Styles></Style>");
        XDocument xdoc2 = XDocument.Load(sr);
        sr.Close();

        sr = new StringReader("<?xml version=\"1.0\"?><Style Width=\"1024\" Height=\"768\"><BaseStyle Width=\"1024\" Height=\"768\" BackgroundPath=\"./Images/BackgroundBBB.png\"/><Styles></Styles></Style>");
        XDocument xDocDest = XDocument.Load(sr);
        sr.Close();
        XElement xeDest = xDocDest.Root.Descendants("Styles").Single();

        XElement[] x2s = (from x in xdoc2.Root.Descendants("LabelStyle") orderby x.Attribute("ID").Value select x).ToArray() ;

        Int32 iCurrentX2 = 0;
         XElement xeCurrentX2 = (x2s.Count() > 1) ? x2s[0] : null;
        foreach (XElement x1 in from x in xdoc1.Root.Descendants("LabelStyle") orderby x.Attribute("ID").Value select x) {
            if (xeCurrentX2 == null || String.Compare(x1.Attribute("ID").Value, xeCurrentX2.Attribute("ID").Value) < 0) {
                xeDest.Add(x1);
            } else {
                while (iCurrentX2 < x2s.Count() && String.Compare(x1.Attribute("ID").Value, xeCurrentX2.Attribute("ID").Value) >= 0) {
                    xeDest.Add(xeCurrentX2);
                    xeCurrentX2 = (++iCurrentX2 < x2s.Count()) ? x2s[iCurrentX2] : null;
                }
            }
        }
        while (iCurrentX2 < x2s.Count()) {
            xeDest.Add(x2s[iCurrentX2++]);
        }

        Console.WriteLine(xDocDest.ToString());
    }
}

这不是完美的,但我认为结构在这里