// 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.Serialize { using System; using System.Collections; using System.Reflection; using System.Xml; /// /// Class used for reading XML files in to the CodeDom. /// public class CodeDomReader { private Assembly[] assemblies; /// /// Creates a new CodeDomReader, using the current assembly. /// public CodeDomReader() { this.assemblies = new Assembly[] { Assembly.GetExecutingAssembly() }; } /// /// Creates a new CodeDomReader, and takes in a list of assemblies in which to /// look for elements. /// /// Assemblies in which to look for types that correspond /// to elements. public CodeDomReader(Assembly[] assemblies) { this.assemblies = assemblies; } /// /// Loads an XML file into a strongly-typed code dom. /// /// File to load into the code dom. /// The strongly-typed object at the root of the tree. 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("Multiple root elements found in file."); } schemaElement = this.CreateObjectFromElement(element); this.ParseObjectFromElement(schemaElement, element); } } return schemaElement; } /// /// Parses an ISchemaElement from the XmlElement. /// /// ISchemaElement to fill in. /// XmlElement to parse from. private void ParseObjectFromElement(ISchemaElement schemaElement, XmlElement element) { foreach (XmlAttribute attribute in element.Attributes) { this.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("ISchemaElement with name " + element.LocalName + " does not implement ICreateChildren."); } else { childSchemaElement = createChildren.CreateChild(childElement.LocalName); } if (childSchemaElement == null) { childSchemaElement = this.CreateObjectFromElement(childElement); if (childSchemaElement == null) { throw new InvalidOperationException("XmlElement with name " + childElement.LocalName + " does not have a corresponding ISchemaElement."); } } this.ParseObjectFromElement(childSchemaElement, childElement); IParentElement parentElement = (IParentElement)schemaElement; parentElement.AddChild(childSchemaElement); } else { XmlText childText = node as XmlText; if (childText != null) { this.SetAttributeOnObject(schemaElement, "Content", childText.Value); } } } } /// /// Sets an attribute on an ISchemaElement. /// /// Schema element to set attribute on. /// Name of the attribute to set. /// Value to set on the attribute. private void SetAttributeOnObject(ISchemaElement schemaElement, string name, string value) { ISetAttributes setAttributes = schemaElement as ISetAttributes; if (setAttributes == null) { throw new InvalidOperationException("ISchemaElement with name " + schemaElement.GetType().FullName.ToString() + " does not implement ISetAttributes."); } else { setAttributes.SetAttribute(name, value); } } /// /// Creates an object from an XML element by digging through the assembly list. /// /// XML Element to create an ISchemaElement from. /// A constructed ISchemaElement. 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) && typeof(ISchemaElement).IsAssignableFrom(type)) { schemaElement = (ISchemaElement)Activator.CreateInstance(type); } } } return schemaElement; } } }