我有多个XML文件,我正在尝试合并到一个文件中。 Linq to XML可能是最好的选择,但我对创意持开放态度(XSLT似乎很擅长合并两个文件但在n> 2或n =大的情况下很笨拙。)
通过阅读其他问题,某种联系看起来很不错。
File1.xml:
<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>
即。它根据第三个/ @id属性合并值。
如何使用linq优雅地完成此操作?
答案 0 :(得分:3)
以下内容仍然相当丑陋,我相信它可以通过一些工作带入更加流线型的形状,但是现在这似乎可以完成这项工作:
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");
}
这将从OPs问题中的两个示例输入文件生成以下输出文件:
<?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>
答案 1 :(得分:1)
这应该使用LINQ将第二个文件'contents'合并到第一个文件中。
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));