获取完整路径当前节点 [英] Get full path to current node

查看:224
本文介绍了获取完整路径当前节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有一个的XPathNavigator 定位在一个节点上,我怎么能得到一个XPath EX pression的重新presents的路径节点,从根?

If I have an XPathNavigator positioned on a node, how can I get an XPath expression that represents the path to that node, from the root?

例如,如果XML是:

<data>
    <class name='dogs'>
        <item name='doberman />
        <item name='husky' />
    </class>
    <class name='cats'>
        <item name='persian' />
        <item name='tabby' />
    </class> </data>
</data>

...那么路径就波斯猫可能pssed为 EX $ P $ /数据/类[2] /项目[1]

我可以列举相关节点的祖先与 SelectAncestors()(或者我可以反复地爬了 SelectParent父母的关系() ),但是,这并不让我的位置信息。

I can enumerate the ancestors of the node in question with SelectAncestors() (or I could iteratively climb up the parent relationship with SelectParent()), but that doesn't get me the positional information.

请问我在使用位置()每个祖先计算XPath,还是有更好的方法来做到这一点?

Would I have to evaluate an XPath using position() for each ancestor, or is there a better way to do this?

推荐答案

假设你只对XML元素的XPath的兴趣,我实现了一个蛮力算法(即遍历XML结构)的扩展方法对的XmlElement 。这是非常相似的@ Zenexer的回答,虽然我已经就我自己的版本的时候,他张贴了他。

Assuming you're interested only in the xpath of xml elements, I implemented a brute force algorithm (i.e. traversing the XML structure) as extension methods on XmlElement. This is very similar to @Zenexer's answer, although I had already started on my own version when he posted his.

此外,通过阿列克谢的提示有关性能很感兴趣,我用一个比较复杂的XML文件lyring在这里产生出了一种测试用例。然后,我实现了两个版本的同一算法;一个依赖于previousSibling,和其他的迭代器节点顺序。第三个版本依靠XPath的位置()的功能,但如预期,并丢弃它没有工作。

Also, intrigued by Alexei's tip about performance, I created a sort of test case using a somewhat complex XML file lyring around here. Then I implemented two versions of the same algorithm; one that depends on PreviousSibling, and other that iterates nodes sequentially. A third version relied on XPath's position() function, but it didn't work as expected and was discarded.

虽然你应该检查自己,在我的机器,结果表明显著表现为反复版本的优势 - 1.7S对21S得分的兄弟姐妹版本

While you should check for yourself, in my machine the results showed a significant performance advantage for the iterative version -- 1.7s against 21s scored by the siblings version.

Importart:这些扩展方法在静态类XmlElementExtension声明

Importart: these extension methods are declared inside a static class XmlElementExtension.

    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());
                });
    }

这篇关于获取完整路径当前节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆