/// <summary> /// <c>ParseManifest</c> parses the XML template manifest indicated by <paramref name="templatePath"/> /// and creates a corresponding instance of <c>TemplateManifest</c>. /// </summary> /// <param name="templatePath">The full path of the template</param> /// <param name="parseFlags">Specifies settings related to template manifest creation</param> /// <returns>a reference to the newly created <c>TemplateManifest</c></returns> public static TemplateManifest ParseManifest(string templatePath, ManifestParseFlags parseFlags) { string fileName = Path.GetFileName(templatePath); TemplateLocation fileLoc = new PathTemplateLocation(Path.GetDirectoryName(templatePath)); return(ParseManifest(fileName, fileLoc, parseFlags)); }
/// <summary> /// Gets the template manifest for this template. Can optionally parse an entire template manifest spanning tree. /// See <see cref="ManifestParseFlags"/> for details. /// </summary> /// <param name="parseFlags">See <see cref="ManifestParseFlags"/>.</param> /// <returns></returns> public TemplateManifest GetManifest(ManifestParseFlags parseFlags) { return(TemplateManifest.ParseManifest(FileName, Location, parseFlags)); }
/// <summary> /// Gets the template manifest for this template. Can optionally parse an entire template manifest spanning tree. /// See <see cref="ManifestParseFlags"/> for details. /// </summary> /// <param name="parseFlags">See <see cref="ManifestParseFlags"/>.</param> /// <returns></returns> public TemplateManifest GetManifest(ManifestParseFlags parseFlags) { return TemplateManifest.ParseManifest(FileName, Location, parseFlags); }
private static HashSet <T> GetHashSet <T>(ManifestParseFlags parseFlags, ManifestParseFlags flag) where T : class { return(((parseFlags & flag) == flag) ? new HashSet <T>() : null); }
/// <summary> /// <c>ParseManifest</c> parses the XML template manifest indicated by <paramref name="fileName"/> /// and <paramref name="location"/>, and creates a corresponding instance of <c>TemplateManifest</c>. /// </summary> /// <param name="fileName">The file name of the template</param> /// <param name="location">The location of the template, such as a file system folder, a package file, a database, etc.</param> /// <param name="parseFlags">Specifies settings related to template manifest creation</param> /// <returns>a reference to the newly created <c>TemplateManifest</c></returns> public static TemplateManifest ParseManifest(string fileName, TemplateLocation location, ManifestParseFlags parseFlags) { TemplateManifest templateManifest = new TemplateManifest(); TemplateFileLocation baseTemplateLoc = new TemplateFileLocation(fileName, location); HashSet <VariableInfo> variables = GetHashSet <VariableInfo>(parseFlags, ManifestParseFlags.ParseVariables); HashSet <Dependency> dependencies = GetHashSet <Dependency>(parseFlags, ManifestParseFlags.ParseDependencies); HashSet <AdditionalFile> additionalFiles = GetHashSet <AdditionalFile>(parseFlags, ManifestParseFlags.ParseAdditionalFiles); HashSet <DataSource> dataSources = GetHashSet <DataSource>(parseFlags, ManifestParseFlags.ParseDataSources); Queue <TemplateFileLocation> templateQueue = new Queue <TemplateFileLocation>(); HashSet <TemplateFileLocation> processedTemplates = new HashSet <TemplateFileLocation>(); // Add the base template to the queue templateQueue.Enqueue(baseTemplateLoc); while (templateQueue.Count > 0) { TemplateFileLocation templateFileLoc = templateQueue.Dequeue(); if (!processedTemplates.Contains(templateFileLoc)) { try { // TODO: Condider re-writing this using an XmlReader so that the entire document does not need to be allocated in a DOM. Doing so // should make processing template manifest files faster. For now using an XDocument to just get things done fast. XDocument manifest; using (Stream manifestStream = templateFileLoc.FileLocation.GetFile(GetManifestName(templateFileLoc.FileName))) { // Read the template manifest so that it can be parsed. manifest = XDocument.Load(manifestStream, LoadOptions.None); } if (templateFileLoc.Equals(baseTemplateLoc)) { // Process the root templateManifest element. templateManifest.HotDocsVersion = manifest.Root.Attribute("hotdocsVersion").Value; templateManifest.TemplateId = manifest.Root.Attribute("templateId").Value; templateManifest.FileName = manifest.Root.Attribute("fileName").Value; templateManifest.EffectiveCmpFileName = manifest.Root.Attribute("effectiveCmpFile").Value; if (manifest.Root.Attribute("expirationDate") != null) { templateManifest.ExpirationDate = DateTime.Parse(manifest.Root.Attribute("expirationDate").Value); if (manifest.Root.Attribute("warningDays") != null) { templateManifest.WarningDays = int.Parse(manifest.Root.Attribute("warningDays").Value); } if (manifest.Root.Attribute("extensionDays") != null) { templateManifest.ExtensionDays = int.Parse(manifest.Root.Attribute("extensionDays").Value); } } var titleElem = manifest.Root.Element(s_namespace + "title"); templateManifest.Title = (titleElem != null) ? titleElem.Value.Trim() : string.Empty; var descriptionElem = manifest.Root.Element(s_namespace + "description"); templateManifest.Description = (descriptionElem != null) ? descriptionElem.Value.Trim() : string.Empty; } if (variables != null) { // Process the variables element. var variablesElem = manifest.Root.Element(s_namespace + "variables"); if (variablesElem != null) { // Add any not yet encountered variable to the variables collection. foreach (var variableElem in variablesElem.Elements(s_namespace + "variable")) { ValueType valueType; switch (variableElem.Attribute("type").Value) { case "text": valueType = ValueType.Text; break; case "number": valueType = ValueType.Number; break; case "date": valueType = ValueType.Date; break; case "trueFalse": valueType = ValueType.TrueFalse; break; case "multipleChoice": valueType = ValueType.MultipleChoice; break; default: valueType = ValueType.Unknown; break; } variables.Add(new VariableInfo(variableElem.Attribute("name").Value, valueType)); } } } if (dependencies != null) { // Process the dependencies element. var dependenciesElem = manifest.Root.Element(s_namespace + "dependencies"); if (dependenciesElem != null) { // Add any not yet encountered dependency to the dependencies collection. foreach (var dependencyElem in dependenciesElem.Elements(s_namespace + "dependency")) { string hintPath = (dependencyElem.Attribute("hintPath") != null) ? dependencyElem.Attribute("hintPath").Value : null; DependencyType dependencyType; switch (dependencyElem.Attribute("type").Value) { case "baseCmpFile": dependencyType = DependencyType.BaseCmpFile; break; case "pointedToCmpFile": dependencyType = DependencyType.PointedToCmpFile; break; case "templateInsert": dependencyType = DependencyType.TemplateInsert; break; case "clauseInsert": dependencyType = DependencyType.ClauseInsert; break; case "clauseLibraryInsert": dependencyType = DependencyType.ClauseLibraryInsert; break; case "imageInsert": dependencyType = DependencyType.ImageInsert; break; case "interviewImage": dependencyType = DependencyType.InterviewImage; break; case "assemble": dependencyType = DependencyType.Assemble; break; case "publisherMapFile": dependencyType = DependencyType.PublisherMapFile; break; case "userMapFile": dependencyType = DependencyType.UserMapFile; break; case "additionalTemplate": dependencyType = DependencyType.AdditionalTemplate; break; default: throw new Exception(string.Format("Invalid dependency type '{0}'.", dependencyElem.Attribute("type").Value)); } dependencies.Add(new Dependency(dependencyElem.Attribute("fileName").Value, hintPath, dependencyType)); } } } if (additionalFiles != null) { // Process the additionalFiles element. var additionalFilesElem = manifest.Root.Element(s_namespace + "additionalFiles"); if (additionalFilesElem != null) { // Add any not yet encountered additionalFile to the additionalFiles collection. foreach (var fileElem in additionalFilesElem.Elements(s_namespace + "file")) { additionalFiles.Add(new AdditionalFile(fileElem.Attribute("fileName").Value)); } } } if (dataSources != null) { // Process the dataSources element. var dataSourcesElem = manifest.Root.Element(s_namespace + "dataSources"); if (dataSourcesElem != null) { // Add any not yet encountered dataSource to the dataSources collection. foreach (var dataSourceElem in dataSourcesElem.Elements(s_namespace + "dataSource")) { DataSourceType dataSourceType; switch (dataSourceElem.Attribute("type").Value) { case "currentAnswerFile": dataSourceType = DataSourceType.CurrentAnswerFile; break; case "answerFile": dataSourceType = DataSourceType.AnswerFile; break; case "databaseComponent": dataSourceType = DataSourceType.DatabaseComponent; break; case "custom": dataSourceType = DataSourceType.Custom; break; default: throw new Exception(string.Format("Invalid data source type '{0}'.", dataSourceElem.Attribute("type").Value)); } List <DataSourceField> dataSourceFields = new List <DataSourceField>(); foreach (var dataSourceFieldElem in dataSourceElem.Elements(s_namespace + "dataSourceField")) { DataSourceFieldType fieldType; switch (dataSourceFieldElem.Attribute("type").Value) { case "text": fieldType = DataSourceFieldType.Text; break; case "number": fieldType = DataSourceFieldType.Number; break; case "date": fieldType = DataSourceFieldType.Date; break; case "trueFalse": fieldType = DataSourceFieldType.TrueFalse; break; default: throw new Exception(string.Format("Invalid data source field type '{0}'.", dataSourceFieldElem.Attribute("type").Value)); } DataSourceBackfillType backfillType; switch (dataSourceFieldElem.Attribute("backfill").Value) { case "never": backfillType = DataSourceBackfillType.Never; break; case "always": backfillType = DataSourceBackfillType.Always; break; case "prompt": backfillType = DataSourceBackfillType.Prompt; break; case "doNotAllow": backfillType = DataSourceBackfillType.DoNotAllow; break; default: throw new Exception(string.Format("Invalid data source backfill type '{0}'.", dataSourceFieldElem.Attribute("backfill").Value)); } bool isKey = (dataSourceFieldElem.Attribute("isKey") != null) ? Convert.ToBoolean(dataSourceFieldElem.Attribute("isKey").Value) : false; dataSourceFields.Add(new DataSourceField(dataSourceFieldElem.Attribute("sourceName").Value, fieldType, backfillType, isKey)); } dataSources.Add(new DataSource(dataSourceElem.Attribute("id").Value, dataSourceElem.Attribute("name").Value, dataSourceType, dataSourceFields.ToArray())); } } } if ((parseFlags & ManifestParseFlags.ParseRecursively) == ManifestParseFlags.ParseRecursively) { // Add any referenced templates to the template queue. var dependenciesElem = manifest.Root.Element(s_namespace + "dependencies"); if (dependenciesElem != null) { var templateDependencies = from d in dependenciesElem.Elements(s_namespace + "dependency") let type = d.Attribute("type").Value where type == "templateInsert" || type == "additionalTemplate" select d; foreach (var templateDependency in templateDependencies) { templateQueue.Enqueue(GetDependencyFileLocation(baseTemplateLoc, (templateDependency.Attribute("hintPath") != null) ? templateDependency.Attribute("hintPath").Value : null, templateDependency.Attribute("fileName").Value)); } } // Mark the template as processed so that its manifest will not get processed again. processedTemplates.Add(templateFileLoc); } } catch (Exception e) { string errorText = String.Format("Failed to read the manifest file for the template:\r\n\r\n {0} \r\n\r\n" + "The following error occurred:\r\n\r\n {1} ", templateFileLoc.FileName, e.Message); throw new Exception(errorText, e); } } } if (variables != null) { templateManifest.Variables = variables.ToArray(); } if (dependencies != null) { templateManifest.Dependencies = dependencies.ToArray(); } if (additionalFiles != null) { templateManifest.AdditionalFiles = additionalFiles.ToArray(); } if (dataSources != null) { templateManifest.DataSources = dataSources.ToArray(); } return(templateManifest); }