using System; using System.Collections.Generic; using System.Linq; using System.Text; using ICD.Common.EventArguments; using ICD.Common.Properties; using ICD.Common.Utils.IO; namespace ICD.Common.Utils.Xml { /// /// XmlUtils provides utility methods for working with XML. /// public static class XmlUtils { /// /// Returns the contents of the outermost element as a string. /// /// /// [PublicAPI] public static string GetInnerXml(string xml) { using (IcdXmlReader reader = new IcdXmlReader(xml)) { reader.SkipToNextElement(); return reader.ReadInnerXml(); } } #region Attributes /// /// Returns true if the attribute exists. /// /// /// /// [PublicAPI] public static bool HasAttribute(string xml, string name) { using (IcdXmlReader reader = new IcdXmlReader(xml)) return reader.HasAttribute(name); } /// /// Gets the attributes for the current xml element. /// /// /// [PublicAPI] public static IEnumerable GetAttributes(string xml) { using (IcdXmlReader reader = new IcdXmlReader(xml)) { reader.SkipToNextElement(); return reader.GetAttributes(); } } /// /// Convenience method for getting attribute by name. /// /// /// /// [PublicAPI] public static IcdXmlAttribute GetAttribute(string xml, string name) { return GetAttributes(xml).First(a => a.Name == name); } /// /// Gets the value of the attribute with the given name. /// /// /// /// [PublicAPI] public static string GetAttributeAsString(string xml, string name) { using (IcdXmlReader reader = new IcdXmlReader(xml)) { reader.SkipToNextElement(); return reader.GetAttributeAsString(name); } } /// /// Gets the value of the attribute with the given name and returns as an integer. /// /// /// /// [PublicAPI] public static int GetAttributeAsInt(string xml, string name) { using (IcdXmlReader reader = new IcdXmlReader(xml)) { reader.SkipToNextElement(); return reader.GetAttributeAsInt(name); } } /// /// Gets the value of the attribute with the given name and returns as a bool. /// /// /// /// [PublicAPI] public static bool GetAttributeAsBool(string xml, string name) { using (IcdXmlReader reader = new IcdXmlReader(xml)) { reader.SkipToNextElement(); return reader.GetAttributeAsBool(name); } } #endregion #region Recurse /// /// Recurses through the entire XML, calling the callback for each Element/Text node. /// /// /// [PublicAPI] public static void Recurse(string xml, Action callback) { Recurse(xml, new Stack(), callback); } /// /// Recurses through the entire XML, calling the callback for each Element/Text node. /// /// /// /// private static void Recurse(string xml, Stack path, Action callback) { IcdXmlReader childReader; try { childReader = new IcdXmlReader(xml); childReader.SkipToNextElement(); } catch (IcdXmlException) { return; } path.Push(childReader.Name); string[] pathOutput = path.Reverse().ToArray(); callback(new XmlRecursionEventArgs(xml, pathOutput)); foreach (string child in childReader.GetChildElementsAsString()) Recurse(child, path, callback); path.Pop(); childReader.Dispose(); } #endregion #region Get Child Element /// /// Returns true if the given xml element contains at least 1 child element. /// /// /// public static bool HasChildElements(string xml) { using (IcdXmlReader reader = new IcdXmlReader(xml)) { reader.SkipToNextElement(); return reader.HasChildElements(); } } /// /// Gets the child elements from the topmost element in the xml. /// /// /// [PublicAPI] public static IEnumerable GetChildElements(string xml) { IcdXmlReader reader = new IcdXmlReader(xml); reader.SkipToNextElement(); foreach (IcdXmlReader child in reader.GetChildElements()) yield return child; reader.Dispose(); } /// /// Returns the child elements with the given name. /// /// /// [PublicAPI] public static IEnumerable GetChildElementsAsString(string xml, string element) { using (IcdXmlReader reader = new IcdXmlReader(xml)) { reader.SkipToNextElement(); foreach (IcdXmlReader child in reader.GetChildElements()) { string output = null; if (child.Name == element) output = child.ReadOuterXml(); child.Dispose(); if (output != null) yield return output; } } } /// /// Gets the child elements for the current element. /// /// /// [PublicAPI] public static IEnumerable GetChildElementsAsString(string xml) { using (IcdXmlReader reader = new IcdXmlReader(xml)) { reader.SkipToNextElement(); foreach (string item in reader.GetChildElementsAsString()) yield return item; } } /// /// Gets the immediate child element with the given name. /// /// /// /// [PublicAPI] public static string GetChildElementAsString(string xml, string element) { string output; if (!TryGetChildElementAsString(xml, element, out output)) throw new FormatException(string.Format("No child element named {0}", element)); return output; } /// /// Gets the immediate child element with the given name. /// /// /// /// /// Whether or not the method succeeded [PublicAPI] public static bool TryGetChildElementAsString(string xml, string element, out string output) { using (IcdXmlReader reader = new IcdXmlReader(xml)) { reader.SkipToNextElement(); foreach (IcdXmlReader child in reader.GetChildElements()) { output = null; if (child.Name == element) output = child.ReadOuterXml(); child.Dispose(); if (output != null) return true; } } output = null; return false; } #endregion #region Read Child Element /// /// Gets the content of an immediate child. /// /// /// /// [PublicAPI] public static string ReadChildElementContentAsString(string xml, string childElement) { string child = GetChildElementAsString(xml, childElement); using (IcdXmlReader reader = new IcdXmlReader(child)) { reader.SkipToNextElement(); return reader.ReadElementContentAsString(); } } /// /// Gets the content of an immediate child. /// /// /// /// [PublicAPI] public static int ReadChildElementContentAsInt(string xml, string childElement) { string child = GetChildElementAsString(xml, childElement); using (IcdXmlReader reader = new IcdXmlReader(child)) { reader.SkipToNextElement(); return reader.ReadElementContentAsInt(); } } /// /// Gets the content of an immediate child. /// /// /// /// [PublicAPI] public static uint ReadChildElementContentAsUint(string xml, string childElement) { string child = GetChildElementAsString(xml, childElement); using (IcdXmlReader reader = new IcdXmlReader(child)) { reader.SkipToNextElement(); return reader.ReadElementContentAsUint(); } } /// /// Gets the content of an immediate child. /// /// /// /// [PublicAPI] public static long ReadChildElementContentAsLong(string xml, string childElement) { string child = GetChildElementAsString(xml, childElement); using (IcdXmlReader reader = new IcdXmlReader(child)) { reader.SkipToNextElement(); return reader.ReadElementContentAsLong(); } } /// /// Gets the content of an immediate child. /// /// /// /// [PublicAPI] public static ushort ReadChildElementContentAsUShort(string xml, string childElement) { string child = GetChildElementAsString(xml, childElement); using (IcdXmlReader reader = new IcdXmlReader(child)) { reader.SkipToNextElement(); return reader.ReadElementContentAsUShort(); } } /// /// Gets the content of an immediate child. /// /// /// /// [PublicAPI] private static float? ReadChildElementContentAsFloat(string xml, string childElement) { string child = GetChildElementAsString(xml, childElement); using (IcdXmlReader reader = new IcdXmlReader(child)) { reader.SkipToNextElement(); return reader.ReadElementContentAsFloat(); } } /// /// Gets the content of an immediate child. /// /// /// /// [PublicAPI] public static bool ReadChildElementContentAsBoolean(string xml, string childElement) { // IcdXmlReader.ReadElementContentAsBoolean() is too case sensitive string output = ReadChildElementContentAsString(xml, childElement); return bool.Parse(output); } /// /// Gets the content of an immediate child. /// /// /// /// [PublicAPI] public static byte ReadChildElementContentAsByte(string xml, string childElement) { string child = GetChildElementAsString(xml, childElement); using (IcdXmlReader reader = new IcdXmlReader(child)) { reader.SkipToNextElement(); return reader.ReadElementContentAsByte(); } } /// /// Gets the content of an immediate child. /// /// /// /// /// [PublicAPI] public static T ReadChildElementContentAsEnum(string xml, string childElement, bool ignoreCase) { string child = GetChildElementAsString(xml, childElement); using (IcdXmlReader reader = new IcdXmlReader(child)) { reader.SkipToNextElement(); return reader.ReadElementContentAsEnum(ignoreCase); } } #endregion #region Try Read Child Element /// /// Gets the content of the immediate child. Returns null if the child element was not found. /// /// /// /// [PublicAPI] public static string TryReadChildElementContentAsString(string xml, string childElement) { try { return ReadChildElementContentAsString(xml, childElement); } catch (FormatException) { return null; } } /// /// Gets the content of the immediate child. Returns null if the child element was not found. /// /// /// /// [PublicAPI] public static int? TryReadChildElementContentAsInt(string xml, string childElement) { try { return ReadChildElementContentAsInt(xml, childElement); } catch (FormatException) { return null; } } /// /// Gets the content of the immediate child. Returns null if the child element was not found. /// /// /// /// [PublicAPI] public static long? TryReadChildElementContentAsLong(string xml, string childElement) { try { return ReadChildElementContentAsLong(xml, childElement); } catch (FormatException) { return null; } } /// /// Gets the content of the immediate child. Returns null if the child element was not found. /// /// /// /// [PublicAPI] public static ushort? TryReadChildElementContentAsUShort(string xml, string childElement) { try { return ReadChildElementContentAsUShort(xml, childElement); } catch (FormatException) { return null; } } /// /// Gets the content of the immediate child. Returns null if the child element was not found. /// /// /// /// [PublicAPI] public static float? TryReadChildElementContentAsFloat(string xml, string childElement) { try { return ReadChildElementContentAsFloat(xml, childElement); } catch (FormatException) { return null; } } /// /// Gets the content of an immediate child. Returns null if the child element was not found. /// /// /// /// [PublicAPI] public static bool? TryReadChildElementContentAsBoolean(string xml, string childElement) { try { return ReadChildElementContentAsBoolean(xml, childElement); } catch (FormatException) { return null; } } /// /// Gets the content of the immediate child. Returns null if the child element was not found. /// /// /// /// [PublicAPI] public static byte? TryReadChildElementContentAsByte(string xml, string childElement) { try { return ReadChildElementContentAsByte(xml, childElement); } catch (FormatException) { return null; } } /// /// Gets the content of the immediate child. Returns default if the child element could not be parsed. /// /// /// /// /// /// [PublicAPI] public static T? TryReadChildElementContentAsEnum(string xml, string childElement, bool ignoreCase) where T : struct { T? output; return !TryReadChildElementContentAsEnum(xml, childElement, ignoreCase, out output) ? null : output; } /// /// Gets the content of the immediate child. Returns false if the child element could not be parsed. /// /// /// /// /// /// /// [PublicAPI] public static bool TryReadChildElementContentAsEnum(string xml, string childElement, bool ignoreCase, out T output) { output = default(T); try { output = ReadChildElementContentAsEnum(xml, childElement, ignoreCase); return true; } // Null xml catch (ArgumentException) { } catch (FormatException) { } return false; } #endregion #region Read Element Content /// /// Returns the content for a single element. /// /// /// [PublicAPI] public static string ReadElementContent(string xml) { using (IcdXmlReader reader = new IcdXmlReader(xml)) { reader.SkipToNextElement(); return reader.ReadElementContentAsString(); } } /// /// Parses the element content as a uint. /// /// /// [PublicAPI] public static uint ReadElementContentAsUint(string xml) { using (IcdXmlReader reader = new IcdXmlReader(xml)) { reader.Read(); return reader.ReadElementContentAsUint(); } } /// /// Parses the element content as a uint. /// /// /// [PublicAPI] public static int ReadElementContentAsInt(string xml) { using (IcdXmlReader reader = new IcdXmlReader(xml)) { reader.Read(); return reader.ReadElementContentAsInt(); } } /// /// Parses the element content as a uint. /// /// /// [PublicAPI] public static ushort ReadElementContentAsUShort(string xml) { using (IcdXmlReader reader = new IcdXmlReader(xml)) { reader.Read(); return reader.ReadElementContentAsUShort(); } } /// /// Parses the element content as an enum. /// /// /// /// /// [PublicAPI] public static T ReadElementContentAsEnum(string xml, bool ignoreCase) { using (IcdXmlReader reader = new IcdXmlReader(xml)) { reader.Read(); return reader.ReadElementContentAsEnum(ignoreCase); } } #endregion #region Try Read Element Content /// /// Parses the element content as a uint. /// /// /// [PublicAPI] public static uint? TryReadElementContentAsUint(string xml) { IcdXmlReader reader = new IcdXmlReader(xml); reader.Read(); try { return reader.ReadElementContentAsUint(); } catch { return null; } } /// /// Parses the element content as a uint. /// /// /// [PublicAPI] public static int? TryReadElementContentAsInt(string xml) { IcdXmlReader reader = new IcdXmlReader(xml); reader.Read(); try { return reader.ReadElementContentAsInt(); } catch { return null; } } #endregion /// /// Returns the name of the first element in the given xml. /// /// /// /// No element in the xml [PublicAPI] public static string ReadElementName(string xml) { using (IcdXmlReader reader = new IcdXmlReader(xml)) { if (!reader.SkipToNextElement()) throw new FormatException("Unable to read element name, no element in given xml"); return reader.Name; } } #region Read Content /// /// Calls readKey and readValue for each key/value pair in the dict. /// /// /// /// /// /// /// /// public static IEnumerable> ReadDictFromXml( string xml, string rootElement, string childElement, string keyElement, string valueElement, Func readKey, Func readValue) { if (readKey == null) throw new ArgumentNullException("readKey"); if (readValue == null) throw new ArgumentNullException("readValue"); Func> readChild = child => { string key; string value; TryGetChildElementAsString(child, keyElement, out key); TryGetChildElementAsString(child, valueElement, out value); return new KeyValuePair(readKey(key), readValue(value)); }; return ReadListFromXml(xml, rootElement, childElement, readChild); } /// /// Calls childElementCallback for each item in the list. /// /// /// /// /// public static IEnumerable ReadListFromXml(string xml, string rootElement, string childElement, Func readChild) { if (readChild == null) throw new ArgumentNullException("readChild"); if (!TryGetChildElementAsString(xml, rootElement, out xml)) yield break; foreach (string child in GetChildElementsAsString(xml, childElement)) yield return readChild(child); } #endregion #region Write Content /// /// Serializes the given list to XML using IcdXmlConvert to write each key and value. /// /// /// /// /// /// /// /// /// public static void WriteDictToXml(IcdXmlTextWriter writer, IDictionary dict, string rootElement, string childElement, string keyElement, string valueElement) { if (writer == null) throw new ArgumentNullException("writer"); if (dict == null) throw new ArgumentNullException("dict"); Action writeKey = key => writer.WriteElementString(keyElement, IcdXmlConvert.ToString(key)); Action writeValue = value => writer.WriteElementString(valueElement, IcdXmlConvert.ToString(value)); WriteDictToXml(writer, dict, rootElement, childElement, writeKey, writeValue); } /// /// Serializes the given list to XML using the actions to write each item. /// /// /// /// /// /// /// /// /// public static void WriteDictToXml(IcdXmlTextWriter writer, IDictionary dict, string rootElement, string childElement, Action writeKey, Action writeValue) { if (writer == null) throw new ArgumentNullException("writer"); if (dict == null) throw new ArgumentNullException("dict"); if (writeKey == null) throw new ArgumentNullException("writeKey"); if (writeValue == null) throw new ArgumentNullException("writeValue"); Action> writeItem = pair => { writer.WriteStartElement(childElement); { writeKey(pair.Key); writeValue(pair.Value); } writer.WriteEndElement(); }; WriteListToXml(writer, dict, rootElement, writeItem); } /// /// Serializes the given list to XML using IcdXmlConvert to write each item. /// /// /// /// /// /// public static void WriteListToXml(IcdXmlTextWriter writer, IEnumerable list, string listElement, string childElement) { if (writer == null) throw new ArgumentNullException("writer"); if (list == null) throw new ArgumentNullException("list"); Action writeItem = child => writer.WriteElementString(childElement, IcdXmlConvert.ToString(child)); WriteListToXml(writer, list, listElement, writeItem); } /// /// Serializes the given list to XML using the writeItem action to write each item. /// /// /// /// /// /// public static void WriteListToXml(IcdXmlTextWriter writer, IEnumerable list, string listElement, Action writeItem) { if (writer == null) throw new ArgumentNullException("writer"); if (list == null) throw new ArgumentNullException("list"); if (writeItem == null) throw new ArgumentNullException("writeItem"); writer.WriteStartElement(listElement); { foreach (T child in list) writeItem(child); } writer.WriteEndElement(); } #endregion /// /// Returns true if the given xml is valid. /// /// /// [PublicAPI] public static bool IsValidXml(string xml) { try { IcdXmlDocument document = new IcdXmlDocument(); document.LoadXml(xml); return true; } catch (IcdXmlException) { return false; } } /// /// Prints the xml document. /// /// [PublicAPI] public static void Print(string xml) { string result = Format(xml); IcdConsole.PrintLine(result); } /// /// Formats the given xml string into a human readable structure with indentations. /// /// /// [PublicAPI] public static string Format(string xml) { using (IcdMemoryStream mStream = new IcdMemoryStream()) { using (IcdXmlTextWriter writer = new IcdXmlTextWriter(mStream, Encoding.UTF8)) { IcdXmlDocument document = new IcdXmlDocument(); // Load the XmlDocument with the XML. document.LoadXml(xml); // Write the XML into a formatting IcdXmlTextWriter document.WriteContentTo(writer); writer.Flush(); mStream.Flush(); // Have to rewind the MemoryStream in order to read its contents. mStream.Position = 0; return new IcdStreamReader(mStream).ReadToEnd(); } } } } }