我有两个xml文件,它们都具有相同的模式,我想合并到一个xml文件中.是否有捷径可寻?
例如,
<Root> <LeafA> <Item1 /> <Item2 /> </LeafA> <LeafB> <Item1 /> <Item2 /> </LeafB> </Root>
<Root> <LeafA> <Item3 /> <Item4 /> </LeafA> <LeafB> <Item3 /> <Item4 /> </LeafB> </Root>
=包含新文件
<Root> <LeafA> <Item1 /> <Item2 /> <Item3 /> <Item4 /> </LeafA> <LeafB> <Item1 /> <Item2 /> <Item3 /> <Item4 /> </LeafB> </Root>
解决方法
“自动XML合并”听起来像是一个相对简单的要求,但是当你深入研究所有细节时,它会变得非常复杂.与更具体的任务相比,使用c#或XSLT更容易,例如在
answer for EF模型中.使用工具来协助手动合并也是一种选择(见
this SO question).
有关参考(并提供有关复杂性的概念),这里是来自Java世界的开源示例:XML merging made easy
回到原来的问题.任务规范中几乎没有大的灰色区域:当2个元素应该被认为是等价的(具有相同的名称,匹配选定的或所有的属性,或者在父元素中也具有相同的位置);原始或合并的XML有多个等价元素等时如何处理情况
下面的代码假设
>我们目前只关心元素
如果元素名称,属性名称和属性值匹配,则>元素是等效的
>元素没有多个具有相同名称的属性
>合并文档中的所有等效元素将与源XML文档中的第一个等效元素组合.
.
// determine which elements we consider the same // private static bool AreEquivalent(XElement a,XElement b) { if(a.Name != b.Name) return false; if(!a.HasAttributes && !b.HasAttributes) return true; if(!a.HasAttributes || !b.HasAttributes) return false; if(a.Attributes().Count() != b.Attributes().Count()) return false; return a.Attributes().All(attA => b.Attributes(attA.Name) .Count(attB => attB.Value == attA.Value) != 0); } // Merge "merged" document B into "source" A // private static void MergeElements(XElement parentA,XElement parentB) { // merge per-element content from parentB into parentA // foreach (XElement childB in parentB.DescendantNodes()) { // merge childB with first equivalent childA // equivalent childB1,childB2,.. will be combined // bool isMatchFound = false; foreach (XElement childA in parentA.Descendants()) { if (AreEquivalent(childA,childB)) { MergeElements(childA,childB); isMatchFound = true; break; } } // if there is no equivalent childA,add childB into parentA // if (!isMatchFound) parentA.Add(childB); } }
它将使用原始XML片段产生所需的结果,但如果输入XML更复杂并且具有重复元素,则结果将更加有趣:
public static void Test() { var a = XDocument.Parse(@" <Root> <LeafA> <Item1 /> <Item2 /> <SubLeaf><X/></SubLeaf> </LeafA> <LeafB> <Item1 /> <Item2 /> </LeafB> </Root>"); var b = XDocument.Parse(@" <Root> <LeafB> <Item5 /> <Item1 /> <Item6 /> </LeafB> <LeafA Name=""X""> <Item3 /> </LeafA> <LeafA> <Item3 /> </LeafA> <LeafA> <SubLeaf><Y/></SubLeaf> </LeafA> </Root>"); MergeElements(a.Root,b.Root); Console.WriteLine("Merged document:\n{0}",a.Root); }
这里的合并文档显示了文档B中的等效元素是如何组合在一起的:
<Root> <LeafA> <Item1 /> <Item2 /> <SubLeaf> <X /> <Y /> </SubLeaf> <Item3 /> </LeafA> <LeafB> <Item1 /> <Item2 /> <Item5 /> <Item6 /> </LeafB> <LeafA Name="X"> <Item3 /> </LeafA> </Root>