public static XDocument CreateOutputDocument(string projectPath, string projectName, string relativeSourceFilePath) { // create sourceFilePath var sourceFilePath = projectPath + relativeSourceFilePath; // if source file does not exist throw exception if (!File.Exists(sourceFilePath)) { Helpers.ThrowException <Exception>(SOURCE_EXCEPTION + sourceFilePath); } // load source doc var sourceDoc = XDocument.Load(sourceFilePath); // get default namespace for doc creation and filtering var defaultNameSpace = sourceDoc.Root.GetDefaultNamespace(); // get res dict string var resDictString = sourceDoc.Root.Name.LocalName; var outputDoc = XDocument.Parse("<" + resDictString + " xmlns=\"" + defaultNameSpace + "\"/>"); // create documents var documents = new Dictionary <string, Data>(); // add elements ResourceMerger.PrepareDocuments(ref documents, projectPath, projectName, relativeSourceFilePath); // add elements (ordered by dependency count) foreach (var item in documents.OrderByDescending(item => item.Value.DependencyCount)) { // add attributes foreach (var attribute in item.Value.Document.Root.Attributes()) { outputDoc.Root.SetAttributeValue(attribute.Name, attribute.Value); } // add elements outputDoc.Root.Add(item.Value.Document.Root.Elements().Where(e => !e.Name.LocalName.StartsWith(resDictString))); } return(outputDoc); }
/// <summary> /// save all resources into one big resource dictionary respecting the dependencies to increase performance /// </summary> /// <param name="projectPath">project path (C:/..)</param> /// <param name="relativeSourceFilePath">relative source file path (/LookAndFeel.xaml)</param> /// <param name="relativeOutputFilePath">relative output file path (/xGeneric/Generic.xaml)</param> /// <param name="projectName">project name</param> /// <param name="resDictString">resource dictionary string (node name)</param> public static void MergeResources(string projectPath, string projectName = null, string relativeSourceFilePath = "/LookAndFeel.xaml", string relativeOutputFilePath = "/FullLookAndFeel.xaml") { if (!Directory.Exists(projectPath)) { Helpers.ThrowException <Exception>(PROJECT_PATH_EXCEPTION); } projectName = string.IsNullOrEmpty(projectName) ? Path.GetFileName(Path.GetDirectoryName(projectPath)) : projectName; if (!relativeSourceFilePath.EndsWith(".xaml", StringComparison.InvariantCultureIgnoreCase)) { Helpers.ThrowException <Exception>(SOURCE_TYPE_EXCEPTION); } if (!relativeOutputFilePath.EndsWith(".xaml", StringComparison.InvariantCultureIgnoreCase)) { Helpers.ThrowException <Exception>(OUTPUT_TYPE_EXCEPTION); } var documents = new Dictionary <string, Data>(); var existingNamespaces = new List <Namespace>(); ResourceMerger.PrepareDocuments(documents, projectPath, projectName, relativeSourceFilePath, existingNamespaces); var existingKeys = new HashSet <string>(); var sourceDoc = LoadDocument(projectPath, relativeSourceFilePath); var resDictString = sourceDoc.Root.Name.LocalName; var defaultNameSpace = sourceDoc.Root.GetDefaultNamespace(); var outputDoc = XDocument.Parse("<" + resDictString + " xmlns=\"" + defaultNameSpace + "\"/>"); foreach (var item in documents.OrderByDescending(item => item.Value.DependencyCount)) { // add attributes foreach (var attribute in item.Value.Document.Root.Attributes()) { outputDoc.Root.SetAttributeValue(attribute.Name, attribute.Value); } var elements = item.Value.Document.Root.Elements().Where(e => !e.Name.LocalName.StartsWith(resDictString)).ToList(); var elementKeys = elements.Select(GetKey); // TODO: not sure about this part. our xamls contained duplicate keys such as "BooleanToVisibilityConverter". // obviously we need only one of them. but if two keys actually reference completely different things, this might be a bad idea // better warn the user and let him fix it? outputDoc.Root.Add(elements.Where(e => !existingKeys.Contains(GetKey(e)))); existingKeys.UnionWith(elementKeys); existingKeys.ExceptWith(new string[] { null }); } using (var ms = new MemoryStream()) { outputDoc.Save(ms); // TODO: I don't think we need this. If we include this into our build process, we don't wanna waste time if (OutputEqualsExistingFileContent(Path.Combine(projectPath, relativeOutputFilePath), ms.ToArray())) { return; } } outputDoc.Save(projectPath + relativeOutputFilePath); }
/// <summary> /// save all resources into one big resource dictionary respecting the dependencies to increase performance /// </summary> /// <param name="projectPath">project path (C:/..)</param> /// <param name="relativeSourceFilePath">relative source file path (/LookAndFeel.xaml)</param> /// <param name="relativeOutputFilePath">relative output file path (/xGeneric/Generic.xaml)</param> /// <param name="projectName">project name</param> /// <param name="resDictString">resource dictionary string (node name)</param> public static void MergeResources(string projectPath, string projectName = null, string relativeSourceFilePath = "/LookAndFeel.xaml", string relativeOutputFilePath = "/FullLookAndFeel.xaml") { // if project path does not exist throw exception if (!Directory.Exists(projectPath)) { Helpers.ThrowException <Exception>(PROJECT_PATH_EXCEPTION); } // Get default values for optional parameters projectName = string.IsNullOrEmpty(projectName) ? Path.GetFileName(Path.GetDirectoryName(projectPath)) : projectName; // if relativeSourceFilePath is not of type .xaml throw exception if (!relativeSourceFilePath.EndsWith(".xaml", StringComparison.InvariantCultureIgnoreCase)) { Helpers.ThrowException <Exception>(SOURCE_TYPE_EXCEPTION); } // if relativeOutputFilePath is not of type .xaml throw exception if (!relativeOutputFilePath.EndsWith(".xaml", StringComparison.InvariantCultureIgnoreCase)) { Helpers.ThrowException <Exception>(OUTPUT_TYPE_EXCEPTION); } // create sourceFilePath var sourceFilePath = projectPath + relativeSourceFilePath; // if source file does not exist throw exception if (!File.Exists(sourceFilePath)) { Helpers.ThrowException <Exception>(SOURCE_EXCEPTION + sourceFilePath); } // load source doc var sourceDoc = XDocument.Load(sourceFilePath); // get default namespace for doc creation and filtering var defaultNameSpace = sourceDoc.Root.GetDefaultNamespace(); // get res dict string var resDictString = sourceDoc.Root.Name.LocalName; // create output doc var outputDoc = XDocument.Parse("<" + resDictString + " xmlns=\"" + defaultNameSpace + "\"/>"); // create documents var documents = new Dictionary <string, Data>(); // add elements ResourceMerger.PrepareDocuments(ref documents, projectPath, projectName, relativeSourceFilePath); // add elements (ordered by dependency count) foreach (var item in documents.OrderByDescending(item => item.Value.DependencyCount)) { // add attributes foreach (var attribute in item.Value.Document.Root.Attributes()) { outputDoc.Root.SetAttributeValue(attribute.Name, attribute.Value); } // add elements outputDoc.Root.Add(item.Value.Document.Root.Elements().Where(e => !e.Name.LocalName.StartsWith(resDictString))); } using (var ms = new MemoryStream()) { outputDoc.Save(ms); if (OutputEqualsExistingFileContent(Path.Combine(projectPath, relativeOutputFilePath), ms.ToArray())) { return; } } // save file outputDoc.Save(projectPath + relativeOutputFilePath); }
/// <summary> /// save all resources into one big resource dictionary respecting the dependencies to increase performance /// </summary> /// <param name="projectPath">project path (C:/..)</param> /// <param name="relativeSourceFilePath">relative source file path (/LookAndFeel.xaml)</param> /// <param name="relativeOutputFilePath">relative output file path (/xGeneric/Generic.xaml)</param> /// <param name="projectName">project name</param> /// <param name="resDictString">resource dictionary string (node name)</param> public static void MergeResources(string projectPath, string projectName = null, string relativeSourceFilePath = "/LookAndFeel.xaml", string relativeOutputFilePath = "/FullLookAndFeel.xaml") { // if project path does not exist throw exception if (!Directory.Exists(projectPath)) { throw new DirectoryNotFoundException($"Project path `{projectPath}` does not exist."); } // Get default values for optional parameters projectName = string.IsNullOrEmpty(projectName) ? Path.GetFileName(Path.GetDirectoryName(projectPath)) : projectName; // if relativeSourceFilePath is not of type .xaml throw exception if (!relativeSourceFilePath.EndsWith(".xaml", StringComparison.InvariantCultureIgnoreCase)) { throw new InvalidOperationException($"The relative source file `{relativeSourceFilePath}` should have a .xaml extension."); } // if relativeOutputFilePath is not of type .xaml throw exception if (!relativeOutputFilePath.EndsWith(".xaml", StringComparison.InvariantCultureIgnoreCase)) { throw new InvalidOperationException($"The relative output file `{relativeOutputFilePath}` should have a .xaml extension."); } // create sourceFilePath var sourceFilePath = projectPath + relativeSourceFilePath; // if source file does not exist throw exception if (!File.Exists(sourceFilePath)) { throw new FileNotFoundException($"The source file `{sourceFilePath}` was not found."); } // load source doc var sourceDoc = XDocument.Load(sourceFilePath); // get default namespace for doc creation and filtering var defaultNameSpace = sourceDoc.Root.GetDefaultNamespace(); // get res dict string var resDictString = sourceDoc.Root.Name.LocalName; // create output doc var outputDoc = XDocument.Parse("<" + resDictString + " xmlns=\"" + defaultNameSpace + "\"/>"); // create documents var documents = new Dictionary <string, Data>(); // create dictionary for references that cannot be resolved locally. var unresolvedRefs = new HashSet <string>(); // add elements ResourceMerger.PrepareDocuments(ref documents, unresolvedRefs, projectPath, projectName, relativeSourceFilePath); // add referenced elements if (unresolvedRefs.Any()) { var xnsp = outputDoc.Root.GetDefaultNamespace(); var mergedDicts = unresolvedRefs .Select(x => new XElement(xnsp + resDictString, new XAttribute("Source", x))) .ToArray(); var elm = new XElement(xnsp + resDictString + ".MergedDictionaries", mergedDicts); outputDoc.Root.Add(elm); } // add elements (ordered by dependency count) foreach (var item in documents.OrderByDescending(item => item.Value.DependencyCount)) { // add attributes foreach (var attribute in item.Value.Document.Root.Attributes()) { outputDoc.Root.SetAttributeValue(attribute.Name, attribute.Value); } // add elements outputDoc.Root.Add(item.Value.Document.Root.Elements().Where(e => !e.Name.LocalName.StartsWith(resDictString))); } using (var ms = new MemoryStream()) { outputDoc.Save(ms); if (OutputEqualsExistingFileContent(Path.Combine(projectPath, relativeOutputFilePath), ms.ToArray())) { return; } } // save file outputDoc.Save(projectPath + relativeOutputFilePath); }