C# 使用linq合并具有相同结构的多个XML文件,并基于密钥删除重复项
我有多个XML文件,我正试图合并成一个文件。Linq到XML可能是最好的选择,但我乐于接受(XSLT似乎擅长合并两个文件,但在n>2或n=big的情况下很笨拙) 通过阅读这里的其他问题,某种连接看起来不错 File1.xml:C# 使用linq合并具有相同结构的多个XML文件,并基于密钥删除重复项,c#,xml,linq,xslt,merge,C#,Xml,Linq,Xslt,Merge,我有多个XML文件,我正试图合并成一个文件。Linq到XML可能是最好的选择,但我乐于接受(XSLT似乎擅长合并两个文件,但在n>2或n=big的情况下很笨拙) 通过阅读这里的其他问题,某种连接看起来不错 File1.xml: <first> <second> <third id="Id1"> <values> <value a="1" b="one"/> <value a=
<first>
<second>
<third id="Id1">
<values>
<value a="1" b="one"/>
<value a="2" b="two"/>
<value a="3" b="three"/>
</values>
</third>
<third id="Id2">
<values>
<value a="f" b="foo"/>
<value a="b" b="bar"/>
<value a="w" b="wibble"/>
</values>
</third>
</second>
</first>
File2.xml:
<first>
<second>
<third id="Id1">
<values>
<value a="2" b="two"/>
<value a="3" b="three"/>
<value a="6" b="six"/>
</values>
</third>
<third id="Id3">
<values>
<value a="x" b="ex"/>
<value a="y" b="why"/>
<value a="z" b="zed"/>
</values>
</third>
</second>
</first>
Merged.xml:
<first>
<second>
<third id="Id1">
<values>
<value a="1" b="one"/>
<value a="2" b="two"/>
<value a="3" b="three"/>
<value a="6" b="six"/>
</values>
</third>
<third id="Id2">
<values>
<value a="f" b="foo"/>
<value a="b" b="bar"/>
<value a="w" b="wibble"/>
</values>
</third>
<third id="Id3">
<values>
<value a="x" b="ex"/>
<value a="y" b="why"/>
<value a="z" b="zed"/>
</values>
</third>
</second>
</first>
i、 e.它根据第三个/@id属性合并值
如何使用linq优雅地执行此操作?这应该使用linq将第二个文件“内容”合并到第一个文件中
XDocument document = XDocument.Load("File1.xml");
XElement secondElement = document.Descendants("second").FirstOrDefault();
XDocument document2 = XDocument.Load("File2.xml");
XElement secondlement2 = document2.Descendants("second").FirstOrDefault();
secondElement.Add(secondlement2.Nodes());
更新-在下面添加代码,以满足最终输出中的独特条目
XDocument document = XDocument.Load(@"File1.xml");
XElement secondElement = document.Descendants("second").FirstOrDefault();
XDocument document2 = XDocument.Load(@"File2.xml");
XElement secondlement2 = document2.Descendants("second").FirstOrDefault();
var startingNodes = (from n2 in secondElement.Descendants("third") select n2.Attribute("id").Value).ToList();
var nonUniqueNodes = (from n in secondlement2.Descendants("third") where startingNodes.Contains(n.Attribute("id").Value) select n).ToList();
secondElement.Add(secondlement2.Elements().Except(nonUniqueNodes));
这应该使用LINQ将第二个文件“内容”合并到第一个文件中
XDocument document = XDocument.Load("File1.xml");
XElement secondElement = document.Descendants("second").FirstOrDefault();
XDocument document2 = XDocument.Load("File2.xml");
XElement secondlement2 = document2.Descendants("second").FirstOrDefault();
secondElement.Add(secondlement2.Nodes());
更新-在下面添加代码,以满足最终输出中的独特条目
XDocument document = XDocument.Load(@"File1.xml");
XElement secondElement = document.Descendants("second").FirstOrDefault();
XDocument document2 = XDocument.Load(@"File2.xml");
XElement secondlement2 = document2.Descendants("second").FirstOrDefault();
var startingNodes = (from n2 in secondElement.Descendants("third") select n2.Attribute("id").Value).ToList();
var nonUniqueNodes = (from n in secondlement2.Descendants("third") where startingNodes.Contains(n.Attribute("id").Value) select n).ToList();
secondElement.Add(secondlement2.Elements().Except(nonUniqueNodes));
下面这张照片仍然很难看,我相信只要稍加修改,它就可以变得更加流线型,但现在这张照片似乎可以做到这一点:
public static void MergeXml()
{
var xdoc1 = XDocument.Load(@"c:\temp\test.xml");
var xdoc2 = XDocument.Load(@"c:\temp\test2.xml");
var d1Targets = xdoc1.Descendants("third");
var d2Selection = xdoc2.Descendants("third").ToList();
Func<XElement, XElement, string, bool> attributeMatches = (x, y, a) =>
x.Attribute(a).Value == y.Attribute(a).Value;
Func<IEnumerable<XElement>, XElement, bool> hasMatchingValue = (ys, x) =>
// remove && if matching "a" should cause replacement.
ys.Any(d => attributeMatches(d, x, "a") && attributeMatches(d, x, "b"));
foreach (var e in d1Targets)
{
var fromD2 = d2Selection.Find(x => attributeMatches(x, e, "id"));
if (fromD2 != null)
{
d2Selection.Remove(fromD2);
var dest = e.Descendants("value");
dest.LastOrDefault()
.AddAfterSelf(fromD2.Descendants("value").Where(x => !hasMatchingValue(dest, x)));
}
};
if (d2Selection.Count > 0)
d1Targets.LastOrDefault().AddAfterSelf(d2Selection);
xdoc1.Save(@"c:\temp\merged.xml");
}
publicstaticvoidmergexml()
{
var xdoc1=XDocument.Load(@“c:\temp\test.xml”);
var xdoc2=XDocument.Load(@“c:\temp\test2.xml”);
变量d1Targets=xdoc1.substands(“第三”);
var d2Selection=xdoc2.substands(“第三”).ToList();
函数属性匹配=(x,y,a)=>
x、 属性(a).Value==y.Attribute(a).Value;
Func hasMatchingValue=(ys,x)=>
//如果匹配“a”会导致更换,则删除(&I)。
任何(d=>属性匹配(d,x,“a”)&属性匹配(d,x,“b”);
foreach(目标中的变量e)
{
var fromD2=d2Selection.Find(x=>attributeMatches(x,e,“id”);
if(fromD2!=null)
{
D2选择。删除(从D2中删除);
var dest=e.e.(“价值”);
dest.LastOrDefault()
.AddAfterSelf(来自d2.substands(“value”)。其中(x=>!hasMatchingValue(dest,x));
}
};
如果(d2Selection.Count>0)
d1Targets.LastOrDefault().AddAfterSelf(d2Selection);
xdoc1.Save(@“c:\temp\merged.xml”);
}
这将根据问题中的两个示例输入文件生成以下输出文件:
<?xml version="1.0" encoding="utf-8"?>
<first>
<second>
<third id="Id1">
<values>
<value a="1" b="one" />
<value a="2" b="two" />
<value a="3" b="three" />
<value a="6" b="six" />
</values>
</third>
<third id="Id2">
<values>
<value a="f" b="foo" />
<value a="b" b="bar" />
<value a="w" b="wibble" />
</values>
</third>
<third id="Id3">
<values>
<value a="x" b="ex" />
<value a="y" b="why" />
<value a="z" b="zed" />
</values>
</third>
</second>
</first>
下面的内容仍然很难看,我相信只要稍加努力,它就可以变得更加流线型,但目前看来这似乎可以做到:
public static void MergeXml()
{
var xdoc1 = XDocument.Load(@"c:\temp\test.xml");
var xdoc2 = XDocument.Load(@"c:\temp\test2.xml");
var d1Targets = xdoc1.Descendants("third");
var d2Selection = xdoc2.Descendants("third").ToList();
Func<XElement, XElement, string, bool> attributeMatches = (x, y, a) =>
x.Attribute(a).Value == y.Attribute(a).Value;
Func<IEnumerable<XElement>, XElement, bool> hasMatchingValue = (ys, x) =>
// remove && if matching "a" should cause replacement.
ys.Any(d => attributeMatches(d, x, "a") && attributeMatches(d, x, "b"));
foreach (var e in d1Targets)
{
var fromD2 = d2Selection.Find(x => attributeMatches(x, e, "id"));
if (fromD2 != null)
{
d2Selection.Remove(fromD2);
var dest = e.Descendants("value");
dest.LastOrDefault()
.AddAfterSelf(fromD2.Descendants("value").Where(x => !hasMatchingValue(dest, x)));
}
};
if (d2Selection.Count > 0)
d1Targets.LastOrDefault().AddAfterSelf(d2Selection);
xdoc1.Save(@"c:\temp\merged.xml");
}
publicstaticvoidmergexml()
{
var xdoc1=XDocument.Load(@“c:\temp\test.xml”);
var xdoc2=XDocument.Load(@“c:\temp\test2.xml”);
变量d1Targets=xdoc1.substands(“第三”);
var d2Selection=xdoc2.substands(“第三”).ToList();
函数属性匹配=(x,y,a)=>
x、 属性(a).Value==y.Attribute(a).Value;
Func hasMatchingValue=(ys,x)=>
//如果匹配“a”会导致更换,则删除(&I)。
任何(d=>属性匹配(d,x,“a”)&属性匹配(d,x,“b”);
foreach(目标中的变量e)
{
var fromD2=d2Selection.Find(x=>attributeMatches(x,e,“id”);
if(fromD2!=null)
{
D2选择。删除(从D2中删除);
var dest=e.e.(“价值”);
dest.LastOrDefault()
.AddAfterSelf(来自d2.substands(“value”)。其中(x=>!hasMatchingValue(dest,x));
}
};
如果(d2Selection.Count>0)
d1Targets.LastOrDefault().AddAfterSelf(d2Selection);
xdoc1.Save(@“c:\temp\merged.xml”);
}
这将根据问题中的两个示例输入文件生成以下输出文件:
<?xml version="1.0" encoding="utf-8"?>
<first>
<second>
<third id="Id1">
<values>
<value a="1" b="one" />
<value a="2" b="two" />
<value a="3" b="three" />
<value a="6" b="six" />
</values>
</third>
<third id="Id2">
<values>
<value a="f" b="foo" />
<value a="b" b="bar" />
<value a="w" b="wibble" />
</values>
</third>
<third id="Id3">
<values>
<value a="x" b="ex" />
<value a="y" b="why" />
<value a="z" b="zed" />
</values>
</third>
</second>
</first>
但是,结果是,您不会得到任何与请求的Merged.xml文件类似的内容。您需要匹配每个第三个
元素,然后比较其中的每个值(因为两个元素中都存在一些值,但结果中只有一个值)。@CharlesMager您的更正,我在操作中遗漏了这一点。正在进行更正。但是,您不会得到与请求的Merged.xml
文件类似的任何结果。你需要匹配每个第三个元素,然后比较其中的每个值(因为两个元素中都存在一些值,但结果中只有一个)。@CharlesMager你的正确答案,我在操作中错过了。正在进行更正。太棒了。谢谢你。@IainHolder我看你没有接受这个答案。如果您能评论一下为什么这不能/不再回答您的问题,我们将不胜感激。感谢您指出这一点。如果是我,那就是胖手指。答案很好。funcs是关键。我对它进行了修改,并创建了一个for循环,以便将多个文件合并在一起。我重新接受了答案。:-)好的,谢谢,这让我想知道它可能有什么问题。funcs和扩展方法一样好,可以稍微清理一下这些方法。谢谢你。@IainHolder我看你没有接受这个答案。如果您能评论一下为什么这不能/不再回答您的问题,我们将不胜感激。感谢您指出这一点。如果是我,那就是胖手指。答案很好。funcs是关键。我对它进行了修改,并创建了一个for循环,以便将多个文件合并在一起。我重新接受了答案。:-)好的,谢谢,这让我想知道它可能有什么问题。funcs也会做得很好