wasStitchNET – Blame information for rev 7
?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/ |
||
7 | using System; |
||
8 | using System.Collections.Generic; |
||
9 | using System.Linq; |
||
10 | using System.Text; |
||
11 | using System.Reflection; |
||
12 | using System.Xml.Linq; |
||
13 | |||
14 | namespace wasStitchNET.Patchers |
||
15 | { |
||
16 | public static class Utilities |
||
17 | { |
||
18 | |||
19 | /// <summary> |
||
20 | /// Get the absolute XPath to a given XElement |
||
21 | /// (e.g. "/people/person[6]/name[1]/last[1]"). |
||
22 | /// </summary> |
||
23 | /// <param name="element"> |
||
24 | /// The element to get the index of. |
||
25 | /// </param> |
||
26 | public static string GetAbsoluteXPath(this XElement element) |
||
27 | { |
||
28 | if (element == null) |
||
29 | throw new ArgumentNullException("element"); |
||
30 | |||
31 | Func<XElement, string> relativeXPath = e => |
||
32 | { |
||
33 | var index = e.IndexPosition(); |
||
34 | var name = e.Name.LocalName; |
||
35 | |||
36 | // If the element is the root, no index is required |
||
37 | |||
38 | return (index == -1) ? "/" + name : string.Format |
||
39 | ( |
||
40 | "/{0}[{1}]", |
||
41 | name, |
||
42 | index.ToString() |
||
43 | ); |
||
44 | }; |
||
45 | |||
46 | var ancestors = from e in element.Ancestors() |
||
47 | select relativeXPath(e); |
||
48 | |||
49 | return string.Concat(ancestors.Reverse().ToArray()) + |
||
50 | relativeXPath(element); |
||
51 | } |
||
52 | |||
53 | /// <summary> |
||
54 | /// Get the index of the given XElement relative to its |
||
55 | /// siblings with identical names. If the given element is |
||
56 | /// the root, -1 is returned. |
||
57 | /// </summary> |
||
58 | /// <param name="element"> |
||
59 | /// The element to get the index of. |
||
60 | /// </param> |
||
61 | public static int IndexPosition(this XElement element) |
||
62 | { |
||
63 | if (element == null) |
||
64 | { |
||
65 | throw new ArgumentNullException("element"); |
||
66 | } |
||
67 | |||
68 | if (element.Parent == null) |
||
69 | { |
||
70 | return -1; |
||
71 | } |
||
72 | |||
73 | var i = 1; // Indexes for nodes start at 1, not 0 |
||
74 | |||
75 | foreach (var sibling in element.Parent.Elements(element.Name)) |
||
76 | { |
||
77 | if (sibling == element) |
||
78 | { |
||
79 | return i; |
||
80 | } |
||
81 | |||
82 | i++; |
||
83 | } |
||
84 | |||
85 | throw new InvalidOperationException |
||
86 | ("element has been removed from its parent."); |
||
87 | } |
||
88 | |||
89 | } |
||
90 | } |