MTL323
MTL323

Reputation: 177

Find an Attribute based off Attribute in same element using XmlDocument

I am looking to loop thru an element based off one attribute, "sequence" , to retrieve another, "strokes".

My xml is as follows:

    <tournament>
  <leaderboard>
    <player first_name="Jimmy" last_name="Walker" country="UNITED STATES" id="2db60f6e-7b0a-4daf-97d9-01a057f44f1d" position="1" money="900000.0" points="500.0" score="-17" strokes="267">
      <rounds>
        <round score="-1" strokes="70" thru="18" eagles="0" birdies="5" pars="9" bogeys="4" double_bogeys="0" other_scores="0" sequence="1"/>
        <round score="-2" strokes="69" thru="18" eagles="0" birdies="3" pars="14" bogeys="1" double_bogeys="0" other_scores="0" sequence="2"/>
        <round score="-9" strokes="62" thru="18" eagles="0" birdies="10" pars="7" bogeys="1" double_bogeys="0" other_scores="0" sequence="3"/>
        <round score="-5" strokes="66" thru="18" eagles="0" birdies="6" pars="11" bogeys="1" double_bogeys="0" other_scores="0" sequence="4"/>
      </rounds>
    </player>
</leaderboard>
</tournament>

I am able to retrieve individual round elements based on the following code:

// EDITED TO REFLECT SOLUTION

foreach (XmlNode player in doc.GetElementsByTagName("player"))
            {
                string strokes;
                dtAttributeList.Rows.Add(
                    player.Attributes["last_name"].Value,
                    player.Attributes["first_name"].Value,
                    player.Attributes["position"].Value,
                    player.Attributes["score"].Value);
                if (player.HasChildNodes)
                {
                    foreach (XmlNode round in player.LastChild)
                    {
                        strokes = round.Attributes["strokes"].Value;
                        dtAttributeList.Rows.Add(strokes);
                    }
                }
            }

however in doing this I am only able to retrieve the first element and its values.

please help me find a solution to loop thru the "round" elements either via a filter on sequence or a loop of some sort.

Upvotes: 0

Views: 24

Answers (1)

JLRishe
JLRishe

Reputation: 101690

It's much easier to use XPath for this than the approach you've tried above. You're also creating a huge amount of duplicate code by using a for loop instead of foreach:

foreach (XmlNode player in doc.GetElementsByTagName("player"))
{
    string strokes;
    dtAttributeList.Rows.Add(
        player.Attributes["last_name"].Value,
        player.Attributes["first_name"].Value,
        player.Attributes["position"].Value, 
        player.Attributes["score"].Value);

    foreach (XmlNode round in player.SelectNodes("rounds/round"))
    {
        strokes = round.Attributes["strokes"].Value;
        dtAttributeList.Rows.Add(strokes);
    }
}

If you need to iterate throug them based on the order of sequence (and they're not already in order), you can do this:

var rounds = player.SelectNodes("rounds/round")
                   .OfType<XmlNode>()
                   .OrderBy(n => int.Parse(n.Attributes["sequence"].Value));
foreach (XmlNode round in rounds)
{
    // ...
}

Upvotes: 1

Related Questions