我在文档中有一个XElement。给定XElement(和XDocument?),是否有扩展方法来获取完整的(例如,绝对的/root/item/element/child)XPath?
/root/item/element/child
例如myXElement.GetXPath()?
编辑:好的,看起来我忽略了一些非常重要的内容。 哎呀!需要考虑元素的索引。请参阅我的最新答案以获取建议的更正解决方案。
扩展方法:
public static class XExtensions { /// <summary> /// Get the absolute XPath to a given XElement /// (e.g. "/people/person[6]/name[1]/last[1]"). /// </summary> public static string GetAbsoluteXPath(this XElement element) { if (element == null) { throw new ArgumentNullException("element"); } Func<XElement, string> relativeXPath = e => { int index = e.IndexPosition(); string 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; } int 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."); } }
和测试:
class Program { static void Main(string[] args) { Program.Process(XDocument.Load(@"C:\test.xml").Root); Console.Read(); } static void Process(XElement element) { if (!element.HasElements) { Console.WriteLine(element.GetAbsoluteXPath()); } else { foreach (XElement child in element.Elements()) { Process(child); } } } }
并输出示例:
/tests/test[1]/date[1] /tests/test[1]/time[1]/start[1] /tests/test[1]/time[1]/end[1] /tests/test[1]/facility[1]/name[1] /tests/test[1]/facility[1]/website[1] /tests/test[1]/facility[1]/street[1] /tests/test[1]/facility[1]/state[1] /tests/test[1]/facility[1]/city[1] /tests/test[1]/facility[1]/zip[1] /tests/test[1]/facility[1]/phone[1] /tests/test[1]/info[1] /tests/test[2]/date[1] /tests/test[2]/time[1]/start[1] /tests/test[2]/time[1]/end[1] /tests/test[2]/facility[1]/name[1] /tests/test[2]/facility[1]/website[1] /tests/test[2]/facility[1]/street[1] /tests/test[2]/facility[1]/state[1] /tests/test[2]/facility[1]/city[1] /tests/test[2]/facility[1]/zip[1] /tests/test[2]/facility[1]/phone[1] /tests/test[2]/info[1]
那应该解决这个。没有?