// Copyright (c) 2015, Yves Goergen, http://unclassified.software/source/easyxml // // Copying and distribution of this file, with or without modification, are permitted provided the // copyright notice and this notice are preserved. This file is offered as-is, without any warranty. using System; using System.Drawing; using System.Globalization; using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Xml; namespace Unclassified.Util { /// /// Provides easy read and write access to XML documents through XPath selectors. /// public class EasyXml { #region Private data /// /// Internal XML document that is acted upon. /// private XmlDocument xd; #endregion Private data #region Constructors /// /// Initialises a new instance of the EasyXml class and creates a new empty XML document. /// public EasyXml() { xd = new XmlDocument(); } /// /// Initialises a new instance of the EasyXml class and creates a new XML document from the specified content. /// /// XML document string. public EasyXml(string xml) { xd = new XmlDocument(); if (!string.IsNullOrWhiteSpace(xml)) { xd.LoadXml(xml); } } /// /// Initialises a new instance of the EasyXml class with the specified XML document. /// /// XML document. public EasyXml(XmlDocument xmlDocument) { xd = xmlDocument; } #endregion Constructors #region Public properties /// /// Gets or sets the current XML document as a formatted string. /// public string Xml { get { using (MemoryStream ms = new MemoryStream()) { XmlWriterSettings xws = new XmlWriterSettings(); xws.Encoding = Encoding.UTF8; xws.Indent = true; xws.IndentChars = " "; XmlWriter xw = XmlWriter.Create(ms, xws); xd.Save(xw); // If the BOM is in the stream, skip it for the string output int start = 0; int count = (int)ms.Length; byte[] bom = new byte[3]; ms.Seek(0, SeekOrigin.Begin); ms.Read(bom, 0, 3); if (bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF) { // Skip UTF-8 Byte Order Mark (BOM) start = 3; count -= start; } return Encoding.UTF8.GetString(ms.ToArray(), start, count); } } set { xd.LoadXml(value); } } /// /// Gets the current XML document as a formatted string without any declarative markup. /// public string PlainXml { get { using (MemoryStream ms = new MemoryStream()) { XmlWriterSettings xws = new XmlWriterSettings(); xws.Encoding = Encoding.GetEncoding(28605); // ISO-8859-15 xws.Indent = true; xws.IndentChars = " "; xws.OmitXmlDeclaration = true; XmlWriter xw = XmlWriter.Create(ms, xws); xd.Save(xw); return Encoding.GetEncoding(28605).GetString(ms.ToArray()); // ISO-8859-15 } } } /// /// Gets the internal XML document for direct access. /// public XmlDocument XmlDocument { get { return xd; } } #endregion Public properties #region Document management methods /// /// Creates a new document instance and clears all contents. /// public void Clear() { xd = new XmlDocument(); } /// /// Loads an XML file into this document. /// /// XML file name. public void Load(string fileName) { xd.Load(fileName); } #endregion Document management methods #region Element read access methods /// /// Determines whether an element or attribute specified by the XPath selector exists in the document. /// /// XPath selector to check. /// true if an element or attribute exists, false otherwise. public bool Exists(string xPath) { return Exists(xd, xPath); } /// /// Determines whether an element or attribute specified by the XPath selector exists in the document. /// /// XML node to start searching at. /// XPath selector to check. /// true if an element or attribute exists, false otherwise. public bool Exists(XmlNode baseNode, string xPath) { return baseNode.SelectSingleNode(xPath) != null; } /// /// Reads a string value from a node. /// /// XPath selector for the node. /// Text contents or attribute value of the selected node. public string ReadString(string xPath) { return ReadStringInternal(xd, xPath, true, null); } /// /// Reads a string value from a node. /// /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Text contents or attribute value of the selected node. public string ReadString(string xPath, string defaultValue) { return ReadStringInternal(xd, xPath, false, defaultValue); } /// /// Reads a string value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Text contents or attribute value of the selected node. public string ReadString(XmlNode baseNode, string xPath) { return ReadStringInternal(baseNode, xPath, true, null); } /// /// Reads a string value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Text contents or attribute value of the selected node. public string ReadString(XmlNode baseNode, string xPath, string defaultValue) { return ReadStringInternal(baseNode, xPath, false, defaultValue); } /// /// Reads an int value from a node. /// /// XPath selector for the node. /// Int value of the selected node. public int ReadInt(string xPath) { return (int)ReadIntInternal(xd, xPath, true, null); } /// /// Reads an int value from a node. /// /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Int value of the selected node. public int ReadInt(string xPath, int defaultValue) { return (int)ReadIntInternal(xd, xPath, false, defaultValue); } /// /// Reads an int value from a node. /// /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Int value of the selected node. public int? ReadInt(string xPath, int? defaultValue) { return ReadIntInternal(xd, xPath, false, defaultValue); } /// /// Reads an int value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Int value of the selected node. public int ReadInt(XmlNode baseNode, string xPath) { return (int)ReadIntInternal(baseNode, xPath, true, null); } /// /// Reads an int value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Int value of the selected node. public int ReadInt(XmlNode baseNode, string xPath, int defaultValue) { return (int)ReadIntInternal(baseNode, xPath, false, defaultValue); } /// /// Reads an int value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Int value of the selected node. public int? ReadInt(XmlNode baseNode, string xPath, int? defaultValue) { return ReadIntInternal(baseNode, xPath, false, defaultValue); } /// /// Reads a decimal value from a node. /// /// XPath selector for the node. /// Decimal value of the selected node. public decimal ReadDecimal(string xPath) { return (decimal)ReadDecimalInternal(xd, xPath, true, null); } /// /// Reads a decimal value from a node. /// /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Decimal value of the selected node. public decimal ReadDecimal(string xPath, decimal defaultValue) { return (decimal)ReadDecimalInternal(xd, xPath, false, defaultValue); } /// /// Reads a decimal value from a node. /// /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Decimal value of the selected node. public decimal? ReadDecimal(string xPath, decimal? defaultValue) { return ReadDecimalInternal(xd, xPath, false, defaultValue); } /// /// Reads a decimal value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Decimal value of the selected node. public decimal ReadDecimal(XmlNode baseNode, string xPath) { return (decimal)ReadDecimalInternal(baseNode, xPath, true, null); } /// /// Reads a decimal value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Decimal value of the selected node. public decimal ReadDecimal(XmlNode baseNode, string xPath, decimal defaultValue) { return (decimal)ReadDecimalInternal(baseNode, xPath, false, defaultValue); } /// /// Reads a decimal value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Decimal value of the selected node. public decimal? ReadDecimal(XmlNode baseNode, string xPath, decimal? defaultValue) { return ReadDecimalInternal(baseNode, xPath, false, defaultValue); } /// /// Reads a bool value from a node. /// /// XPath selector for the node. /// Bool value of the selected node. public bool ReadBool(string xPath) { return (bool)ReadBoolInternal(xd, xPath, true, null); } /// /// Reads a bool value from a node. /// /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Bool value of the selected node. public bool ReadBool(string xPath, bool defaultValue) { return (bool)ReadBoolInternal(xd, xPath, false, defaultValue); } /// /// Reads a bool value from a node. /// /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Bool value of the selected node. public bool? ReadBool(string xPath, bool? defaultValue) { return ReadBoolInternal(xd, xPath, false, defaultValue); } /// /// Reads a bool value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Bool value of the selected node. public bool ReadBool(XmlNode baseNode, string xPath) { return (bool)ReadBoolInternal(baseNode, xPath, true, null); } /// /// Reads a bool value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Bool value of the selected node. public bool ReadBool(XmlNode baseNode, string xPath, bool defaultValue) { return (bool)ReadBoolInternal(baseNode, xPath, false, defaultValue); } /// /// Reads a bool value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Bool value of the selected node. public bool? ReadBool(XmlNode baseNode, string xPath, bool? defaultValue) { return ReadBoolInternal(baseNode, xPath, false, defaultValue); } /// /// Reads a DateTime value from a node. /// /// XPath selector for the node. /// DateTime value of the selected node. public DateTime ReadDateTime(string xPath) { return (DateTime)ReadDateTimeInternal(xd, xPath, true, null); } /// /// Reads a DateTime value from a node. /// /// XPath selector for the node. /// Value to be returned if the node does not exist. /// DateTime value of the selected node. public DateTime ReadDateTime(string xPath, DateTime defaultValue) { return (DateTime)ReadDateTimeInternal(xd, xPath, false, defaultValue); } /// /// Reads a DateTime value from a node. /// /// XPath selector for the node. /// Value to be returned if the node does not exist. /// DateTime value of the selected node. public DateTime? ReadDateTime(string xPath, DateTime? defaultValue) { return ReadDateTimeInternal(xd, xPath, false, defaultValue); } /// /// Reads a DateTime value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// DateTime value of the selected node. public DateTime ReadDateTime(XmlNode baseNode, string xPath) { return (DateTime)ReadDateTimeInternal(baseNode, xPath, true, null); } /// /// Reads a DateTime value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Value to be returned if the node does not exist. /// DateTime value of the selected node. public DateTime ReadDateTime(XmlNode baseNode, string xPath, DateTime defaultValue) { return (DateTime)ReadDateTimeInternal(baseNode, xPath, false, defaultValue); } /// /// Reads a DateTime value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Value to be returned if the node does not exist. /// DateTime value of the selected node. public DateTime? ReadDateTime(XmlNode baseNode, string xPath, DateTime? defaultValue) { return ReadDateTimeInternal(baseNode, xPath, false, defaultValue); } /// /// Reads a TimeSpan value from a node. /// /// XPath selector for the node. /// TimeSpan value of the selected node. public TimeSpan ReadTimeSpan(string xPath) { return (TimeSpan)ReadTimeSpanInternal(xd, xPath, true, null); } /// /// Reads a TimeSpan value from a node. /// /// XPath selector for the node. /// Value to be returned if the node does not exist. /// TimeSpan value of the selected node. public TimeSpan ReadTimeSpan(string xPath, TimeSpan defaultValue) { return (TimeSpan)ReadTimeSpanInternal(xd, xPath, false, defaultValue); } /// /// Reads a TimeSpan value from a node. /// /// XPath selector for the node. /// Value to be returned if the node does not exist. /// TimeSpan value of the selected node. public TimeSpan? ReadTimeSpan(string xPath, TimeSpan? defaultValue) { return ReadTimeSpanInternal(xd, xPath, false, defaultValue); } /// /// Reads a TimeSpan value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// TimeSpan value of the selected node. public TimeSpan ReadTimeSpan(XmlNode baseNode, string xPath) { return (TimeSpan)ReadTimeSpanInternal(baseNode, xPath, true, null); } /// /// Reads a TimeSpan value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Value to be returned if the node does not exist. /// TimeSpan value of the selected node. public TimeSpan ReadTimeSpan(XmlNode baseNode, string xPath, TimeSpan defaultValue) { return (TimeSpan)ReadTimeSpanInternal(xd, xPath, false, defaultValue); } /// /// Reads a TimeSpan value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Value to be returned if the node does not exist. /// TimeSpan value of the selected node. public TimeSpan? ReadTimeSpan(XmlNode baseNode, string xPath, TimeSpan? defaultValue) { return ReadTimeSpanInternal(xd, xPath, false, defaultValue); } /// /// Reads a Color value from a node. /// /// XPath selector for the node. /// Color value of the selected node. public Color ReadColor(string xPath) { return (Color)ReadColorInternal(xd, xPath, true, null); } /// /// Reads a Color value from a node. /// /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Color value of the selected node. public Color ReadColor(string xPath, Color defaultValue) { return (Color)ReadColorInternal(xd, xPath, false, defaultValue); } /// /// Reads a Color value from a node. /// /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Color value of the selected node. public Color? ReadColor(string xPath, Color? defaultValue) { return ReadColorInternal(xd, xPath, false, defaultValue); } /// /// Reads a Color value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Color value of the selected node. public Color ReadColor(XmlNode baseNode, string xPath) { return (Color)ReadColorInternal(baseNode, xPath, true, null); } /// /// Reads a Color value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Color value of the selected node. public Color ReadColor(XmlNode baseNode, string xPath, Color defaultValue) { return (Color)ReadColorInternal(xd, xPath, false, defaultValue); } /// /// Reads a Color value from a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// Value to be returned if the node does not exist. /// Color value of the selected node. public Color? ReadColor(XmlNode baseNode, string xPath, Color? defaultValue) { return ReadColorInternal(xd, xPath, false, defaultValue); } #endregion Element read access methods #region Internal element read access methods private string ReadStringInternal(XmlNode baseNode, string xPath, bool isRequired, string defaultValue) { XmlNode node = baseNode.SelectSingleNode(xPath); XmlElement element = node as XmlElement; if (element != null) { return element.InnerText; } XmlAttribute attribute = node as XmlAttribute; if (attribute != null) { return attribute.Value; } if (!isRequired) { return defaultValue; } if (node != null) { throw new NotSupportedException("Unsupported node type selected."); } else { throw new EasyXmlNodeNotFoundException(xPath); } } private int? ReadIntInternal(XmlNode baseNode, string xPath, bool isRequired, int? defaultValue) { string s = ReadStringInternal(baseNode, xPath, isRequired, null); if (string.IsNullOrWhiteSpace(s) && !isRequired) { return defaultValue; } return int.Parse(s, CultureInfo.InvariantCulture); } private decimal? ReadDecimalInternal(XmlNode baseNode, string xPath, bool isRequired, decimal? defaultValue) { string s = ReadStringInternal(baseNode, xPath, isRequired, null); if (string.IsNullOrWhiteSpace(s) && !isRequired) { return defaultValue; } return decimal.Parse(s, CultureInfo.InvariantCulture); } private bool? ReadBoolInternal(XmlNode baseNode, string xPath, bool isRequired, bool? defaultValue) { string s = ReadStringInternal(baseNode, xPath, isRequired, null); if (string.IsNullOrWhiteSpace(s) && !isRequired) { return defaultValue; } if (!string.IsNullOrWhiteSpace(s)) { // Word sources: // http://smwbp.googlecode.com/svn/trunk/release/semediawiki-1.4.2/SemanticMediaWiki/languages/SMW_Messages.php // http://search.cpan.org/~jmcnamara/Spreadsheet-WriteExcel-2.37/lib/Spreadsheet/WriteExcel/Examples.pm // http://www.obout.com/t2/KnowledgeBase.aspx?id=308 // https://svn.typo3.org/TYPO3v4/Extensions/cal/tags/cal-1.3.0/controller/locallang.xml string[] trueWords = new string[] { "1", "true", "yes", "on", // en "wahr", "ja", // de "verdadero", "si", // es "tosi", "ei", // fi "vrai", "oui", // fr "igaz", // hu "rétt", // is "vero", "si", // it "waar", "ja", // nl "sant", "ja", // nn, no "prawda", "tak", // pl "verdadeiro", "sim", // pt "истина", "да", // ru "áno", // sk "sant", "ja", // sv "đúng", "có", // vi "是", // zh-cn, zh-tw }; string[] falseWords = new string[] { "0", "false", "no", "off", // en "falsch", "nein", // de "falso", "no", // es "epätosi", "kyllä", // fi "faux", "non", // fr "hamis", // hu "rangt", // is "falso", "no", // it "onwaar", "nee", // nl "usant", "nei", // nn, no "fałsz", "nie", // pl "falso", "nao", "não", // pt "ложь", "нет", // ru "nie", // sk "falskt", "nej", // sv "sai", "không", // vi "否", // zh-cn, zh-tw }; s = s.Trim(); foreach (var word in trueWords) { if (s.Equals(word, StringComparison.InvariantCultureIgnoreCase)) return true; } foreach (var word in falseWords) { if (s.Equals(word, StringComparison.InvariantCultureIgnoreCase)) return false; } } throw new FormatException(); } private DateTime? ReadDateTimeInternal(XmlNode baseNode, string xPath, bool isRequired, DateTime? defaultValue) { string s = ReadStringInternal(baseNode, xPath, isRequired, null); if (string.IsNullOrWhiteSpace(s) && !isRequired) { return defaultValue; } return DateTime.Parse(s, CultureInfo.InvariantCulture); } private TimeSpan? ReadTimeSpanInternal(XmlNode baseNode, string xPath, bool isRequired, TimeSpan? defaultValue) { string s = ReadStringInternal(baseNode, xPath, isRequired, null); if (string.IsNullOrWhiteSpace(s) && !isRequired) { return defaultValue; } Match m = Regex.Match(s, "^P((?[0-9]+)D)?(T((?[0-9]+)H)?((?[0-9]+)M)?((?[0-9]+)S)?)?$"); if (m.Success) { int days = string.IsNullOrEmpty(m.Groups["D"].Value) ? 0 : int.Parse(m.Groups["D"].Value); int hours = string.IsNullOrEmpty(m.Groups["H"].Value) ? 0 : int.Parse(m.Groups["H"].Value); int mins = string.IsNullOrEmpty(m.Groups["M"].Value) ? 0 : int.Parse(m.Groups["M"].Value); int secs = string.IsNullOrEmpty(m.Groups["S"].Value) ? 0 : int.Parse(m.Groups["S"].Value); return TimeSpan.FromSeconds(days * 86400 + hours * 3600 + mins * 60 + secs); } throw new FormatException(); } private Color? ReadColorInternal(XmlNode baseNode, string xPath, bool isRequired, Color? defaultValue) { string s = ReadStringInternal(baseNode, xPath, isRequired, null); if (string.IsNullOrWhiteSpace(s) && !isRequired) { return defaultValue; } Match m = Regex.Match(s, "^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); if (m.Success) { int r = int.Parse(m.Groups[1].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture); int g = int.Parse(m.Groups[2].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture); int b = int.Parse(m.Groups[3].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture); return Color.FromArgb(r, g, b); } throw new FormatException(); } #endregion Internal element read access methods #region Element write access methods /// /// Creates a node. /// /// XPath selector for the node. /// The created or existing node. public XmlNode Create(string xPath) { return Create(xd, xPath, false); } /// /// Creates a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// The created or existing node. public XmlNode Create(XmlNode baseNode, string xPath) { return Create(baseNode, xPath, false); } /// /// Creates a new node. /// /// XPath selector for the node. /// The created node. public XmlNode CreateNew(string xPath) { return Create(xd, xPath, true); } /// /// Creates a new node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// The created node. public XmlNode CreateNew(XmlNode baseNode, string xPath) { return Create(baseNode, xPath, true); } /// /// Creates a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// true to always create a new node, false to return an existing node. /// The created or existing node. public XmlNode Create(XmlNode baseNode, string xPath, bool newNode) { // Idea (less strict parsing): xPath.Trim('/').Split('/') if (!Regex.IsMatch(xPath, "^(/?[-._a-z0-9]+)(/[-._a-z0-9]+)*(/@[-._a-z0-9]+)?$", RegexOptions.IgnoreCase)) { if (!Regex.IsMatch(xPath, "^@[-._a-z0-9]+$", RegexOptions.IgnoreCase)) { throw new NotSupportedException("Unsupported XPath expression for creating an XML node."); } } string[] elements = xPath.Split('/'); if (newNode && elements[elements.Length - 1][0] == '@') { throw new NotSupportedException("You cannot create a new node with an XPath expression for an XML attribute."); } XmlNode node = baseNode; for (int i = 0; i < elements.Length; i++) { string element = elements[i]; if (element.Length == 0) continue; XmlNode subNode = node.SelectSingleNode(element); bool skip = newNode && i == elements.Length - 1; // Skip existing to create a new element if (subNode != null && !skip) { node = subNode; } else { if (element[0] == '@') { string attribute = element.Substring(1); subNode = xd.CreateAttribute(attribute); node.Attributes.Append((XmlAttribute)subNode); node = subNode; } else { subNode = xd.CreateElement(element); node.AppendChild(subNode); node = subNode; } } } return node; } /// /// Writes an int value to a node. /// /// XPath selector for the node. /// The int value to write. public void Write(string xPath, int? value) { Write(xd, xPath, value); } /// /// Writes an int value to a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// The int value to write. public void Write(XmlNode baseNode, string xPath, int? value) { if (value != null) { Write(baseNode, xPath, ((int)value).ToString(CultureInfo.InvariantCulture)); } else { Write(baseNode, xPath, ""); } } /// /// Writes a decimal value to a node. /// /// XPath selector for the node. /// The decimal value to write. public void Write(string xPath, decimal? value) { Write(xd, xPath, value); } /// /// Writes a decimal value to a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// The decimal value to write. public void Write(XmlNode baseNode, string xPath, decimal? value) { if (value != null) { Write(baseNode, xPath, ((decimal)value).ToString(CultureInfo.InvariantCulture)); } else { Write(baseNode, xPath, ""); } } /// /// Writes a bool value to a node. /// /// XPath selector for the node. /// The bool value to write. public void Write(string xPath, bool? value) { Write(xd, xPath, value); } /// /// Writes a bool value to a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// The bool value to write. public void Write(XmlNode baseNode, string xPath, bool? value) { if (value != null) { Write(baseNode, xPath, value == true ? "true" : "false"); } else { Write(baseNode, xPath, ""); } } /// /// Writes a DateTime value to a node. /// /// XPath selector for the node. /// The DateTime value to write. public void Write(string xPath, DateTime? value) { Write(xd, xPath, value); } /// /// Writes a DateTime value to a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// The DateTime value to write. public void Write(XmlNode baseNode, string xPath, DateTime? value) { if (value != null) { Write(baseNode, xPath, ((DateTime)value).ToString("s")); } else { Write(baseNode, xPath, ""); } } /// /// Writes a TimeSpan value to a node. /// /// XPath selector for the node. /// The TimeSpan value to write. public void Write(string xPath, TimeSpan? value) { Write(xd, xPath, value); } /// /// Writes a TimeSpan value to a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// The TimeSpan value to write. public void Write(XmlNode baseNode, string xPath, TimeSpan? value) { if (value != null) { TimeSpan t = (TimeSpan)value; string s = "P"; if (t.Days > 0) s += t.Days + "D"; if (t.Hours > 0 || t.Minutes > 0 || t.Seconds > 0) s += "T"; if (t.Hours > 0) s += t.Hours + "H"; if (t.Minutes > 0) s += t.Minutes + "M"; if (t.Seconds > 0) s += t.Seconds + "S"; if (s == "P") s = "PT0S"; Write(baseNode, xPath, s); } else { Write(baseNode, xPath, ""); } } /// /// Writes a Color value to a node. /// /// XPath selector for the node. /// The Color value to write. public void Write(string xPath, Color? value) { Write(xd, xPath, value); } /// /// Writes a Color value to a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// The Color value to write. public void Write(XmlNode baseNode, string xPath, Color? value) { if (value != null) { Color c = (Color)value; Write(baseNode, xPath, "#" + c.R.ToString("x2") + c.G.ToString("x2") + c.B.ToString("x2")); } else { Write(baseNode, xPath, ""); } } /// /// Writes a string value to a node. /// /// XPath selector for the node. /// The string value to write. public void Write(string xPath, string value) { Write(xd, xPath, value); } /// /// Writes a string value to a node. /// /// Base node for the XPath selector. /// XPath selector for the node. /// The string value to write. public void Write(XmlNode baseNode, string xPath, string value) { XmlNode node = baseNode.SelectSingleNode(xPath); if (node == null) { node = Create(baseNode, xPath); } XmlElement element = node as XmlElement; if (element != null) { element.InnerText = value; return; } XmlAttribute attribute = node as XmlAttribute; if (attribute != null) { attribute.Value = value; return; } throw new NotSupportedException("Unsupported node type selected."); } #endregion Element write access methods } /// /// The exception that is thrown when an XML node is not found. /// public class EasyXmlNodeNotFoundException : Exception { /// /// Gets the XPath selector of the node that was not found. /// public string XPath { get; private set; } /// /// Initialises a new instance of the EasyXmlNodeNotFoundException class. /// /// The XPath selector of the node that was not found. public EasyXmlNodeNotFoundException(string xPath) { XPath = xPath; } } }