views:

833

answers:

3

Given the following Xml fragment:

<root>
  <sheetData>
    <row r="1" />
    <row r="2" />
    <row r="3" />
    <row r="4" />
    <row r="5" />
    <row r="6" />
    <row r="7" />
  </sheetData>
</root>

Which can be created with the following code:

XElement testElement = new XElement("root",
    new XElement("sheetData",
        new XElement("row",
            new XAttribute("r", 1)),
        new XElement("row",
            new XAttribute("r", 2)),
        new XElement("row",
            new XAttribute("r", 3)),
        new XElement("row",
            new XAttribute("r", 4)),
        new XElement("row",
            new XAttribute("r", 5)),
        new XElement("row",
            new XAttribute("r", 6)),
        new XElement("row",
            new XAttribute("r", 7))));

Is this the best way to find the row where the r attribute is 2? This works, but I am repeating the Where clause in the select statement, and I am wondering if there is a better way and more efficent method.

int rowNumber = 2;

XElement rowElement = testElement
    .Descendants("sheetData")
    .Where<XElement>(item => item.Descendants("row")
                                  .Where<XElement>(i => i.Attribute("r").Value == rowNumber.ToString())
                                  .FirstOrDefault<XElement>() != null)
    .Select<XElement, XElement>(item => item.Descendants("row")
                                  .Where<XElement>(i => i.Attribute("r").Value == rowNumber.ToString())
                                  .FirstOrDefault<XElement>())
    .FirstOrDefault<XElement>();

In general what is the best way to determine if Linq to Xml query optimized?

+1  A: 
//if sheetData appears multiple times
    XElement rowElement = testElement
        .Descendants("sheetData")
        .SelectMany(s=>s.Descendats("row))
        .Where(i=>i.Attribute("r").Value == rowNumber.ToString());
//if sheetData appears once
    XElement rowElement = testElement
        .Element("sheetData")
        .Descendants("row))
        .Where(i=>i.Attribute("r").Value == rowNumber.ToString());
eglasius
+2  A: 

The best way is:

var row = testElement
   .XPathSelectElements("sheetData/row[@r='2']")
   .FirstOrDefault();

A pure LINQ query that doesn't repeat the Where call:

var row = testElement
    .Descendants("sheetData")
    .Descendants("row")
    .Where(x => x.Attribute("r").Value == "2")
    .FirstOrDefault();
Robert Rossney
where is the XPathSelectElements defined? if it is an extension method please post the namespace, I would love to have that in XElement :)
eglasius
I'd use .Where(x => (string)x.Attribute("r") == "2") instead. If no `r` attribute exists, it won't throw NullReferenceException.
Mehrdad Afshari
found it: http://msdn.microsoft.com/en-us/library/bb342176.aspx ...+1 very nice :) - I will surely use this one quite a bit
eglasius
A: 

Isn't the Select clause in your code redundant? Where returns an IEnumerable<XElement> already. I think

var row = testElements.Descendents("row").Where(e => (int)e.Attribute("r") == rowNumber).SingleOrDefault();

should do what you want

Lee