我有两个XML文件,我想合并。
合并文件应包含两个文件中的每个元素(维护层次结构),当第二个XML中的元素可以覆盖第一个XML中的元素时:
当两个元素相同(相同的XPATH,相同的属性)时,我想覆盖。
可能有一百万种方法可以做到这一点 - 这是最轻松的(没有学习XSLT,最好)
示例结果:
档案1
<a>
<b foo="d"/>
<b bar="c"/>
<c/>
</a>
文件2
<a>
<b foo="e"/>
<b boo="c"/>
<c/>
</a>
<x>
<b bar="c"/>
</x>
输出
<a>
<b foo="d"/>
<b bar="c"/>
<b boo="c"/>
<c/>
</a>
<x>
<b bar="c"/>
</x>
答案 0 :(得分:2)
XSLT看起来可能是一个挑战,但它可以为您的问题提供一个很好的解决方案。您可能需要考虑公开可用于您的问题的XSLT。由于许多平台实现了这些转换,因此这将是非常独立的平台。也许试试这个:
http://www2.informatik.hu-berlin.de/~obecker/XSLT/#merge
有一些选项可以巧妙地改变合并的执行方式,为您提供更灵活的解决方案。
答案 1 :(得分:1)
答案 2 :(得分:0)
使用xml2可以使用以下过程非常简单:
我还不确定如何进行覆盖,但其余部分看起来与
类似xml2 file1 file2 |排序| 2xml
答案 3 :(得分:0)
我在第一个答案中没有找到任何有用的东西,而第二个答案似乎不完整,所以我自己写了。
代码相当丑陋(我很想听到建议 - 我的XML处理能力......不太好)。
using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Xml;
namespace XmlMerge
{
internal class Program
{
private static int Main(string[] args)
{
if (args.Length != 3)
{
Console.WriteLine("Usage: XmlMerge <mainFile> <mergedFile> <output>");
return 1;
}
string mainFile = args[0];
string mergedFile = args[1];
string outputFile = args[2];
if (!File.Exists(mainFile) ||
!File.Exists(mergedFile))
{
Console.WriteLine("One of the input files doesn't exist");
return 1;
}
var main = new XmlDocument();
main.Load(mainFile);
var merged = new XmlDocument();
merged.Load(mergedFile);
foreach (XmlNode element in merged.SelectNodes("/config/section/value"))
{
string xpath = GetXpath(element);
XmlNode mainNode = main.SelectSingleNode(xpath);
if (mainNode != null)
{
// existing value
mainNode.InnerText = element.InnerText;
}
else
{
// go to father, add as new node
AddNewNode(element, main, xpath);
}
}
main.Save(outputFile);
return 0;
}
/// <summary>
/// Add <paramref name="toAdd"/> to <paramref name="existing"/> under <paramref name="xpath"/>
/// </summary>
/// <param name="toAdd"></param>
/// <param name="existing"></param>
/// <param name="xpath"></param>
private static void AddNewNode(XmlNode toAdd, XmlNode existing, string xpath)
{
foreach (var part in xpath.Split('/'))
{
if (part == "")
continue;
var child = existing.SelectSingleNode(part);
if (child != null)
{
existing = child;
continue;
}
// similar child does not exist, add it ourselves
var partMatch = Regex.Match(part, @"(.*)(?:\[(.*)\])");
var name = partMatch.Groups[1].Value;
var attributes = partMatch.Groups[2].Value;
var newChild = existing.OwnerDocument.CreateElement(name);
if (attributes != null)
{
foreach (var attributeStr in attributes.Split(new[]{"and"}, StringSplitOptions.None))
{
var attributeMatch = Regex.Match(attributeStr, "@(.*)='(.*)'");
var attributeName = attributeMatch.Groups[1].Value;
var attributeValue = attributeMatch.Groups[2].Value;
XmlAttribute attribute = existing.OwnerDocument.CreateAttribute(attributeName);
attribute.Value = attributeValue;
newChild.Attributes.Append(attribute);
}
}
existing.AppendChild(newChild);
}
}
private static string GetXpath(XmlNode node)
{
if (node.ParentNode == null)
return "";
string attributeStr = GetAttributeStr(node);
return GetXpath(node.ParentNode) + "/" + node.Name + attributeStr;
}
private static string GetAttributeStr(XmlNode node)
{
if (node.Attributes.Count == 0)
return "";
var result = "[";
bool first = true;
foreach (XmlAttribute attribute in node.Attributes)
{
if (!first)
result += " and ";
result += "@" + attribute.Name + "='" + attribute.Value + "'";
first = false;
}
return result + "]";
}
}
}