321 lines · 15.6 KB · C#
RawDownload
//******************************************************************************************************//  XmlExtensions.cs - Gbtc////  Copyright © 2012, Grid Protection Alliance.  All Rights Reserved.////  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See//  the NOTICE file distributed with this work for additional information regarding copyright ownership.//  The GPA licenses this file to you under the MIT License (MIT), the "License"; you may//  not use this file except in compliance with the License. You may obtain a copy of the License at:////      http://www.opensource.org/licenses/MIT////  Unless agreed to in writing, the subject software distributed under the License is distributed on an//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the//  License for the specific language governing permissions and limitations.////  Code Modification History://  ----------------------------------------------------------------------------------------------------//  02/23/2003 - J. Ritchie Carroll//       Generated original version of source code.//  01/23/2006 - J. Ritchie Carroll//       Migrated 2.0 version of source code from 1.1 source (GSF.Shared.Common).//  01/24/2007 - J. Ritchie Carroll//       Added GetDataSet method to convert an XML string of data into a DataSet object.//  12/13/2007 - Darrell Zuercher//       Edited code comments.//  09/12/2008 - J. Ritchie Carroll//       Converted to C# extension functions.//  08/10/2009 - Josh L. Patterson//       Edited Comments.//  09/14/2009 - Stephen C. Wills//       Added new header and license agreement.////****************************************************************************************************** using System;using System.Collections.Generic;using System.Data;using System.Diagnostics.CodeAnalysis;using System.IO;using System.Linq;using System.Xml;using System.Xml.Linq;using System.Xml.Xsl; namespace GSF.Xml{    /// <summary>    /// Defines extension functions related to Xml elements.    /// </summary>    public static class XmlExtensions    {        /// <summary>Gets an XML node from given path, creating the entire path if it does not exist.</summary>        /// <remarks>This overload just allows the start of the given XML document by using its root element.</remarks>        /// <param name="xmlDoc">An <see cref="XmlDocument"/> to query.</param>        /// <param name="xpath">A <see cref="string"/> xpath query.</param>        /// <returns>An <see cref="XmlNode"/> corresponding to the xpath query.</returns>        public static XmlNode GetXmlNode(this XmlDocument xmlDoc, string xpath) =>             xmlDoc.DocumentElement.GetXmlNode(xpath, out bool _);         /// <summary>Gets an XML node from given path, creating the entire path if it does not exist.</summary>        /// <remarks>        /// <para>This overload just allows the start of the given XML document by using its root element.</para>        /// <para>Note that the <paramref name="isDirty" /> parameter will be set to True if any items were added to        /// the tree.</para>        /// </remarks>        /// <param name="xmlDoc">An <see cref="XmlDocument"/> to query.</param>        /// <param name="xpath">A <see cref="string"/> xpath query.</param>        /// <param name="isDirty">A <see cref="System.Boolean"/> value indicating if items were added to the tree.</param>        /// <returns>An <see cref="XmlNode"/> corresponding to the xpath query.</returns>        public static XmlNode GetXmlNode(this XmlDocument xmlDoc, string xpath, out bool isDirty) =>             xmlDoc.DocumentElement.GetXmlNode(xpath, out isDirty);         /// <summary>Gets an XML node from given path, creating the entire path if it does not exist.</summary>        /// <param name="parentNode">An <see cref="XmlNode"/> parent node to query.</param>        /// <param name="xpath">A <see cref="string"/> xpath query.</param>        /// <returns>An <see cref="XmlNode"/> corresponding to the xpath query.</returns>        public static XmlNode GetXmlNode(this XmlNode parentNode, string xpath) =>             parentNode.GetXmlNode(xpath, out bool _);         /// <summary>Gets an XML node from given path, creating the entire path if it does not exist.</summary>        /// <remarks>Note that the <paramref name="isDirty" /> parameter will be set to True if any items were added to        /// the tree.</remarks>        /// <param name="parentNode">An <see cref="XmlNode"/> parent node to query.</param>        /// <param name="xpath">A <see cref="string"/> xpath query.</param>        /// <param name="isDirty">A <see cref="System.Boolean"/> value indicating if items were added to the tree.</param>        /// <returns>An <see cref="XmlNode"/> corresponding to the xpath query.</returns>        public static XmlNode GetXmlNode(this XmlNode parentNode, string xpath, out bool isDirty)        {            XmlNode node = null;             isDirty = false;             // Removes any slash prefixes.            while (xpath[0] == '/')                xpath = xpath.Substring(1);             string[] elements = xpath.Split('/');             if (elements.Length == 1)            {                XmlNodeList nodes = parentNode.SelectNodes(xpath);                 if (nodes is not null)                {                    if (nodes.Count == 0)                    {                        if (parentNode.OwnerDocument is not null)                        {                            node = parentNode.OwnerDocument.CreateElement(xpath);                            parentNode.AppendChild(node);                            isDirty = true;                        }                    }                    else                    {                        node = nodes[0];                    }                }            }            else            {                foreach (string element in elements)                {                    node = GetXmlNode(parentNode, element);                    parentNode = node;                }            }             return node;        }         /// <summary>Safely gets or sets an XML node's attribute.</summary>        /// <remarks>If you get an attribute that does not exist, null will be returned.</remarks>        /// <param name="name">A <see cref="string"/> name of the value to get.</param>        /// <param name="node">A <see cref="XmlNode"/> to query.</param>        /// <returns>A <see cref="string"/> value returned for the attribute's value.</returns>        public static string GetAttributeValue(this XmlNode node, string name)        {            if (node?.Attributes is null)                return null;             XmlAttribute attribute = node.Attributes[name];             return attribute?.Value;        }         /// <summary>Safely sets an XML node's attribute.</summary>        /// <remarks>If you assign a value to an attribute that does not exist, the attribute will be created.</remarks>        /// <param name="name">A <see cref="string"/> indicating the node name to use.</param>        /// <param name="node">An <see cref="XmlNode"/> node to operate on.</param>        /// <param name="value">A <see cref="string"/> value to set the node attribute's value to.</param>        public static void SetAttributeValue(this XmlNode node, string name, string value)        {            if (node?.Attributes is null)                return;             XmlAttribute attribute = node.Attributes[name];             if (attribute is null)            {                // Add the attribute.                if (node.OwnerDocument != null)                {                    attribute = node.OwnerDocument.CreateAttribute(name);                    attribute.Value = value;                    node.Attributes.Append(attribute);                }            }            else            {                // Set the attribute value.                attribute.Value = value;                node.Attributes.SetNamedItem(attribute);            }        }         /// <summary>        /// Gets a data set object from an XML data set formatted as a String.        /// </summary>        /// <param name="xmlData">XML data string in standard DataSet format.</param>        /// <returns>A <see cref="DataSet"/> object.</returns>        public static DataSet GetDataSet(this string xmlData)        {            DataSet dataSet = new DataSet();             using (XmlTextReader xmlReader = new XmlTextReader(xmlData, XmlNodeType.Document, null))            {                xmlReader.ReadOuterXml();                 // Reads the outer XML into the Dataset.                dataSet.ReadXml(xmlReader);            }             return dataSet;        }         /// <summary>        /// Transforms an XML document using the given XSL template.        /// </summary>        /// <param name="document">The document to be transformed.</param>        /// <param name="transform">The template that defines how the data should be transformed.</param>        /// <returns>The result of the transformation.</returns>        public static string ApplyXSLTransform(this string document, string transform)        {            using (StringReader documentReader = new StringReader(document))            using (StringReader transformReader = new StringReader(transform))            using (XmlReader xmlDocumentReader = XmlReader.Create(documentReader))            using (XmlReader xmlTransformReader = XmlReader.Create(transformReader))            using (StringWriter resultWriter = new StringWriter())            {                XslCompiledTransform compiler = new XslCompiledTransform();                compiler.Load(xmlTransformReader);                compiler.Transform(xmlDocumentReader, null, resultWriter);                return resultWriter.ToString();            }        }         /// <summary>        /// Transforms all elements in the given document matching the given        /// <paramref name="name"/> using the given <paramref name="selector"/>        /// function to perform the transformation.        /// </summary>        /// <param name="document">The document to be modified.</param>        /// <param name="name">The name of the elements to be transformed.</param>        /// <param name="selector">The function that defines the transformation.</param>        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "This is a targeted extension for an XML document")]        public static void TransformAll(this XDocument document, XName name, Func<XElement, object> selector)        {            document                .Descendants(name)                .ToList()                .ForEach(element => element.ReplaceWith(selector(element)));        }         /// <summary>        /// Transforms all elements in the given document matching the given        /// <paramref name="name"/> using the given <paramref name="selector"/>        /// function to perform the transformation.        /// </summary>        /// <param name="document">The document to be modified.</param>        /// <param name="name">The name of the elements to be transformed.</param>        /// <param name="selector">The function that defines the transformation.</param>        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "This is a targeted extension for an XML document")]        public static void TransformAll(this XDocument document, XName name, Func<XElement, int, object> selector)        {            document                .Descendants(name)                .Select((Element, Index) => new { Element, Index })                .ToList()                .ForEach(obj => obj.Element.ReplaceWith(selector(obj.Element, obj.Index)));        }         /// <summary>        /// Formats the contents of an XML element and returns the result.        /// </summary>        /// <param name="element">The elements whose contents are to be formatted.</param>        /// <returns>The formatted contents of the elements.</returns>        /// <remarks>        /// The format to be used is determined by the <c>type</c> and <c>spec</c>        /// attributes of the element. The <c>type</c> attribute should be the fully        /// qualified type name of an <see cref="IFormattable"/> type. The <c>spec</c>        /// attribute defines the format string to be used when formatting the contents.        /// If <c>type</c> or <c>spec</c> are not defined or if <c>type</c> resovles to        /// a type that is not <see cref="IFormattable"/>, the contents are not formatted        /// and are returned as-is.        /// </remarks>        public static object Format(this XElement element)        {            Type elementType = Type.GetType((string)element.Attribute("type"), false);            string formatString = (string)element.Attribute("spec");             if (elementType is null || formatString is null)                return element.Nodes();             if (!typeof(IFormattable).IsAssignableFrom(elementType))                return element.Nodes();             string value = (string)element;            IFormattable formattable = (IFormattable)Convert.ChangeType(value, elementType);            return new XText(formattable.ToString(formatString, null));        }         /// <summary>        /// Finds all attributes in an enumeration of <see cref="XElement"/> items that match the specified <paramref name="attributeName"/>.        /// </summary>        /// <param name="source">Set of <see cref="XElement"/> values to search.</param>        /// <param name="attributeName">Attribute name to match.</param>        /// <returns>Matching sets of <see cref="XElement"/> items and associated attribute values.</returns>        /// <remarks>        /// When used in conjunction with the <see cref="Is"/> extension, allows for expressions like:        /// <code>        /// var globals = XDocument.Load(configFile)        ///     .Descendants("SettingsGroup")        ///     .WhereAttribute("Type").Is("Globals");        /// </code>        /// </remarks>        public static IEnumerable<Tuple<XElement, string>> WhereAttribute(this IEnumerable<XElement> source, string attributeName) =>            source.Select(element => new Tuple<XElement, string>(element, element.Attribute(attributeName)?.Value))            .Where(tuple => !string.IsNullOrWhiteSpace(tuple.Item2));         /// <summary>        /// Finds all attributes queried from <see cref="WhereAttribute"/> that match <paramref name="attributeValue"/>.        /// </summary>        /// <param name="source">Attributes queried from <see cref="WhereAttribute"/> extension.</param>        /// <param name="attributeValue">Attribute value to match.</param>        /// <param name="ignoreCase">Flag that determines if attribute value match is case sensitive.</param>        /// <returns><see cref="XElement"/> items that match <paramref name="attributeValue"/>.</returns>        /// <remarks>        /// When used in conjunction with the <see cref="WhereAttribute"/> extension, allows for expressions like:        /// <code>        /// var globals = XDocument.Load(configFile)        ///     .Descendants("SettingsGroup")        ///     .WhereAttribute("Type").Is("Globals");        /// </code>        /// </remarks>        public static IEnumerable<XElement> Is(this IEnumerable<Tuple<XElement, string>> source, string attributeValue, bool ignoreCase = true) =>            source.Where(tuple => string.Equals(tuple.Item2, attributeValue, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal))            .Select(tuple => tuple.Item1);    }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t