Xpath сортировка из XML-документа - PullRequest
4 голосов
/ 07 февраля 2010

У меня есть документ XML, и он содержит некоторые данные даты, такие как:

<Message>
<messagetext>Testing purpose only</messagetext>
<date>05.02.2010</date>
</Message>

Я хочу, чтобы они были отсортированы по ключу XPath, как его получить?

Ответы [ 4 ]

3 голосов
/ 07 февраля 2010

Класс XPathExpression позволяет добавлять спецификации сортировки. Вот пример кода, который должен работать с .NET 2.0:

XPathDocument doc = new XPathDocument(@"..\..\XMLFile1.xml");
XPathNavigator nav = doc.CreateNavigator();
XPathExpression exp = nav.Compile("Messages/Message");
exp.AddSort(
  "number(concat(substring(date, 7), substring(date, 4, 2), substring(date, 1, 2)))",
  XmlSortOrder.Descending, 
  XmlCaseOrder.None, 
  null, 
  XmlDataType.Number
);
foreach (XPathNavigator msg in nav.Select(exp))
{
  Console.WriteLine(
    "{0}: {1}", 
    msg.SelectSingleNode("date").Value, 
    msg.SelectSingleNode("messagetext").Value
  );
}

С XMLFile1.xml, равным

<Messages>
  <Message>
    <messagetext>Message 2</messagetext>
    <date>04.02.2010</date>
  </Message>
  <Message>
    <messagetext>Message 1</messagetext>
    <date>05.02.2010</date>
  </Message>
  <Message>
    <messagetext>Message 3</messagetext>
    <date>05.02.2009</date>
  </Message>
</Messages>

вывод

05.02.2010: Message 1
04.02.2010: Message 2
05.02.2009: Message 3

Предполагаемый формат даты - ddmmyyyy, но вы можете при необходимости изменить эти выражения подстроки, если хотите mmddyyyy.

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

Вы можете сделать это, используя LINQ to XML, следующим образом. Я предполагаю, что вы используете формат MM.dd.yyyy, но это легко изменить, если вы хотите:

using System;
using System.Linq;
using System.Xml.Linq;

public class Message
{
    public string Text { get; set; }
    public DateTime Date { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        XDocument doc = XDocument.Load("input.xml");
        var messages = doc.Descendants("Message")
            .Select(element => new Message
            {
                Text = element.Element("messagetext").Value,
                Date = DateTime.ParseExact(element.Element("date").Value, "MM.dd.yyyy", null)
            }).OrderBy(message => message.Date);
        foreach (Message message in messages)
        {
            Console.WriteLine("{0} : {1}", message.Date, message.Text);
        }
    }
}

Результаты:

02-05-2010 00:00:00 : Test1
17-05-2010 00:00:00 : Test2
22-05-2010 00:00:00 : Test3

Данные испытаний, которые я использовал:

<xml>
  <Message>
    <messagetext>Test1</messagetext>
    <date>05.02.2010</date>
  </Message>
  <Message>
    <messagetext>Test3</messagetext>
    <date>05.22.2010</date>
  </Message>
  <Message>
    <messagetext>Test2</messagetext>
    <date>05.17.2010</date>
  </Message>
</xml>
0 голосов
/ 07 февраля 2010

Если у вас есть контроль над форматом XML, я бы рекомендовал изменить формат даты на ISO 8601. Таким образом, даты можно сортировать как обычные строки. Например, 05.02.2010 будет 2010-05-02. Кроме того, ISO 8601 является менее двусмысленным (месяц перед днем ​​или день перед месяцем?)

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

Прежде всего XPath не поможет выполнить какую-либо сортировку, кроме как как часть XSLT-преобразования. Во-вторых, XPath 1.0, используемый в .NET, не поддерживает даты.

Самый простой подход - это загрузить XML в XDocument и использовать код, подобный этому (предполагается, что ряд узлов «Message» находится под верхним корневым узлом в документе): -

Func<XElement, DateTime> fn = e => DateTime.ParseExact(e.Element("date").Value, "dd.MM.yyyy", CultureInfo.InvariantCulture);

var messages = doc.Root.Elements("Message").OrderBy(fn);

foreach (var elem in messages)
{
    Console.WriteLine(fn(elem));
}

В качестве альтернативы, если у вас есть причина придерживаться XmlDocument, этот немного более уродливый код будет работать: -

Func<XmlElement, DateTime> fn = e => DateTime.ParseExact(e.SelectSingleNode("date").InnerText, "dd.MM.yyyy", CultureInfo.InvariantCulture);

var messages = doc.DocumentElement.SelectNodes("Message")
    .Cast<XmlElement>().OrderBy(fn);


foreach (var elem in messages)
{
    Console.WriteLine(fn(elem));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...