wasStitchNET – Rev 9

Subversion Repositories:
Rev:
///////////////////////////////////////////////////////////////////////////
//  Copyright (C) Wizardry and Steamworks 2017 - License: GNU GPLv3      //
//  Please see: http://www.gnu.org/licenses/gpl.html for legal details,  //
//  rights of fair usage, the disclaimer and warranty conditions.        //
///////////////////////////////////////////////////////////////////////////
// Based on: https://seattlesoftware.wordpress.com/2009/03/13/get-the-xpath-to-an-xml-element-xelement/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace wasStitchNET.Patchers
{
    public static class Utilities
    {
        public static IEnumerable<XElement> ParentsAndSelf(this XElement e)
        {
            if (e == null)
                yield break;

            yield return e;

            foreach (var p in ParentsAndSelf(e.Parent))
            {
                yield return p;
            }
        }

        /// <summary>
        ///     Get the absolute XPath to a given XElement
        ///     (e.g. "/people/person[6]/name[1]/last[1]").
        /// </summary>
        /// <param name="element">
        ///     The element to get the index of.
        /// </param>
        public static string GetAbsoluteXPath(this XElement element)
        {
            if (element == null)
                throw new ArgumentNullException("element");

            Func<XElement, string> relativeXPath = e =>
            {
                var index = e.IndexPosition();
                var name = e.Name.LocalName;

                // If the element is the root, no index is required

                return index == -1
                    ? "/" + name
                    : string.Format
                    (
                        "/{0}[{1}]",
                        name,
                        index.ToString()
                    );
            };

            var ancestors = from e in element.Ancestors()
                select relativeXPath(e);

            return string.Concat(ancestors.Reverse().ToArray()) +
                   relativeXPath(element);
        }

        /// <summary>
        ///     Get the index of the given XElement relative to its
        ///     siblings with identical names. If the given element is
        ///     the root, -1 is returned.
        /// </summary>
        /// <param name="element">
        ///     The element to get the index of.
        /// </param>
        public static int IndexPosition(this XElement element)
        {
            if (element == null)
                throw new ArgumentNullException("element");

            if (element.Parent == null)
                return -1;

            var i = 1; // Indexes for nodes start at 1, not 0

            foreach (var sibling in element.Parent.Elements(element.Name))
            {
                if (sibling == element)
                    return i;

                i++;
            }

            throw new InvalidOperationException
                ("element has been removed from its parent.");
        }
    }
}

Generated by GNU Enscript 1.6.5.90.