using System; using System.Collections.Generic; using System.Linq; using ICD.Common.Properties; using ICD.Common.Utils.EventArguments; using ICD.Common.Utils.Extensions; #if SIMPLSHARP using Crestron.SimplSharp.CrestronXml; #else using System.Xml; #endif namespace ICD.Common.Utils.Xml { public static class XmlReaderExtensions { #region Attributes /// /// Returns true if the attribute exists. /// /// /// /// [PublicAPI] public static bool HasAttribute(this IcdXmlReader extends, string name) { if (extends == null) throw new ArgumentNullException("extends"); string unused; return extends.TryGetAttribute(name, out unused); } /// /// Returns true if the attribute exists. /// /// /// /// /// [PublicAPI] public static bool TryGetAttribute(this IcdXmlReader extends, string name, out string value) { return (value = extends.GetAttribute(name)) != null; } /// /// Gets the attributes for the current element without moving the reader. /// /// /// [PublicAPI] public static IEnumerable> GetAttributes(this IcdXmlReader extends) { if (extends == null) throw new ArgumentNullException("extends"); while (extends.MoveToNextAttribute()) yield return new KeyValuePair(extends.Name, extends.Value); // Move back to element. extends.MoveToElement(); } /// /// Gets the value of the attribute with the given name. /// /// /// /// [PublicAPI] public static string GetAttributeAsString(this IcdXmlReader extends, string name) { if (extends == null) throw new ArgumentNullException("extends"); string output = extends.GetAttribute(name); if (output == null) throw new FormatException(string.Format("Missing attribute \"{0}\"", name)); return output; } /// /// Gets the value of the attribute with the given name and returns as an integer. /// /// /// /// [PublicAPI] public static int GetAttributeAsInt(this IcdXmlReader extends, string name) { if (extends == null) throw new ArgumentNullException("extends"); string value = extends.GetAttributeAsString(name); return int.Parse(value); } /// /// Gets the value of the attribute with the given name and returns as a bool. /// /// /// /// [PublicAPI] public static bool GetAttributeAsBool(this IcdXmlReader extends, string name) { if (extends == null) throw new ArgumentNullException("extends"); string value = extends.GetAttributeAsString(name); return bool.Parse(value); } /// /// Gets the value of the attribute with the given name and returns as a GUID. /// /// /// /// [PublicAPI] public static Guid GetAttributeAsGuid(this IcdXmlReader extends, string name) { if (extends == null) throw new ArgumentNullException("extends"); string value = extends.GetAttributeAsString(name); return new Guid(value); } #endregion #region Recurse /// /// Recurses through the entire XML, calling the callback for each Element/Text node. /// /// /// [PublicAPI] public static void Recurse(this IcdXmlReader extends, Func callback) { if (extends == null) throw new ArgumentNullException("extends"); XmlUtils.Recurse(extends.ReadString(), callback); } #endregion #region Skip /// /// Skips over insignificant whitespace. /// /// [PublicAPI] public static void SkipInsignificantWhitespace(this IcdXmlReader extends) { if (extends == null) throw new ArgumentNullException("extends"); while (extends.NodeType == XmlNodeType.Whitespace && extends.Read()) { } } /// /// Continues reading until an element is reached. /// /// [PublicAPI] public static bool ReadToNextElement(this IcdXmlReader extends) { if (extends == null) throw new ArgumentNullException("extends"); while (extends.Read() && extends.NodeType != XmlNodeType.Element) { } return extends.NodeType == XmlNodeType.Element; } #endregion #region Get Child Element /// /// Returns true if the current node has child elements. /// /// /// public static bool HasChildElements(this IcdXmlReader extends) { if (extends == null) throw new ArgumentNullException("extends"); while (extends.Read() && extends.NodeType != XmlNodeType.EndElement) { if (extends.NodeType == XmlNodeType.Element) return true; } return false; } /// /// Gets the child element with the given name under the current element. /// /// /// /// public static IcdXmlReader GetChildElement(this IcdXmlReader extends, string element) { if (extends == null) throw new ArgumentNullException("extends"); IcdXmlReader output; if (extends.GetChildElements(element).TryFirst(out output)) return output; throw new FormatException("No child element with name " + element); } /// /// Gets the child elements for the current element. /// /// /// public static IEnumerable GetChildElements(this IcdXmlReader extends) { if (extends == null) throw new ArgumentNullException("extends"); foreach (IcdXmlReader output in extends.GetChildElementsAsString().Select(child => new IcdXmlReader(child))) { output.ReadToNextElement(); yield return output; } } /// /// Gets the child elements for the current element. /// /// /// /// public static IEnumerable GetChildElements(this IcdXmlReader extends, string element) { if (extends == null) throw new ArgumentNullException("extends"); foreach (IcdXmlReader output in extends.GetChildElementsAsString(element).Select(child => new IcdXmlReader(child))) { output.ReadToNextElement(); yield return output; } } /// /// Gets the child elements for the current element. /// /// /// [PublicAPI] public static IEnumerable GetChildElementsAsString(this IcdXmlReader extends) { if (extends == null) throw new ArgumentNullException("extends"); // Step into the first child. extends.ReadToNextElement(); while (extends.NodeType == XmlNodeType.Element || extends.NodeType == XmlNodeType.Comment) { switch (extends.NodeType) { case XmlNodeType.Comment: extends.Skip(); break; case XmlNodeType.Element: yield return extends.ReadOuterXml(); break; } extends.SkipInsignificantWhitespace(); } } /// /// Gets the child elements for the current element. /// /// /// /// [PublicAPI] public static IEnumerable GetChildElementsAsString(this IcdXmlReader extends, string element) { if (extends == null) throw new ArgumentNullException("extends"); // Step into the first child. extends.ReadToNextElement(); while (extends.NodeType == XmlNodeType.Element || extends.NodeType == XmlNodeType.Comment) { switch (extends.NodeType) { case XmlNodeType.Comment: extends.Skip(); break; case XmlNodeType.Element: string name = extends.Name; string output = extends.ReadOuterXml(); if (name == element) yield return output; break; } extends.SkipInsignificantWhitespace(); } } public static bool TryGetChildElementAsString(this IcdXmlReader extends, string element, out string output) { if (extends == null) throw new ArgumentNullException("extends"); return extends.GetChildElementsAsString(element).TryFirst(out output); } #endregion #region Read Element Content /// /// Parses the element content in the format 0xXX as a byte. /// /// /// [PublicAPI] public static byte ReadElementContentAsByte(this IcdXmlReader extends) { if (extends == null) throw new ArgumentNullException("extends"); string content = extends.ReadElementContentAsString(); return StringUtils.FromIpIdString(content); } /// /// Parses the element content as a uint. /// /// /// [PublicAPI] public static uint ReadElementContentAsUint(this IcdXmlReader extends) { if (extends == null) throw new ArgumentNullException("extends"); string content = extends.ReadElementContentAsString(); return IcdXmlConvert.ToUInt32(content); } /// /// Parses the element content as a uint. /// /// /// [PublicAPI] public static int ReadElementContentAsInt(this IcdXmlReader extends) { if (extends == null) throw new ArgumentNullException("extends"); string content = extends.ReadElementContentAsString(); return IcdXmlConvert.ToInt32(content); } /// /// Parses the element content as a ushort. /// /// /// [PublicAPI] public static ushort ReadElementContentAsUShort(this IcdXmlReader extends) { if (extends == null) throw new ArgumentNullException("extends"); string content = extends.ReadElementContentAsString(); return IcdXmlConvert.ToUInt16(content); } /// /// Parses the element content as a short. /// /// /// [PublicAPI] public static short ReadElementContentAsShort(this IcdXmlReader extends) { if (extends == null) throw new ArgumentNullException("extends"); string content = extends.ReadElementContentAsString(); return IcdXmlConvert.ToInt16(content); } /// /// Parses the element content as a TimeSpan. /// /// /// [PublicAPI] public static TimeSpan ReadElementContentAsTimeSpan(this IcdXmlReader extends) { if (extends == null) throw new ArgumentNullException("extends"); string content = extends.ReadElementContentAsString(); try { // 00:00:00 format return TimeSpan.Parse(content); } catch (FormatException) { } // PT0S format return IcdXmlConvert.ToTimeSpan(content); } /// /// Parses the element content as a DateTime. /// /// /// [PublicAPI] public static DateTime ReadElementContentAsDateTime(this IcdXmlReader extends) { if (extends == null) throw new ArgumentNullException("extends"); string content = extends.ReadElementContentAsString(); return IcdXmlConvert.ToDateTime(content); } /// /// Parses the element content as an enum. /// /// /// /// [PublicAPI] public static T ReadElementContentAsEnum(this IcdXmlReader extends, bool ignoreCase) where T : struct, IConvertible { if (extends == null) throw new ArgumentNullException("extends"); string content = extends.ReadElementContentAsString(); return EnumUtils.Parse(content, ignoreCase); } #endregion } }