Search code examples
c#resx

How to read a filename in the value field of a RESX file


The issue I am stuck with is how to iterate through a resource file when a file name is the value. I first tried to use DictionaryEntry and found the same issue as well. Would you be able to provide some guidance on how to resolve this problem?

Prereqs:

A local resource file with the following string resource value:

Name                 |Value                                   |Comment
-----------------------------------------------------------------------------------------------------
MouseImageUrl2.Text  |protected/images/tutorial/goodwork.gif  |protected/images/tutorial/goodwork.gif
  • Persistence: Embedded in .resx
  • Type: System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

The following operation (using System.Windows.Forms;):

ResXResourceReader rsxr = new ResXResourceReader(@"C:\Projects\Working\TFS\Source\Help.aspx.resx");
IEnumerator enumerator = rsxr.GetEnumerator();

Details:

This is the error that I receive (The solution is located at C:\Projects\Team - SE\Code_PSGDashboard\Development\TAS_LanguageProcessor\TAS_LanguageProcessor):

ResX file Could not find a part of the path 'C:\Projects\Team - SE\Code_PSGDashboard\Development\TAS_LanguageProcessor\TAS_LanguageProcessor\bin\Protected\Images\tutorial\goodwork.gif'. Line 123, position 5. cannot be parsed.

I am using DictionaryEntry, but the provided code does produce the same results. The DictionaryEntry routine that will throw the same error is:

ResXResourceReader rsxr = new ResXResourceReader(@"C:\Projects\Working\TFS\Source\Help.aspx.resx");
foreach (DictionaryEntry d in rsxr){}

Solution

  • The solution I ended up using was the following:

    using System.Collections;
    using System.Resources;
    
    /// <summary>   Resource item. </summary>
    public static class ResourceItem
    {
        /// <summary>
        /// This routine is responsible for getting all the comments from the original files and then
        /// adding them to the new resource files.
        /// </summary>
        /// <param name="inputResX">    The path to the source resx. </param>
        /// <param name="outputResX">   The path to the destination resx. </param>
        /// <returns>   True if changes were made. </returns>
        public static bool CopyComments(string inputResX, string outputResX)
        {
            bool changesMade = false;
    
            // Populate a Hashtable containing the DataNodes in the output file
            var output = new Hashtable();
            using (var reader = new ResXResourceReader(outputResX))
            {
                reader.UseResXDataNodes = true;
                IEnumerator enumerator = reader.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    var entry = (DictionaryEntry)enumerator.Current;
    
                    var dataNode = (ResXDataNode)entry.Value;
                    output.Add(dataNode.Name, dataNode);
                }
            }
    
            // Search the Hashtable for equivalent DataNodes in the input file
            using (var reader = new ResXResourceReader(inputResX))
            {
                reader.UseResXDataNodes = true;
                IEnumerator enumerator = reader.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    var entry = (DictionaryEntry)enumerator.Current;
    
                    var inputDataNode = (ResXDataNode)entry.Value;
    
                    if (output.ContainsKey(inputDataNode.Name))
                    {
                        var outputDataNode = (ResXDataNode)output[inputDataNode.Name];
                        if (!string.IsNullOrEmpty(inputDataNode.Comment) && outputDataNode.Comment != inputDataNode.Comment)
                        {
                            // Update the output resx’s comments with the input resx’s comments
                            outputDataNode.Comment = inputDataNode.Comment;
                            changesMade = true;
                        }
                    }
                }
            }
    
            if (changesMade)
            {
                // Write the changes back to the output file
                using (var writer = new ResXResourceWriter(outputResX))
                {
                    foreach (DictionaryEntry entry in output)
                    {
                        writer.AddResource(entry.Key.ToString(), entry.Value);
                    }
    
                    writer.Generate();
                    writer.Close();
                }
            }
    
            return changesMade;
        }
    }
    

    This allowed me to write new resource files and copy the comments to the new one and save it.