Combining XML files with attributes

Duplicate:

Combine XML with attributes

I have two XML files that I would like to combine.

The merged file must contain each element from both files (supporting a hierarchy) when elements from the second XML can override elements from the first XML:

If two elements are identical (same XPATH, same properties), I would like to override.

There are probably a million ways to do this - this is the easiest (without XSLT training, preferably)

Example result:

File 1

<a>
 <b foo="d"/>
 <b bar="c"/>
 <c/>
</a>

File 2

<a>
 <b foo="e"/>
 <b boo="c"/>
 <c/>
</a>
<x>
 <b bar="c"/>
</x>

Exit

<a>
 <b foo="d"/>
 <b bar="c"/>
 <b boo="c"/>
 <c/>
</a>
<x>
 <b bar="c"/>
</x>
+3
source share
4 answers
+2

xml2, , :

  • xml2
  • xml 2xml

, ,

xml2 file1 file2 | | 2xml

0

, , , , .

The code is pretty ugly (I'd love to hear suggestions - my XML processing capabilities ... are not very good).

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
source

Source: https://habr.com/ru/post/1709498/


All Articles