Reputation: 2097
I have this xml
<?xml version="1.0" encoding="utf-8" ?>
<Departments>
<Department>
<id>001</id>
<Section>
<SectionId>001001</SectionId>
<Room>
<RoomID>001001001</RoomID>
<Owner>guest1</Owner>
</Room>
<Room>
<RoomID>001001002</RoomID>
<Owner>guest11</Owner>
</Room>
</Section>
<Section>
<SectionId>001002</SectionId>
<Room>
<RoomID>001002001</RoomID>
<Owner>guest2</Owner>
</Room>
</Section>
</Department>
</Departments>
and this is my code using Linq to Xml
var xDoc = XDocument.Load(inputUrl);
var sections = from el in xDoc.Descendants("Department")
where el.Element("id").Value.Equals("001")
select el.Element("Section");
var rooms = from el in sections
where el.Element("SectionId").Value.Equals("001001")
select el.Element("Room");
var roomsList = (from el in rooms
select new Room
{
roomID = (string)el.Element("RoomID"),
owner = (string)el.Element("Owner")
}).ToList();
My problem is I only get 1 room in the List,but I should get two.Please also advice if this is the right way of using LINQ to xml,I am fairly new to LINQ.
Upvotes: 1
Views: 858
Reputation: 32571
As an alternative to the other answers, you could use the Extensions.XPathSelectElements Method (XNode, String) (make sure you add the using System.Xml.XPath
directive to the top of your file):
string
departmentId = "001",
sectionId = "001001";
var xDoc = XDocument.Load(inputUrl);
var rooms = xDoc.XPathSelectElements(
String.Format(
"//Department[id={0}]/Section[SectionId={1}]/Room",
departmentId,
sectionId))
.Select(el => new Room
{
roomID = (string)el.Element("RoomID"),
owner = (string)el.Element("Owner")
}).ToList();
It's a matter of own preference. I find this shorter to write and easier to read.
Upvotes: 2
Reputation: 109792
Just to show that there are many ways to skin a cat:
var xDoc = XDocument.Load(@"C:\TEST\TEST.XML");
var depts = from e in xDoc.Descendants("Department")
where e.Element("id").Value.Equals("001")
select e;
var sections = from e in depts.Descendants("Section")
where e.Element("SectionId").Value.Equals("001001")
select e;
var rooms = (from e in sections.Descendants("Room")
select new //Room
{
ID = (string)e.Element("RoomID"),
Owner = (string)e.Element("Owner")
}).ToList();
Upvotes: 1
Reputation: 17603
You're only selecting one room in the middle query, it should be .Elements(...)
(pay attention to the trailing s
):
var rooms = from el in sections
where el.Element("SectionId").Value.Equals("001001")
select el.Elements("Room");
The same applies to your section
query.
Upvotes: 0
Reputation: 125650
Change sections
and rooms
queries to:
var sections = xDoc.Descendants("Department")
.FirstOrDefault(x => (string)x.Element("id") == "001")
.Elements("Section");
var rooms = sections.Where(x => (string)x.Element("SectionId") == "001001")
.Elements("Room");
With these, you'll get 2 rooms.
Why isn't your code working?
select el.Element("Section")
selects only first section
element within Department
- you'd never be able to get room from section
with id == "001002"
select el.Element("Room")
in rooms
query returns only first room from every matched section.You can change Element
to Elements
and add additional SelectMany(x => x)
calls to make your syntax-based queries work:
var sections = from el in xDoc.Descendants("Department")
where el.Element("id").Value.Equals("001")
select el.Elements("Section");
var rooms = from el in sections.SelectMany(x => x)
where el.Element("SectionId").Value.Equals("001001")
select el.Elements("Room");
var roomsList = (from el in rooms.SelectMany(x => x)
select new
{
roomID = (string)el.Element("RoomID"),
owner = (string)el.Element("Owner")
}).ToList();
Upvotes: 2
Reputation: 18411
What if you change:
select el.Element("Room");
to
select el.Elements("Room");
Upvotes: 0