Есть ли ошибка в моем коде XML или в .NET? - PullRequest
1 голос
/ 29 октября 2010

Я только что столкнулся с проблемой, когда мой код нормально разбирал xml, но как только я добавил второй узел, он начал загружать неверные данные.Настоящий код охватывает несколько классов и проектов, но для примера я собрал основы того, что вызывает проблему

Когда код будет запущен, я ожидаю, что вывод будет содержимым второй задачиузел, но вместо этого выводится содержимое первого узла.Он продолжает извлекать данные из первого вхождения узла EmailAddresses, несмотря на то, что при проверке объекта настроек его внутренний XML-код совпадает со вторым узлом Задачи.При вызове SelectSingleNode("//EmailAddresses") возникает проблема.

У меня есть два пути решения этой проблемы

  1. Удалите косые черты из выражения XPath EmailAddresses
  2. ВызовClone() после получения узла Задача или Настройки

Решение 1 в этом случае работает, но я считаю, что это приведет к тому, что другой код в моем проекте перестанет работать.

Решение 2 выглядит болеедля меня это скорее хак, чем реальное решение.

Мой вопрос: действительно ли я делаю это правильно, и есть ошибка в .NET (все версии), или я просто неправильно извлекаю XML?

код c #

var doc = new XmlDocument();
doc.Load(@"D:\temp\Sample.xml");

var tasks = doc.SelectSingleNode("Server/Tasks");

foreach (XmlNode threadNode in tasks.ChildNodes)
{
    if (threadNode.Name.ToLower() != "thread")
    {
        continue;
    }

    foreach (XmlNode taskNode in threadNode.ChildNodes)
    {
        if (taskNode.Name.ToLower() != "task" || taskNode.Attributes["name"].Value != "task 1")
        {
            continue;
        }

        var settings = taskNode.SelectSingleNode("Settings");

        var emails = settings.SelectSingleNode("//EmailAddresses");

        Console.WriteLine(emails.InnerText);
    }
}

XML

<?xml version="1.0"?>
<Server>
    <Tasks>
        <Thread>
            <Task name="task 2">
                <Settings>
                    <EmailAddresses>task 2 data</EmailAddresses>
                </Settings>
            </Task>
        </Thread>
        <Thread>
            <Task name="task 1">
                <Settings>
                    <EmailAddresses>task 1 data</EmailAddresses>
                </Settings>
            </Task>
        </Thread>
    </Tasks>
</Server>

Ответы [ 2 ]

5 голосов
/ 29 октября 2010

С http://www.w3.org/TR/xpath/#path-abbrev

// это сокращение от /descendant-or-self::node()/. За Например, //para - это сокращение от /descendant-or-self::node()/child::para и поэтому выберет любой элемент в документ (даже элемент para, который будет выбран элемент документа на //para с элемента документа узел является дочерним по отношению к корневому узлу);

А также:

Шаг местоположения . является коротким для self::node(). Это особенно полезно в сочетании с //. За Например, путь местоположения .//para коротка для

self::node()/descendant-or-self::node()/child::para

и так выберет все пара потомков элементы узла контекста.

Вместо:

var settings = taskNode.SelectSingleNode("Settings");

var emails = settings.SelectSingleNode("//EmailAddresses");

Использование:

var emails = taskNode.SelectSingleNode("Settings/EmailAddresses");
3 голосов
/ 29 октября 2010

Выражение // 1002 * XPath не делает то, что вы думаете, оно делает. Это selects nodes in the document from the current node that match the selection no matter where they are.

Другими словами, он не ограничен текущей областью действия, он фактически сканирует дерево документа и начинает сопоставление с корневого элемента.

Чтобы выбрать первый <EmailAddresses> элемент в текущей области, вам нужно только:

var emails = settings.SelectSingleNode("EmailAddresses");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...