将XML与属性合并 重复:

将XML与属性合并 重复:,xml,Xml,我有两个要合并的XML文件 当第二个XML中的元素可以覆盖第一个XML中的元素时,合并文件应该包含两个文件中的每个元素(维护层次结构): 当两个元素相同(相同的XPATH、相同的属性)时,我希望重写 可能有一百万种方法可以做到这一点——这是最容易做到的(最好不用学习XSLT) 样本结果: 文件1 <a> <b foo="d"/> <b bar="c"/> <c/> </a> 文件2 <a> <b foo=

我有两个要合并的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>

使用可以通过以下过程使这变得非常简单:

  • 在两个文件上使用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 + "]";
        }
    }
}