// 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;
///
/// 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.
[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;
}
///
/// Sets an attribute on an ISchemaElement.
///
/// Schema element to set attribute on.
/// Name of the attribute to set.
/// Value to set on the attribute.
[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);
}
}
///
/// Parses an ISchemaElement from the XmlElement.
///
/// ISchemaElement to fill in.
/// XmlElement to parse from.
[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);
}
}
}
}
///
/// 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, StringComparison.Ordinal)
&& typeof(ISchemaElement).IsAssignableFrom(type))
{
schemaElement = (ISchemaElement)Activator.CreateInstance(type);
}
}
}
return schemaElement;
}
}
}