Объединить XML с атрибутами - PullRequest
3 голосов
/ 01 июня 2009

Дубликат:

Объединение XML с атрибутами

У меня есть два 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 ]

2 голосов
/ 04 июня 2009

XSLT может показаться сложной задачей, но может предложить хорошее решение вашей проблемы. Возможно, вы захотите рассмотреть XSLT, который публично доступен для вашей проблемы. Это будет зависеть от платформы, так как многие платформы реализуют эти преобразования. Возможно, попробуйте это:

http://www2.informatik.hu -berlin.de / ~ obecker / XSLT / # слияние

Есть несколько опций, которые тонко меняют способ выполнения слияния, давая вам, возможно, более гибкое решение.

1 голос
/ 01 июня 2009
0 голосов
/ 02 июня 2009

Я не нашел ничего полезного в первом ответе, а второй показался мне неоднозначным, поэтому я написал это для себя.

Код довольно уродливый (я хотел бы услышать о предложениях - мои возможности обработки 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 + "]";
        }
    }
}
0 голосов
/ 01 июня 2009

Использование xml2 может сделать это довольно просто, используя следующий процесс:

  • используйте xml2 для обоих файлов для простого представления
  • объединить оба
  • переопределение ручки
  • преобразовать обратно в xml, используя 2xml

Я пока не уверен, как сделать переопределения, но остальные могут выглядеть как

xml2 file1 file2 | сортировать | 2xml

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...