合并2个不同的RESX文件- Windows ASP.NET

本文关键字:Windows ASP NET 文件 RESX 2个 合并 | 更新日期: 2023-09-27 18:06:06

我们有几个来自公司几个不同项目的RESX文件,我们需要将它们合并到一个公共文件中。RESX分享给他们所有人。文件之间有一些重叠,它们不相同,但有共同的节点。

是否有一个工具,可以采取2个不同的RESX文件,并创建一个新的组合一个不双重共同元素?

合并2个不同的RESX文件- Windows ASP.NET

我不认为有这样的工具,但它很容易编写。

下面是一个简单的例子:

static XDocument MergeResxFiles(string[] files)
{
    var allResources =
        from f in files
        let doc = XDocument.Load(f)
        from e in doc.Root.Elements("data")
        select Resource.Parse(e, f);
    var elements = new List<XElement>();
    foreach (var g in allResources.GroupBy(r => r.Name))
    {
        elements.AddRange(MergeResources(g.Key, g));
    }
    var output = new XDocument(new XElement("root", elements));
    return output;
}
private static IEnumerable<XElement> MergeResources(string name, IEnumerable<Resource> resources)
{
    var grouped = resources.GroupBy(r => r.Value).ToList();
    if (grouped.Count == 1)
    {
        yield return grouped[0].First().Xml;
    }
    else
    {
        Console.WriteLine($"Duplicate entries for {name}");
        foreach (var g in grouped)
        {
            var comments = g.Select(r => new XComment($"Source: {r.FileName}"));
            yield return new XElement(
                "data",
                comments,
                new XAttribute("name", name),
                new XElement("value", g.Key));
        }
    }
}
class Resource
{
    public string Name { get; }
    public string Value { get; }
    public string FileName { get; }
    public XElement Xml { get; }
    public Resource(string name, string value, string fileName, XElement xml)
    {
        Name = name;
        Value = value;
        FileName = fileName;
        Xml = xml;
    }
    public static Resource Parse(XElement element, string fileName)
    {
        string name = element.Attribute("name").Value;
        string value = element.Element("value").Value;
        return new Resource(name, value, fileName, element);
    }
}

这将用指定文件中的资源生成一个新的resx文档,其行为如下:

  • 如果一个资源存在于多个resx文件中:
    • 如果所有文件的值都相同,输出单个资源
    • else,用这个名字输出所有不同的资源,用注释指出它们来自哪个文件,以帮助解决冲突。
  • else,输出单个资源

代码将重复资源的名称打印到控制台,以便轻松识别它们。

例如,如果您有两个resx文件,其中包含以下资源:

  • Test,存在于两个文件中,值相同
  • Foo,存在于两个文件中,但值不同
  • Bar,只出现在第一个文件
  • Baz,只存在于第二个文件

然后输出如下所示:

<root>
  <data name="Test" xml:space="preserve">
    <value>The value for Test</value>
  </data>
  <data name="Foo">
    <!--Source: D:'tmp'resx'resources1.resx-->
    <value>The value for Foo</value>
  </data>
  <data name="Foo">
    <!--Source: D:'tmp'resx'resources2.resx-->
    <value>Other value for Foo</value>
  </data>
  <data name="Bar" xml:space="preserve">
    <value>The value for Bar</value>
  </data>
  <data name="Baz" xml:space="preserve">
    <value>The value for Baz</value>
  </data>
</root>

(注意:这段代码没有经过彻底的测试,可能需要一些修复和调整)

使用Thomas的代码,这里是一个简单的控制台应用程序,它将两个资源文件合并为一个xml文档。注意,没有错误处理,只是一个快速的工具。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace MergeResx
{
class Program
{
    static void Main(string[] args)
    {
        var folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),"resx");
        var x = MergeResxFiles(new [] { Path.Combine(folder,args[0]), Path.Combine(folder, args[1])});
        File.WriteAllText(Path.Combine(folder, "merged.xml"), x.ToString());
        Console.WriteLine("--done--");
        Console.ReadLine();
    }
    static XDocument MergeResxFiles(string[] files)
    {
        var allResources =
            from f in files
            let doc = XDocument.Load(f)
            from e in doc.Root.Elements("data")
            select Resource.Parse(e, f);
        var elements = new List<XElement>();
        var enumerable = allResources.GroupBy(r => r.Name).OrderBy(x=>x.Key).ToList();
        foreach (var g in enumerable)
        {
            elements.AddRange(MergeResources(g.Key, g));
        }
        Console.WriteLine("Terms: " + enumerable.Count());
        var output = new XDocument(new XElement("root", elements));
        return output;
    }
    private static IEnumerable<XElement> MergeResources(string name, IEnumerable<Resource> resources)
    {
        var grouped = resources.GroupBy(r => r.Value).ToList();
        if (grouped.Count == 1)
        {
            yield return grouped[0].First().Xml;
        }
        else
        {
            Console.WriteLine($"Duplicate entries for {name}");
            foreach (var g in grouped)
            {
                var comments = g.Select(r => new XComment($"Source: {r.FileName}"));
                yield return new XElement(
                    "data",
                    comments,
                    new XAttribute("name", name),
                    new XElement("value", g.Key));
            }
        }
    }
    class Resource
    {
        public string Name { get; }
        public string Value { get; }
        public string Comment { get; }
        public string FileName { get; }
        public XElement Xml { get; }
        public Resource(string name, string value, string fileName,string comment, XElement xml)
        {
            Name = name;
            Value = value;
            Comment = comment;
            FileName = fileName;
            Xml = xml;
        }
        public static Resource Parse(XElement element, string fileName)
        {
            string name = element.Attribute("name").Value;
            string value = element.Element("value").Value;
            string comment = element.Element("comment")?.Value;
            return new Resource(name, value, fileName, comment, element);
        }
    }
}

}

我现在也有同样的问题。感谢之前的回复。我修改了表示的代码(增加并行性并减少new运算符的数量)以提高处理速度。另外,现在您可以在命令行参数中设置任意数量的文件和文件夹(文件夹将搜索"。Resx " files "),或者根本不指定源(files)。Resx"将在当前目录中搜索)。您还可以指定结果文件的名称(默认为"Resources")。和键"- noduplduplicate "(如果指定此键,将不会插入重复项,除非遇到第一个)

using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace MergeResX
{
    static class MergeResX
    {
        static void Main(string[] args)
        {
            var settings = args
                .Select(arg => arg[0] == '-' ? ("keys", arg.TrimStart('-')) : Directory.Exists(arg) ? ("directories", arg) : File.Exists(arg) ? ("sources", arg) : ("targets", arg))
                .Concat(new (string, string)[] { ("keys", null), ("directories", null), ("sources", null), ("targets", null), })
                .GroupBy(item => item.Item1)
                .ToDictionary(group => group.Key, group => group.Select(item => item.Item2).Where(item => !string.IsNullOrWhiteSpace(item)))
                ;
            var files = settings["directories"].Any() || settings["sources"].Any()
                ? settings["directories"]
                .AsParallel()
                .Select(directory => new DirectoryInfo(directory))
                .SelectMany(directory => directory.EnumerateFiles("*.resx", SearchOption.AllDirectories))
                .Concat(settings["sources"].AsParallel().Select(source => new FileInfo(source)))
                : (new DirectoryInfo(Directory.GetCurrentDirectory())).EnumerateFiles()
                ;
            var resources = files
                .AsParallel()
                .Where(file => file.Length > 0)
                .Select(file => XDocument.Load(file.FullName))
                .SelectMany(document => document.Root.Elements("data"))
                .GroupBy(element => element.Attribute("name")?.Value)
                .SelectMany(group => group
                                    .GroupBy(item => item.Attribute("value")?.Value)
                                    .SelectMany(grouped => !grouped.Skip(1).Any() || settings["keys"].Contains("noduplicates", StringComparer.InvariantCultureIgnoreCase)
                                                            ? grouped.Take(1)
                                                            : grouped.Select(item => item.WithComment("NAME DUPLICATED IN FEW RESX FILES DURING MERGE! LOOK AROUND THIS ELEMENT! BE CAREFULLY!"))))
                ;
            new XDocument(new XElement("root", resources)).Save(settings["targets"].FirstOrDefault() ?? "Resources.resx");
        }
        static XElement WithComment(this XElement element, string comment)
        {
            element.AddFirst(new XComment(comment));
            return element;
        }
    }
}