Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting an XElement

Tags:

.net

linq

I have a XElement that maps like follows:

<book>
    <author>sadfasdf</author>
    <title>asdfasdf</title>
    <year>1999</year>
</book>
<book>
    <author>asdfasdf</author>
    <title>asdfasdf</title>
    <year>1888</year>
</book>
<book>
    <author>asdfsdf</author>
    <title>asdfasdf</title>
    <year>1777</year>
</book>

How can I sort the books by author or title or year? Thanks

like image 437
pistacchio Avatar asked Jun 09 '09 07:06

pistacchio


2 Answers

Do you want to read (query) the data in a specific order, or do you actually want to re-order the data in the xml? To read in a specific order, just use the LINQ OrderBy method:

    var qry = from book in el.Elements("book")
              orderby (int)book.Element("year")
              select new
              {
                  Year = (int)book.Element("year"),
                  Title = (string)book.Element("title"),
                  Author = (string)book.Element("author")
              };

(edited) Changing the xml is trickier... maybe something like:

    var qry = (from book in el.Elements("book")
               orderby (int)book.Element("year")
               select book).ToArray();

    foreach (var book in qry) book.Remove();
    foreach (var book in qry) el.Add(book);
like image 115
Marc Gravell Avatar answered Sep 19 '22 13:09

Marc Gravell


It's doable, but slightly odd:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

class Test
{
    static void Main()
    {
        string xml = 
@"<books>
  <book>
    <author>sadfasdf</author>
    <title>asdfasdf</title>
    <year>1999</year>
  </book>
  <book>
    <author>asdfasdf</author>
    <title>asdfasdf</title>
    <year>1888</year>
  </book>
  <book>
    <author>asdfsdf</author>
    <title>asdfasdf</title>
    <year>1777</year>
  </book>
</books>";
        XElement root = XElement.Parse(xml);

        List<XElement> ordered = root.Elements("book")
            .OrderBy(element => (int)element.Element("year"))
            .ToList();

        root.ReplaceAll(ordered);
        Console.WriteLine(root);
    }
}

Note that if you have other content under your root node, you should call Remove on each XElement before adding them, instead of just calling RemoveAll.

like image 24
Jon Skeet Avatar answered Sep 21 '22 13:09

Jon Skeet