reggaeguitar
reggaeguitar

Reputation: 1804

Select Multiple Values From Xml Document in One Statement

I'm trying to select the values from two adjacent xml nodes at the same time using

var values =
            xDoc.Element("root")
                .Elements("model")
                .Where(x => x.Element("modelName").Value == modelType.ToString())
                .Elements("directory")
                .Select(x => new { x.Element("directoryName").Value,
                               x.Element("taskName").Value });

I'm getting red squiggles under the .Values saying "Duplicate anonymous type property name 'Value'. Here is the xml

    <root>
  <model>
    <modelName>Model1</modelName>
    <directory>
      <directoryName>Dir1</directoryName>
      <taskName>Task1</taskName>
    </directory>
  </model>
  <model>
    <modelName>Model2</modelName>
    <directory>
      <directoryName>FirstValue</directoryName>
      <taskName>SecondValue</taskName>
    </directory>
  </model>
</root>

I want to extract Dir1 and Task1 or FirstValue and SecondValue.

Upvotes: 2

Views: 1801

Answers (2)

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236188

I suggest you to use casting elements to string instead of accessing their Value property. Because if element is missing (e.g. for Model1 you don't have taskName element) then you will get NullReferenceException.

var values = from m in xDoc.Root.Elements("model")
             where (string)m.Element("modelName") == modelType.ToString()
             let d = m.Element("directory")
             select new {
                Directory = (string)d.Element("directoryName"),
                Task = (string)d.Element("taskName")
             };

Also I find declarative (query) syntax more readable than lambda syntax (matter of taste). You can also use XPath to make query even more compact:

string xpath = String.Format("root/model[modelName='{0}']/directory", modelType);
var values = from d in xdoc.XPathSelectElements(xpath)
             select new {
                 Directory = (string)d.Element("directoryName"),
                 Task = (string)d.Element("taskName")
             };

Upvotes: 3

reggaeguitar
reggaeguitar

Reputation: 1804

Figured it out, you just need to name the properties in the anonymous type

var values =
            xDoc.Element("root")
                .Elements("model")
                .Where(x => x.Element("modelName").Value == modelType.ToString())
                .Elements("directory")
                .Select(x => new { Directory = x.Element("directoryName").Value,
                                   Task = x.Element("taskName").Value });

Upvotes: 2

Related Questions