wasStitchNET – Blame information for rev 9
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
7 | office | 1 | /////////////////////////////////////////////////////////////////////////// |
2 | // Copyright (C) Wizardry and Steamworks 2017 - License: GNU GPLv3 // |
||
3 | // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
||
4 | // rights of fair usage, the disclaimer and warranty conditions. // |
||
5 | /////////////////////////////////////////////////////////////////////////// |
||
6 | // Based on: https://seattlesoftware.wordpress.com/2009/03/13/get-the-xpath-to-an-xml-element-xelement/ |
||
8 | office | 7 | |
7 | office | 8 | using System; |
9 | office | 9 | using System.Collections.Generic; |
7 | office | 10 | using System.Linq; |
11 | using System.Xml.Linq; |
||
12 | |||
13 | namespace wasStitchNET.Patchers |
||
14 | { |
||
15 | public static class Utilities |
||
16 | { |
||
9 | office | 17 | public static IEnumerable<XElement> ParentsAndSelf(this XElement e) |
18 | { |
||
19 | if (e == null) |
||
20 | yield break; |
||
21 | |||
22 | yield return e; |
||
23 | |||
24 | foreach (var p in ParentsAndSelf(e.Parent)) |
||
25 | { |
||
26 | yield return p; |
||
27 | } |
||
28 | } |
||
29 | |||
8 | office | 30 | /// <summary> |
31 | /// Get the absolute XPath to a given XElement |
||
32 | /// (e.g. "/people/person[6]/name[1]/last[1]"). |
||
33 | /// </summary> |
||
34 | /// <param name="element"> |
||
35 | /// The element to get the index of. |
||
36 | /// </param> |
||
7 | office | 37 | public static string GetAbsoluteXPath(this XElement element) |
38 | { |
||
39 | if (element == null) |
||
40 | throw new ArgumentNullException("element"); |
||
41 | |||
42 | Func<XElement, string> relativeXPath = e => |
||
43 | { |
||
44 | var index = e.IndexPosition(); |
||
45 | var name = e.Name.LocalName; |
||
46 | |||
47 | // If the element is the root, no index is required |
||
48 | |||
8 | office | 49 | return index == -1 |
50 | ? "/" + name |
||
51 | : string.Format |
||
52 | ( |
||
53 | "/{0}[{1}]", |
||
54 | name, |
||
55 | index.ToString() |
||
56 | ); |
||
7 | office | 57 | }; |
58 | |||
59 | var ancestors = from e in element.Ancestors() |
||
8 | office | 60 | select relativeXPath(e); |
7 | office | 61 | |
62 | return string.Concat(ancestors.Reverse().ToArray()) + |
||
63 | relativeXPath(element); |
||
64 | } |
||
65 | |||
8 | office | 66 | /// <summary> |
67 | /// Get the index of the given XElement relative to its |
||
68 | /// siblings with identical names. If the given element is |
||
69 | /// the root, -1 is returned. |
||
70 | /// </summary> |
||
71 | /// <param name="element"> |
||
72 | /// The element to get the index of. |
||
73 | /// </param> |
||
7 | office | 74 | public static int IndexPosition(this XElement element) |
75 | { |
||
76 | if (element == null) |
||
77 | throw new ArgumentNullException("element"); |
||
78 | |||
79 | if (element.Parent == null) |
||
80 | return -1; |
||
81 | |||
82 | var i = 1; // Indexes for nodes start at 1, not 0 |
||
83 | |||
84 | foreach (var sibling in element.Parent.Elements(element.Name)) |
||
85 | { |
||
86 | if (sibling == element) |
||
87 | return i; |
||
88 | |||
89 | i++; |
||
90 | } |
||
91 | |||
92 | throw new InvalidOperationException |
||
93 | ("element has been removed from its parent."); |
||
94 | } |
||
95 | } |
||
8 | office | 96 | } |