获取当前节点的完整路径
如果我在节点上放置了XPathNavigator
,我如何从根目录获取表示该节点路径的XPath表达式?
例如,如果XML是:
…那么波斯猫的路径可以表示为/data/class[2]/item[1]
我可以使用SelectAncestors()
枚举相关节点的祖先(或者我可以使用SelectParent()
迭代地爬上父关系),但这并不能获得位置信息。
我是否必须使用position()
为每个祖先评估一个XPath,还是有更好的方法来做到这一点?
假设您只对xml元素的xpath感兴趣,我实现了一个powershell算法(即遍历XML结构)作为XmlElement
上的扩展方法。 这与@ Zenexer的答案非常相似,尽管我在发布他的时候已经开始使用我自己的版本了。
另外,受到Alexei关于性能的提示的启发,我使用一个复杂的XML文件创建了一种测试用例。 然后我实现了相同算法的两个版本; 一个依赖于PreviousSibling,另一个依赖迭代节点。 第三个版本依赖于XPath的position()
函数,但它没有按预期工作并被丢弃。
虽然您应该自己检查,但在我的机器中,结果显示迭代版本具有显着的性能优势 – 兄弟姐妹版本对21s进行了1.7s。
Importart:这些扩展方法在static class XmlElementExtension
中声明。
PreviousSibling版本
public static string GetXPath_UsingPreviousSiblings(this XmlElement element) { string path = "/" + element.Name; XmlElement parentElement = element.ParentNode as XmlElement; if (parentElement != null) { // Gets the position within the parent element, based on previous siblings of the same name. // However, this position is irrelevant if the element is unique under its parent: XPathNavigator navigator = parentElement.CreateNavigator(); int count = Convert.ToInt32(navigator.Evaluate("count(" + element.Name + ")")); if (count > 1) // There's more than 1 element with the same name { int position = 1; XmlElement previousSibling = element.PreviousSibling as XmlElement; while (previousSibling != null) { if (previousSibling.Name == element.Name) position++; previousSibling = previousSibling.PreviousSibling as XmlElement; } path = path + "[" + position + "]"; } // Climbing up to the parent elements: path = parentElement.GetXPath_UsingPreviousSiblings() + path; } return path; }
迭代版
public static string GetXPath_SequentialIteration(this XmlElement element) { string path = "/" + element.Name; XmlElement parentElement = element.ParentNode as XmlElement; if (parentElement != null) { // Gets the position within the parent element. // However, this position is irrelevant if the element is unique under its parent: XmlNodeList siblings = parentElement.SelectNodes(element.Name); if (siblings != null && siblings.Count > 1) // There's more than 1 element with the same name { int position = 1; foreach (XmlElement sibling in siblings) { if (sibling == element) break; position++; } path = path + "[" + position + "]"; } // Climbing up to the parent elements: path = parentElement.GetXPath_SequentialIteration() + path; } return path; }
测试用例
private static void Measure(string functionName, int iterations, Action implementation) { Stopwatch watch = new Stopwatch(); watch.Start(); for (int i = 0; i < iterations; i++) { implementation(); } watch.Stop(); Console.WriteLine("{0}: {1}ms", functionName, watch.ElapsedMilliseconds); } private static void Main(string[] args) { XmlDocument doc = new XmlDocument(); doc.Load(@"location of some large and complex XML file"); string referenceXPath = "/vps/vendorProductSets/vendorProductSet/product[100]/prodName/locName"; Measure("UsingPreviousSiblings", 10000, () => { XmlElement target = doc.SelectSingleNode(referenceXPath) as XmlElement; Debug.Assert(referenceXPath == target.GetXPath_UsingPreviousSiblings()); }); Measure("SequentialIteration", 10000, () => { XmlElement target = doc.SelectSingleNode(referenceXPath) as XmlElement; Debug.Assert(referenceXPath == target.GetXPath_SequentialIteration()); }); }
未测试; 仅适用于从XmlDocument对象创建的XPathNavigator对象:
private static string GetPath(this XPathNavigator navigator) { StringBuilder path = new StringBuilder(); for (XmlNode node = navigator.UnderlyingObject as XmlNode; node != null; node = node.ParentNode) { string append = "/" + path; if (node.ParentNode != null && node.ParentNode.ChildNodes.Count > 1) { append += "["; int index = 1; while (node.PreviousSibling != null) { index++; } append += "]"; } path.Insert(0, append); } return path.ToString(); }
以下是您将如何使用它:
XPathNavigator navigator = /* ... */; string path = navigator.GetPath();
然而…
XPathNavigator对象通常位于根节点上。 创建它们后,它们的位置无法更改,但您可以使用它们来选择后代。 也许有办法完全避免这个问题? 例如,如果您只想要当前节点,则可以使用XPathNavigator.UnderlyingObject
,如示例中所示。
使用ParentNode的简单解决方案。 只需前进到根节点并记住您传递的每个节点名称。 经测试!
上述就是C#学习教程:获取当前节点的完整路径分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
// Get the node full path static string getPath(XmlNode node) { string path = node.Name; XmlNode search = null; // Get up until ROOT while ((search = node.ParentNode).NodeType != XmlNodeType.Document) { path = search.Name + "/" + path; // Add to path node = search; } return "//"+path; }
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1022954.html