Ошибка добавления XPathExpression

#c# #xml #xpath

#c# #xml #xpath

Вопрос:

Я пытаюсь отсортировать результат запроса xpath, но это не удается.

Вывод вывода:

 ABC
DEF
 

Но я ожидаю:

 DEF
ABC
 

Исходный код выглядит следующим образом, он использует XML-выражение и сортирует результат:

 var doc = new XPathDocument("testmsg2.xml");
var nav = doc.CreateNavigator();

const string query = "//Z/X/Code";

var expr = nav.Compile(query);
expr.AddSort("Code",
             XmlSortOrder.Descending,
             XmlCaseOrder.None,
             "",
             XmlDataType.Text);

switch (expr.ReturnType)
{                
    case XPathResultType.NodeSet:
        var nodes = (XPathNodeIterator)nav.Evaluate(expr);

        while (nodes != null amp;amp; nodes.MoveNext())
        {
            if (nodes.Current == null)
                continue;

            if (nodes.Current.HasChildren)
            {
                var childIter = nodes.Current.SelectChildren(XPathNodeType.All);

                while (childIter.MoveNext())
                {
                    if (childIter.Current != null)
                        Console.WriteLine(childIter.Current.Value);
                }
            }
            else
            {
                Console.WriteLine(nodes.Current.Value);
            }
        }

        break;
}
 

XML-файл упрощен для этого примера:

 <?xml version="1.0" encoding="utf-8"?>
<Z>
  <X>
    <Code>ABC</Code>
  </X>
  <X>
    <Code>DEF</Code>
  </X>
</Z>
 

Ответ №1:

AddSort Метод принимает выражение XPath, которое контекстуально привязано к XPathExpression скомпилированному вами. В вашем случае XPathExpression скомпилирован для <Code> элемента. Выполнение AddSort("Code") подразумевает, что у вас есть следующий XML:

 <Code>
    <Code>
    </Code>
</Code>
 

Вместо этого вы можете либо скомпилировать свое выражение в X :

 const string query = "//Z/X";
 

Или вы можете выполнить сортировку по текущему узлу (являющемуся Code ), . :

 expr.AddSort(".", XmlSortOrder.Descending, XmlCaseOrder.None, "", XmlDataType.Text);
 

Ответ №2:

Что ж, ваш путь //Z/X/Code выбирает Code элементы, затем сортировка должна использовать правильное относительное выражение, в вашем случае

 expr.AddSort(".",
             XmlSortOrder.Descending,
             XmlCaseOrder.None,
             "",
             XmlDataType.Text);
 

Ответ №3:

Либо удалите «/ Code» из вашего запроса, мы используем «.» вместо «Code» в AddSort() — в зависимости от того, хотите ли вы выбрать X-узлы или Code-узлы. В настоящее время вы запрашиваете кодовые узлы, а затем пытаетесь отсортировать их по тому, что возвращает применение XPath «Code» к результату. Но нет ничего, что соответствовало бы «коду» относительно кодового узла.

Комментарии:

1. Что, если я хочу отсортировать содержимое и оставить там /Code ?

2. Извините, я не совсем уверен, чего вы хотите достичь. Как вы хотите, чтобы результат вашего запроса выглядел на первом уровне?

Ответ №4:

Некоторая альтернатива с использованием Linq для Xml

 using System.Xml.XPath;

var document = XDocument.Parse(@"<Z>
                                  <X>
                                    <Code>ABC</Code>
                                  </X>
                                  <X>
                                    <Code>DEF</Code>
                                  </X>
                                 </Z>");

var codeValues = document.XPathSelectElements("//Z/X/Code")
                          .Select(e => e.Value)
                          .OrderByDescending(e => e);
 

Вы можете упростить его еще больше, если хотите. Однако необходимо учитывать производительность. Если ваши XML-файлы большие, я думаю, это не будет работать так же хорошо. Если у вас есть только небольшие файлы, простота этого перевешивает небольшое снижение производительности.

Комментарии:

1. Хотя технически это не неправильный ответ, он не связан с проблемой, с которой сталкивается OP. Это скорее альтернатива, чем решение.

2. Спасибо за голосование @DanAtkinson. В первом абзаце указано, что это альтернатива. Тем не менее, рабочая, более элегантная альтернатива.

3. Это был не я, кто проголосовал против вас ( i.imgur.com/o8Qgl9X.png ). Хотя я с радостью признаю, что я мог бы подделать это изображение. С какой целью, я не знаю.