Можно ли использовать SelectSingleNode в цикле вместо Select? - PullRequest
2 голосов
/ 06 февраля 2011

Есть ли способ использовать SelectSingleNode в цикле или рекурсивно, чтобы получить тот же набор узлов, которые возвращает метод Select? Причина, по которой я не хочу использовать Выберите это потому, что во время выполнения я не могу отображать сообщения о прогрессе Пользователь. Кроме того, если это занимает много времени, приложение может перестали отвечать, и пользователь может подумать, что он повесил трубку. Если я могу использовать Несколько раз выберите SingleSode, тогда я могу показать прогресс и сохранить приложение 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 ]

1 голос
/ 07 февраля 2011

Ответ: да, но ...

Существует несколько проблем, которые необходимо решить :

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) узлов один за другим, а затем оценить полное выражение //b:book[contains(b:author,'Melville')].

0 голосов
/ 10 февраля 2011

Хотя нет способа сделать то, что вы предлагаете в библиотеках .NET по умолчанию, в XQSharp реализация XPath имеет метод Evaluate , который будет выполнять ленивую оценку выражение, которое будет означать, что вы можете сообщать о ходе выполнения, оценивая каждый элемент, а не оценивая их все заранее.

(Отказ от ответственности: я в команде разработчиков XQSharp)

0 голосов
/ 07 февраля 2011

Я думаю, вы должны выяснить, что занимает большую часть времени.Вполне возможно, что разбор 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();
    }
}
0 голосов
/ 06 февраля 2011

Я не вижу четкого решения, используя SelectSingleNode.

Я бы посоветовал вам использовать полную нить Select и BackgroundWorker, чтобы сделать вашу форму отзывчивой во время выбора (конечно, это исключает возможность показать ход выбора).

Кстати, я полагаю, что медлительность вашего запроса xpath связана с частью contains.
Таким образом, как обходной путь, вы можете сделать что-то вроде этого:

  1. Упростите ваш xpath, удалив contains (ваш выбор должен быть значительно быстрее)
  2. Выполнить выбор и сохранить список узлов
  3. Итерация узлов, выполняющих contains, ранее удаленных. В этом цикле вы можете показать индикатор выполнения ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...