将XML与属性合并

时间:2009-06-01 06:01:38

标签: xml

重复:

  

Merge XMLs with attributes

我有两个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>

4 个答案:

答案 0 :(得分:2)

XSLT看起来可能是一个挑战,但它可以为您的问题提供一个很好的解决方案。您可能需要考虑公开可用于您的问题的XSLT。由于许多平台实现了这些转换,因此这将是非常独立的平台。也许试试这个:

http://www2.informatik.hu-berlin.de/~obecker/XSLT/#merge

有一些选项可以巧妙地改变合并的执行方式,为您提供更灵活的解决方案。

答案 1 :(得分:1)

答案 2 :(得分:0)

使用xml2可以使用以下过程非常简单:

  • 在两个文件上使用xml2进行简单表示
  • 合并两者
  • 处理覆盖
  • 使用2xml
  • 转换回xml

我还不确定如何进行覆盖,但其余部分看起来与

类似

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 + "]";
        }
    }
}