可以在循环中使用SelectSingleNode而不是Select吗?

时间:2011-02-06 19:22:13

标签: c# xpath

有没有办法在循环或递归中使用SelectSingleNode来获得相同的结果  Select方法返回的节点集?我不想用的原因 选择是因为在执行时我无法显示进度消息  用户。此外,如果需要很长时间,那么应用程序可能会出现 已停止响应,用户可能认为它已挂断。如果我可以使用 反复选择SelectSingleNode,然后我可以显示进度并保留应用程序  resposive。我需要这个来处理用户可能输入的任何XPath表达式。  在第一个SelectSingleNode之后,我认为xpath表达式必须是 改变,所以起点是当前的背景,我无法弄明白。

        string localXPathExpr = "//b:book[contains(b:author,'Melville')]";

        XmlReaderSettings settings = new XmlReaderSettings();
        settings.ProhibitDtd = false;
        settings.XmlResolver = null;
        XmlReader reader = null;
        XmlNamespaceManager nsmgr=null;
        XPathNavigator nav = null;
        XPathNodeIterator xNode = null;            

            reader = XmlReader.Create(xmlfile, settings); 
            nsmgr = new XmlNamespaceManager(reader.NameTable);
            //if xpath has prefix, extract it and add to namespacemanager
            string prefix = Form1.NSPrefix(localXPathExpr);
            if (string.IsNullOrEmpty(prefix) == false)
            {
                if (string.IsNullOrEmpty(Form1.NSUri) == false) 
                {
                    nsmgr.AddNamespace(prefix, Form1.NSUri);
                }
                else
                {
                    nsmgr.AddNamespace(prefix, rootNodeNamespace);
                }
            }                 XPathDocument doc = new XPathDocument(reader);
            nav = doc.CreateNavigator();

           // xNode = nav.Select(localXPathExpr, nsmgr); 
            XPathNavigator single = nav.SelectSingleNode(localXPathExpr, nsmgr);
           //to get the next book, I think the xpath expression would have to be      changed so the start point is the current context of single
          // I tried the current context operator  "./b:book[contains(b:author,'Melville')]" and also tried
          // "/b:book[contains(b:author,'Melville')]" but they both return null.
            XPathNavigator next = single.SelectSingleNode(localXPathExpr, nsmgr); 

输入来源:

<bookstore xmlns="http://www.mybookstore.com/books">
    <book genre="novel" publicationdate="1847-11-17" ISBN="0-201-63361-2">
        <title>The Confidence Man</title>
        <author>
            <first-name>Herman</first-name>
            <last-name>Melville</last-name>
        </author>
        <price>11.99</price>
    </book>
 <book genre="novel" publicationdate="1841-09-11" ISBN="0-201-76361-2">
        <title>Moby Dick</title>
        <author>
            <first-name>Herman</first-name>
            <last-name>Melville</last-name>
        </author>
        <price>11.99</price>
    </book>
</bookstore>

4 个答案:

答案 0 :(得分:1)

答案是:是的,但是......

有几个问题需要解决

0.1。 如果XML文件很大,我怀疑大量处理时间不是用于评估XPath表达式本身,而是用于解析XML文件。

0.2。 始终尽量避免使用//缩写,因为它通常会导致评估速度非常慢。如果您知道XML文档的结构并且b:book仅出现在某些位置,那么使用它会更有效(例如):

/*/b:book[contains(b:author,'Melville')]

大于

//b:book[contains(b:author,'Melville')]

0.3。 仅在你无法做到的情况下.2。上面,您可以实现以下

在循环SelectSingleNode()中调用以下表达式(索引应该是循环计数器):

   (//b:book[contains(b:author,'Melville')])[1]

   (//b:book[contains(b:author,'Melville')])[2]

   (//b:book[contains(b:author,'Melville')])[3]

   (//b:book[contains(b:author,'Melville')])[4]

。 。 。 。 。 。 。 。 。 。 。 。 。

假设优化器很好并且在找到想要的出现时停止评估完整表达式,那么对第一个表达式的评估将比评估完整表达式//b:book[contains(b:author,'Melville')]快得多。

当然,选择最后一个节点的时间仍然很长,因此您可以采用混合策略:逐个选择前N个(比如100个)节点,然后评估完整表达式{{1} }。

答案 1 :(得分:0)

我无法使用SelectSingleNode看到任何明确的解决方案。

我建议你使用完整的SelectBackgroundWorker帖子让你的表单在选择过程中做出响应(当然这样可以防止显示选择的进度)。

BTW,我认为xpath查询的缓慢是由contains部分引起的。
所以,作为一种解决方法,你可以这样做:

  1. 简化您的xpath删除contains(您的选择应该明显加快)
  2. 执行选择并保留节点列表
  3. 迭代执行先前删除的contains的节点。在此循环中,您可以显示进度条...

答案 2 :(得分:0)

我认为你应该调查大部分时间占用的东西。解析XPathDocument很可能是最耗时的部分。您可以通过扩展XmlTextReader类在解析过程中提供反馈。一个非常简单的例子:

public class MyXmlReader : XmlTextReader
{
    public MyXmlReader(string filename)
        : base(filename)
    {
    }

    public override bool Read()
    {
        Console.WriteLine("Reading line {0}.", this.LineNumber);
        return base.Read();
    }
}

答案 3 :(得分:0)

虽然没有办法在默认的.NET库中执行您的建议,但在XQSharp中,XPath实现具有方法Evaluate,该方法将对表达式执行惰性求值,将意味着您可以在评估每个项目时报告进度,而不是预先评估它们。

(免责声明:我在XQSharp开发团队中)