■ 리소스를 병합하는 방법을 보여준다.
▶ Data.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
using System.Xml.Linq; namespace ResourceMerger { /// <summary> /// 데이터 /// </summary> public class Data { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 문서 - Document /// <summary> /// 문서 /// </summary> public XDocument Document { get; set; } #endregion #region 종속 카운트 - DependencyCount /// <summary> /// 종속 카운트 /// </summary> public int DependencyCount { get; set; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - Data(document, dependencyCount) /// <summary> /// 생성자 /// </summary> /// <param name="document">문서</param> /// <param name="dependencyCount">종속 카운트</param> public Data(XDocument document, int dependencyCount) { Document = document; DependencyCount = dependencyCount; } #endregion } } |
▶ ResourceHelper.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml.Linq; namespace ResourceMerger { /// <summary> /// 리소스 헬퍼 /// </summary> public static class ResourceHelper { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region 리소스 딕셔너리 병합하기 - MergeResourceDictionary(projectDirectoryPath, projectName, sourceRelativeFilePath, targetRelativeFilePath, errorMessage) /// <summary> /// 리소스 딕셔너리 병합하기 /// </summary> /// <param name="projectDirectoryPath">프로젝트 디렉토리 경로</param> /// <param name="projectName">프로젝트명</param> /// <param name="sourceRelativeFilePath">소스 파일 상대 경로</param> /// <param name="targetRelativeFilePath">타겟 파일 상대 경로</param> /// <param name="errorMessage">에러 메시지</param> /// <returns>처리 결과</returns> public static bool MergeResourceDictionary ( string projectDirectoryPath, string projectName, string sourceRelativeFilePath, string targetRelativeFilePath, out string errorMessage ) { if(!Directory.Exists(projectDirectoryPath)) { errorMessage = $"PROJECT DIRECTORY PATH DOES NOT EXISTS : {projectDirectoryPath}"; return false; } projectName = string.IsNullOrWhiteSpace(projectName) ? Path.GetFileName(Path.GetDirectoryName(projectDirectoryPath)) : projectName; if(!sourceRelativeFilePath.EndsWith(".xaml", StringComparison.InvariantCultureIgnoreCase)) { errorMessage = $"RELATIVE SOURCE FILE EXTENSON IS NOT .XAML : {sourceRelativeFilePath}"; return false; } if(!targetRelativeFilePath.EndsWith(".xaml", StringComparison.InvariantCultureIgnoreCase)) { errorMessage = $"RELATIVE TARGET FILE EXTENSON IS NOT .XAML : {targetRelativeFilePath}"; return false; } string sourceFilePath = Path.Combine(projectDirectoryPath, sourceRelativeFilePath); if(!File.Exists(sourceFilePath)) { errorMessage = $"SOURCE FILE DOES NOT EXISTS : {sourceFilePath}"; return false; } XDocument sourceDocument = XDocument.Load(sourceFilePath); XNamespace defaultNamespace = sourceDocument.Root.GetDefaultNamespace(); string resourceDictionaryName = sourceDocument.Root.Name.LocalName; XDocument targetDocument = XDocument.Parse("<" + resourceDictionaryName + " xmlns=\"" + defaultNamespace + "\"/>"); Dictionary<string, Data> dataDictionary = new Dictionary<string, Data>(); try { PrepareDataDictionary(ref dataDictionary, projectDirectoryPath, projectName, sourceRelativeFilePath); } catch(Exception exception) { errorMessage = $"ERROR PREPARE DATA DICTIONARY\n{exception.ToString()}"; return false; } foreach(KeyValuePair<string, Data> keyValuePair in dataDictionary.OrderByDescending(item => item.Value.DependencyCount)) { foreach(XAttribute attribute in keyValuePair.Value.Document.Root.Attributes()) { targetDocument.Root.SetAttributeValue(attribute.Name, attribute.Value); } targetDocument.Root.Add ( keyValuePair.Value.Document.Root.Elements().Where(e => !e.Name.LocalName.StartsWith(resourceDictionaryName)) ); } using(MemoryStream stream = new MemoryStream()) { targetDocument.Save(stream); if(CompareByteArray(Path.Combine(projectDirectoryPath, targetRelativeFilePath), stream.ToArray())) { errorMessage = null; return true; } } string targetFilePath = Path.Combine(projectDirectoryPath, targetRelativeFilePath); targetDocument.Save(targetFilePath); errorMessage = null; return true; } #endregion //////////////////////////////////////////////////////////////////////////////// Private #region 데이터 딕셔너리 준비하기 - PrepareDataDictionary(dataDictionary, projectDirectoryPath, projectName, sourceRelativeFilePath, first, parentDependencyCount) /// <summary> /// 데이터 딕셔너리 준비하기 /// </summary> /// <param name="dataDictionary">데이터 딕셔너리</param> /// <param name="projectDirectoryPath">프로젝트 디렉토리 경로</param> /// <param name="projectName">프로젝트명</param> /// <param name="sourceRelativeFilePath">소스 상대 파일 경로</param> /// <param name="first">첫번째 여부</param> /// <param name="parentDependencyCount">부모 종속 카운트</param> private static void PrepareDataDictionary ( ref Dictionary<string, Data> dataDictionary, string projectDirectoryPath, string projectName, string sourceRelativeFilePath, bool first = true, int parentDependencyCount = 0 ) { string sourceFilePath = Path.Combine(projectDirectoryPath, sourceRelativeFilePath.TrimStart('/')); if(!File.Exists(sourceFilePath)) { throw new Exception($"SOURCE FILE PATH DOES NOT EXISTS : {sourceFilePath}"); } XDocument document = XDocument.Load(sourceFilePath); string resourceDictionaryName = document.Root.Name.LocalName; XNamespace defaultNamespace = document.Root.GetDefaultNamespace(); if(dataDictionary.ContainsKey(sourceFilePath)) { dataDictionary[sourceFilePath].DependencyCount = Math.Max ( dataDictionary[sourceFilePath].DependencyCount + 1, parentDependencyCount + 1 ); } else { dataDictionary.Add ( sourceFilePath, new Data(document, first ? -1 : parentDependencyCount + 1) ); } foreach(XElement dictionaryElement in document.Root.Descendants(defaultNamespace + resourceDictionaryName)) { PrepareDataDictionary ( ref dataDictionary, projectDirectoryPath, projectName, dictionaryElement.Attribute("Source").Value.Replace("/" + projectName + ";component/", string.Empty), false, dataDictionary[sourceFilePath].DependencyCount ); } } #endregion #region 바이트 배열 비교하기 - CompareByteArray(targetFilePath, newByteArray) /// <summary> /// 바이트 배열 비교하기 /// </summary> /// <param name="targetFilePath">타겟 파일 경로</param> /// <param name="newByteArray">신규 바이트 배열</param> /// <returns>바이트 배열 비교 결과</returns> private static bool CompareByteArray(string targetFilePath, byte[] newByteArray) { string finalTargetFilePath = targetFilePath.Replace("/", "\\"); if(!File.Exists(finalTargetFilePath)) { return false; } byte[] targetFileByteArray = File.ReadAllBytes(finalTargetFilePath); return newByteArray.SequenceEqual(targetFileByteArray); ; } #endregion } } |
▶ Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
using System; namespace ResourceMerger { /// <summary> /// 프로그램 /// </summary> public class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main(argumentArray) /// <summary> /// 프로그램 시작하기 /// </summary> /// <param name="argumentArray">인자 배열</param> private static void Main(string[] argumentArray) { int argumentArrayLength = argumentArray.Length; if(argumentArrayLength != 4) { Console.WriteLine($"INVALID ARGUMENT ARRAY LENGTH : {argumentArray.Length}"); return; } string projectDirectoryPath = argumentArray[0]; string projectName = argumentArray[1]; string relativeSourceFilePath = argumentArray[2]; string relativeTargetFilePath = argumentArray[3]; string errorMessage; bool result = ResourceHelper.MergeResourceDictionary ( projectDirectoryPath, projectName, relativeSourceFilePath, relativeTargetFilePath, out errorMessage ); if(!result) { Console.WriteLine(errorMessage); } } #endregion } } |