将XML与属性合并 重复:
我有两个要合并的XML文件 当第二个XML中的元素可以覆盖第一个XML中的元素时,合并文件应该包含两个文件中的每个元素(维护层次结构): 当两个元素相同(相同的XPATH、相同的属性)时,我希望重写 可能有一百万种方法可以做到这一点——这是最容易做到的(最好不用学习XSLT) 样本结果: 文件1将XML与属性合并 重复:,xml,Xml,我有两个要合并的XML文件 当第二个XML中的元素可以覆盖第一个XML中的元素时,合并文件应该包含两个文件中的每个元素(维护层次结构): 当两个元素相同(相同的XPATH、相同的属性)时,我希望重写 可能有一百万种方法可以做到这一点——这是最容易做到的(最好不用学习XSLT) 样本结果: 文件1 <a> <b foo="d"/> <b bar="c"/> <c/> </a> 文件2 <a> <b foo=
<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>
使用可以通过以下过程使这变得非常简单:
- 在两个文件上使用xml2实现简单表示
- 合并两者
- 句柄覆盖
- 使用2xml转换回xml
xml2file1file2 | sort | 2xml我在第一个答案中没有发现任何有用的东西,第二个答案似乎不完整,所以我自己写的 代码相当难看(我很想听到一些建议——我的XML处理能力……不太好)
使用系统;
使用System.IO;
使用System.Text.RegularExpressions;
使用System.Xml;
命名空间XmlMerge
{
内部课程计划
{
私有静态int Main(字符串[]args)
{
如果(参数长度!=3)
{
Console.WriteLine(“用法:XmlMerge”);
返回1;
}
字符串mainFile=args[0];
字符串mergedFile=args[1];
字符串outputFile=args[2];
如果(!File.Exists)(主文件)||
!File.Exists(合并文件))
{
WriteLine(“其中一个输入文件不存在”);
返回1;
}
var main=新的XmlDocument();
加载main.Load(mainFile);
var merged=新的XmlDocument();
合并。加载(合并文件);
foreach(merged.SelectNodes(“/config/section/value”)中的XmlNode元素)
{
字符串xpath=GetXpath(元素);
XmlNode mainNode=main.SelectSingleNode(xpath);
如果(主节点!=null)
{
//现存价值
mainNode.InnerText=element.InnerText;
}
其他的
{
//转到父节点,添加为新节点
AddNewNode(元素、main、xpath);
}
}
main.Save(outputFile);
返回0;
}
///
///加在下面
///
///
///
///
私有静态void AddNewNode(XmlNode toAdd,XmlNode existing,string xpath)
{
foreach(xpath.Split('/')中的var部分)
{
如果(部分==“”)
继续;
var child=existing.SelectSingleNode(部分);
if(child!=null)
{
现有=儿童;
继续;
}
//类似的子项不存在,请自己添加
var partMatch=Regex.Match(part,@“(.*)(?:\[(.*)\])”;
var name=partMatch.Groups[1]。值;
var attributes=partMatch.Groups[2]。值;
var newChild=existing.OwnerDocument.CreateElement(名称);
如果(属性!=null)
{
foreach(attributes.Split中的var attributeStr(新[]{”和“},StringSplitOptions.None))
{
var attributeMatch=Regex.Match(attributeStr,“@(.*)=”(.*)”;
var attributeName=attributeMatch.Groups[1]。值;
var attributeValue=attributeMatch.Groups[2]。值;
XmlAttribute属性=existing.OwnerDocument.CreateAttribute(attributeName);
attribute.Value=attributeValue;
newChild.Attributes.Append(属性);
}
}
现有。追加子女(新子女);
}
}
私有静态字符串GetXpath(XmlNode节点)
{
if(node.ParentNode==null)
返回“”;
字符串attributeStr=GetAttributeStr(节点);
返回GetXpath(node.ParentNode)+“/”+node.Name+attributest;
}
私有静态字符串getAttributeST(XmlNode节点)
{
如果(node.Attributes.Count==0)
返回“”;
var result=“[”;
bool first=true;
foreach(node.Attributes中的XmlAttribute属性)
{
如果(!第一个)
结果+=“和”;
结果+=“@”+属性.名称+“=”+属性.值+”;
第一个=假;
}
返回结果+“]”;
}
}
}
XSLT看起来可能是一个挑战,但它可以为您的问题提供一个很好的解决方案。您可能需要考虑为您的问题公开可用的XSLT。这与平台无关,因为许多平台都实现了这些转换。也许可以试试这个:
也有一些选项可以微妙地改变合并的执行方式,从而为您提供更灵活的解决方案 是的,我在谷歌找到了这些,但还没来得及查看。你知道它能满足我的需要吗?XSLT真的很擅长合并XML,你知道……谢谢,我没有想到要找预先编写好的XSLT。
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 + "]";
}
}
}