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();
}
}
}
}
}