Guy Ben-Moshe
Guy Ben-Moshe

Reputation: 934

Reading Sub-Elements (child nodes) with XMLreader using C#

First: This is NOT a duplicate of Reading Child Nodes with XMLReader (Not the same language, Couldn't get it to help me).

I'm pretty new to XMLreading, I am trying to reach the Sub Element of a specific Element but I am having hard time reaching it, here is an example:

The XML element:

<Group ExerciseNumber="0" Name="R33-IOS1_IOS1" ExerciseName="Unallocated" Status="offline" StatusStatistics="0/1">
      <Clients>
        <Client ClientName="R33-IOS1_IOS1" MachineName="R33-IOS1" ClientType="HC0" ClientStatus="Disconnected" />
      </Clients>
      <GroupAppendedData GroupID="201" Type="IOS" DomeType="None" ConnectedTo="" ForceType="Enemy" />
    </Group>

I am trying to reach the "Client" element from the specific "Group" element, This is my C# code:

while (reader.Read())
            {
                if (reader.Name.Equals("Group"))
                {
                    name = reader.GetAttribute("Name");
                    // Now I need to reach the specific "MachineName" attribute of the "Client" sub-element but don't know how.
                }
            }
            reader.Close();

Notes: It's important that the client element reading will be in the same loop iteration (if possible, if not I will have to think of another design for my generating class).

*Editing the XML is not an option.

Thank you.

Upvotes: 1

Views: 3272

Answers (3)

jdweng
jdweng

Reputation: 34421

try ReadFrom() method in xml linq

            while (reader.Read())
            {
                if (reader.Name.Equals("Group"))
                {
                    XElement group =  (XElement)XDocument.ReadFrom(reader);
                }
            }
            reader.Close();​

Upvotes: 1

w.b
w.b

Reputation: 11228

LINQ to XML would be easier to use than XmlReader, this will give you machine names for all Clients in the document:

var machineNames = XElement.Parse("data.xml")
                           .Descendants("Client")
                           .Select(client => client.Attribute("MachineName").Value);

Edit - this returns both names in every iteration:

var query = XElement.Load("data.xml")
                    .Descendants("Client")
                    .Select(client => new {
                               MachineName = client.Attribute("MachineName").Value,
                               GroupName = client.Ancestors("Group").Select(g => g.Attribute("Name").Value).First()
                           });

foreach (var x in query)
    Console.WriteLine($"GroupName: {x.GroupName}, MachineName: {x.MachineName}");

Upvotes: 2

Charles Mager
Charles Mager

Reputation: 26213

As suggested, unless you have a very good reason to use XmlReader then using a higher level API such as LINQ to XML would be preferred.

Here's a solution using query syntax:

var clients = from @group in doc.Descendants("Group")
              let groupName = (string) @group.Attribute("Name")
              from client in @group.Descendants("Client")
              select new
              {
                  GroupName = groupName,
                  ClientName = (string) client.Attribute("ClientName"),
                  MachineName = (string) client.Attribute("MachineName"),
              };

See this fiddle for a working example.

Upvotes: 1

Related Questions