// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. namespace WixToolset.Harvesters.Serialize { using System; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; using System.Xml; using WixToolset.Harvesters.Extensibility.Serialize; /// <summary> /// Class used for reading XML files in to the CodeDom. /// </summary> public class CodeDomReader { private Assembly[] assemblies; /// <summary> /// Creates a new CodeDomReader, using the current assembly. /// </summary> public CodeDomReader() { this.assemblies = new Assembly[] { Assembly.GetExecutingAssembly() }; } /// <summary> /// Creates a new CodeDomReader, and takes in a list of assemblies in which to /// look for elements. /// </summary> /// <param name="assemblies">Assemblies in which to look for types that correspond /// to elements.</param> public CodeDomReader(Assembly[] assemblies) { this.assemblies = assemblies; } /// <summary> /// Loads an XML file into a strongly-typed code dom. /// </summary> /// <param name="filePath">File to load into the code dom.</param> /// <returns>The strongly-typed object at the root of the tree.</returns> [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.InvalidOperationException.#ctor(System.String)")] public ISchemaElement Load(string filePath) { XmlDocument document = new XmlDocument(); document.Load(filePath); ISchemaElement schemaElement = null; foreach (XmlNode node in document.ChildNodes) { XmlElement element = node as XmlElement; if (element != null) { if (schemaElement != null) { throw new InvalidOperationException(WixHarvesterStrings.EXP_MultipleRootElementsFoundInFile); } schemaElement = this.CreateObjectFromElement(element); this.ParseObjectFromElement(schemaElement, element); } } return schemaElement; } /// <summary> /// Sets an attribute on an ISchemaElement. /// </summary> /// <param name="schemaElement">Schema element to set attribute on.</param> /// <param name="name">Name of the attribute to set.</param> /// <param name="value">Value to set on the attribute.</param> [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.InvalidOperationException.#ctor(System.String)")] private static void SetAttributeOnObject(ISchemaElement schemaElement, string name, string value) { ISetAttributes setAttributes = schemaElement as ISetAttributes; if (setAttributes == null) { throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixHarvesterStrings.EXP_ISchemaElementDoesnotImplementISetAttribute, schemaElement.GetType().FullName)); } else { setAttributes.SetAttribute(name, value); } } /// <summary> /// Parses an ISchemaElement from the XmlElement. /// </summary> /// <param name="schemaElement">ISchemaElement to fill in.</param> /// <param name="element">XmlElement to parse from.</param> [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.InvalidOperationException.#ctor(System.String)")] private void ParseObjectFromElement(ISchemaElement schemaElement, XmlElement element) { foreach (XmlAttribute attribute in element.Attributes) { SetAttributeOnObject(schemaElement, attribute.LocalName, attribute.Value); } foreach (XmlNode node in element.ChildNodes) { XmlElement childElement = node as XmlElement; if (childElement != null) { ISchemaElement childSchemaElement = null; ICreateChildren createChildren = schemaElement as ICreateChildren; if (createChildren == null) { throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixHarvesterStrings.EXP_ISchemaElementDoesnotImplementICreateChildren, element.LocalName)); } else { childSchemaElement = createChildren.CreateChild(childElement.LocalName); } if (childSchemaElement == null) { childSchemaElement = this.CreateObjectFromElement(childElement); if (childSchemaElement == null) { throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixHarvesterStrings.EXP_XmlElementDoesnotHaveISchemaElement, childElement.LocalName)); } } this.ParseObjectFromElement(childSchemaElement, childElement); IParentElement parentElement = (IParentElement)schemaElement; parentElement.AddChild(childSchemaElement); } else { XmlText childText = node as XmlText; if (childText != null) { SetAttributeOnObject(schemaElement, "Content", childText.Value); } } } } /// <summary> /// Creates an object from an XML element by digging through the assembly list. /// </summary> /// <param name="element">XML Element to create an ISchemaElement from.</param> /// <returns>A constructed ISchemaElement.</returns> private ISchemaElement CreateObjectFromElement(XmlElement element) { ISchemaElement schemaElement = null; foreach (Assembly assembly in this.assemblies) { foreach (Type type in assembly.GetTypes()) { if (type.FullName.EndsWith(element.LocalName, StringComparison.Ordinal) && typeof(ISchemaElement).IsAssignableFrom(type)) { schemaElement = (ISchemaElement)Activator.CreateInstance(type); } } } return schemaElement; } } }