Ryan Farber's WebLog

Class Extensions for XLinq

I love XLinq!!  It really has made editing and manipulated Xml files much easier for me.  However there are some features missing that I really wanted to use all the time so I added them using the new class extensions feature in .NET.  So here's what I have.  I am looking for a merge nodes functions in XLinq if anyone has any.

Function

Purpose

IsValid Validates an XElement against a schemas.  I'm really surprised this feature wasn't in XLinq already.  I hope its added in the future.
GetAttributeValue There is a SetAttributeValue but no get attribute value.  I've overloaded this nicely so it can return defaults and the proper casting.  It would be fun to also have it try to look up the declared scema for default values but I haven't had the time or need for that yet.

Also I've used the default keyword in this function which I thought was pretty spiffy. :)

I most commonly use this for boolean test
if (myEl.GetAttributeValue<bool>() == true) { do something }
GetElementValue Ok maybe this function isn't needed that much but I kept finding myself writing the if null and casting code repeatedly plus this nicely matched with GetAttributeValue.
RemoveElements This is another function that really should have existed.  They give us Remove, RemoveAll, RemoveAttributes, RemoveNodes, but nothing for removing just the elements and leaving attributes and comments alone.  I know its a one liner foreach but it still ticks me off that it wasn't there.
HasAttribute A simple test, does this attribute exist.  Certainly a common need.
EncodeForXmlAttribute Ok this one doesn't really belong here but heck I like it being right there at my fingertips to use before setting items or during comparisons.
using System;
using System.Xml.Linq;
using System.Xml.Schema;
using System.Xml;
using System.Diagnostics;
using System.Linq;

/// <summary>
/// Class extensions for XElement
/// </summary>
/// <see cref="IsValid"/>
/// <see cref="GetAttributeVlue"/>
/// <see cref="GetElementValue"/>
/// <see cref="RemoveElements"/>
/// <see cref="HasAttribute"/>
/// <see cref="EncodeForXmlAttribute"/>
public static class Extensions
{
    #region XElement class extensions
    #region IsValid (against schemas) Extension for XElement
    /// <summary>
    /// Validates Xml element against schemas
    /// </summary>
    /// <param name="xEl">Element to verify</param>
    /// <param name="schemaPath">List locations of schemas to compare</param>
    /// <returns>True/False (if false details in Debug)</returns>
    public static bool IsValid(this XElement xEl, params string[] schemaPath)
    {
        XmlSchemaSet schemas = new XmlSchemaSet();

        foreach (String sp in schemaPath)
        {
            if (sp.Contains("<"))
            {
                schemas.Add(String.Empty, XElement.Parse(sp).CreateReader());
            }
            else
            {
                schemas.Add(String.Empty, XmlReader.Create(sp));
            }
        }

        return CompareToSchemas(xEl, schemas);
    }

    /// <summary>
    /// Validates xml element against schemas
    /// </summary>
    /// <param name="xEl">Element to verify</param>
    /// <param name="schemaReader">List of schemas to compare</param>
    /// <returns>True/False (if false details in Debug)</returns>
    public static bool IsValid(this XElement xEl, params XmlReader[] schemaReader)
    {
        XmlSchemaSet schemas = new XmlSchemaSet();

        foreach (XmlReader sr in schemaReader)
            schemas.Add(String.Empty, sr);

        return CompareToSchemas(xEl, schemas);
    }

    private static bool CompareToSchemas(XElement xEl, XmlSchemaSet schemas)
    {
        bool errors = false;
        XDocument doc = xEl.Document;
        if (doc == null)
        {
            doc = XDocument.Parse(xEl.ToString());
        }

        doc.Validate(schemas, (sender, e) =>
        {
            Debug.WriteLine(e.Message, "ValidateErrror");
            errors = true;
        });


        return !errors;
    }
    #endregion

    #region GetAttributeValue
    /// <summary>
    /// Gets the value of an attribute
    /// </summary>
    /// <param name="xEl">Extends this XElement Type</param>
    /// <param name="attName">An XName that contains the name of the attribute to retrieve.</param>
    /// <param name="defaultReturn">Default return if the attribute doesn't exist</param>
    /// <returns>Attribute value or default if attribute doesn't exist</returns>
    public static string GetAttributeValue(this XElement xEl, XName attName, string defaultReturn)
    {
        XAttribute att = xEl.Attribute(attName);
        if (att == null) return defaultReturn;
        return att.Value;
    }

    /// <summary>
    /// Gets the value of an attribute
    /// </summary>
    /// <param name="xEl">Extends this XElement Type</param>
    /// <param name="attName">An XName that contains the name of the attribute to retrieve.</param>
    /// <returns>Attribute value or String.Empty if element doesn't exist</returns>
    public static string GetAttributeValue(this XElement xEl, XName attName)
    {
        return xEl.GetAttributeValue(attName, String.Empty);
    }

    /// <summary>
    /// Gets the value of an attribute
    /// </summary>
    /// <param name="xEl">Extends this XElement Type</param>
    /// <param name="attName">An XName that contains the name of the attribute to retrieve.</param>
    /// <param name="defaultReturn">Default return if the attribute doesn't exist</param>
    /// <returns>Attribute value or default if attribute doesn't exist</returns>
    public static T GetAttributeValue<T>(this XElement xEl, XName attName, T defaultReturn)
    {
        string returnValue = xEl.GetAttributeValue(attName, String.Empty);
        if (returnValue == String.Empty) return defaultReturn;
        return (T)Convert.ChangeType(returnValue, typeof(T));
    }

    /// <summary>
    /// Gets the value of an attribute
    /// </summary>
    /// <param name="xEl">Extends this XElement Type</param>
    /// <param name="attName">An XName that contains the name of the attribute to retrieve.</param>
    /// <returns>Attribute value or default of T if element doesn't exist</returns>
    public static T GetAttributeValue<T>(this XElement xEl, XName attName)
    {
        return xEl.GetAttributeValue<T>(attName, default(T));
    }
    #endregion

    #region GetElementValue
    /// <summary>
    /// Gets the value of a child element.
    /// </summary>
    /// <param name="xEl">Extends this XElement Type</param>
    /// <param name="elName">An XName that contains the name of the child element to retrieve.</param>
    /// <param name="defaultReturn">Default return if the element doesn't exist</param>
    /// <returns>Element value or default if element doesn't exist</returns>
    public static string GetElementValue(this XElement xEl, XName elName, string defaultReturn)
    {
        XElement el = xEl.Element(elName);
        if (el == null) return defaultReturn;
        return el.Value;
    }

    /// <summary>
    /// Gets the value of a child element.
    /// </summary>
    /// <param name="xEl">Extends this XElement Type</param>
    /// <param name="elName">An XName that contains the name of the child element to retrieve.</param>
    /// <returns>Element value or String.Empty if element doesn't exist</returns>
    public static string GetElementValue(this XElement xEl, XName elName)
    {
        return xEl.GetElementValue(elName, String.Empty);
    }

    /// <summary>
    /// Gets the value of a child element.
    /// </summary>
    /// <param name="xEl">Extends this XElement Type</param>
    /// <param name="elName">An XName that contains the name of the child element to retrieve.</param>
    /// <param name="defaultReturn">Default return if the element doesn't exist</param>
    /// <returns>Element value or default if element doesn't exist</returns>
    public static T GetElementValue<T>(this XElement xEl, XName elName, T defaultReturn)
    {
        string returnValue = xEl.GetElementValue(elName, String.Empty);
        if (returnValue == String.Empty) return defaultReturn;
        return (T)Convert.ChangeType(returnValue, typeof(T));
    }

    /// <summary>
    /// Gets the value of a child element.
    /// </summary>
    /// <param name="xEl">Extends this XElement Type</param>
    /// <param name="elName">An XName that contains the name of the child element to retrieve.</param>
    /// <returns>Element value or default of T if element doesn't exist</returns>
    public static T GetElementValue<T>(this XElement xEl, XName elName)
    {
        return xEl.GetElementValue<T>(elName, default(T));
    }
    #endregion

    #region RemoveElements
    /// <summary>
    /// Removes all child elements
    /// </summary>
    /// <param name="xEl">Extends this XElement Type</param>
    public static void RemoveElements(this XElement xEl)
    {
       foreach (XElement el in xEl.Elements().ToArray()) el.Remove();
    }

    /// <summary>
    /// Removes all child elements matching the XName
    /// </summary>
    /// <param name="xEl">Extends this XElement Type</param>
    /// <param name="name">The System.Xml.Linq.XName to match.</param>
    public static void RemoveElements(this XElement xEl, XName name)
    {
        foreach (XElement el in xEl.Elements(name).ToArray()) el.Remove();
    }
    #endregion

    /// <summary>
    /// Determines if attribute doesn't exist or exists but is empty
    /// </summary>
    /// <param name="xEl">Extends this XElement Type</param>
    /// <param name="attName">An XName that contains the name of the attribute to retrieve.</param>
    /// <returns>True if attribute exists and is not empty</returns>
    public static bool HasAttribute(this XElement xEl, XName attName)
    {
        return !String.IsNullOrEmpty(xEl.GetAttributeValue(attName));
    }

    /// <summary>
    /// Replaces invalid XML characters in a string with their valid XML equivalent.
    /// </summary>
    /// <remarks>
    /// Replaced characters are &lt; to &amp;lt;, &gt; to &amp;gt;, &apos; to &amp;apos;, &quot; to &amp;quot; and &amp; to &amp;amp;
    /// </remarks>
    /// <param name="text">The string within which to escape invalid characters.</param>
    /// <returns>The input string with invalid characters replaced.</returns>
    public static string EncodeForXmlAttribute(String text)
    {
        return System.Security.SecurityElement.Escape(text);
    }
    #endregion
}
Published Friday, May 30, 2008 10:57 AM by rfarber

Comments

No Comments
Anonymous comments are disabled

© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker