Rasmus
Rasmus

Reputation: 75

Accessing XElement with specific value

I am trying to save my battleship game to XML and so far it has gone pretty good. What I'm saving in the XML file is player names, coordinates for ships and misses.

The ID attribute for the ships is to know which ship coordinates makes a whole ship. Next up was marking each ship that it has been hit by adding an attribute to the correct element and I know what element to get by the value of it.

But I do not know how to get it. All I have found is how to get XElement by its name and all elements that has that name.

<?xml version="1.0" encoding="UTF-8" ?>
<Players>
  <Playerboard>
    <Name>Player</Name>
    <Ships>
      <ship id="1213">12_13</ship>
      <ship id="1213">12_14</ship>
      <ship id="1211">12_11</ship>
      <ship id="1211">12_12</ship>
    </Ships>
    <Misses>
      <Miss>3_9</Miss>
      <Miss>9_12</Miss>
      <Miss>10_12</Miss>
    </Misses>
  </Playerboard>
  <Computerboard>
    <Name>AI</Name>
    <Ships>
      <ship id="1010">10_10</ship>
      <ship id="1010">10_11</ship>
      <ship id="1010">10_12</ship>
      <ship id="1010">10_13</ship>
      <ship id="11">1_1</ship>
      <ship id="11">2_1</ship>
    </Ships> 
    <Misses>
      <Miss>0_2</Miss>
      <Miss>0_3</Miss>
      <Miss>1_3</Miss>
    </Misses>
  </Computerboard>
</Players>

this is as far as i've come with trying to get the correct element, which doesnt work. "k" in my example below is empty all the time.

XElement e = xelement.Element("Playerboard");
var ships = from s in e.Elements("Ships")            
                        where (string)s.Element("ship") == x + "_" +y
                        select s;

foreach (XElement k in ships) 
{ 
   Console.WriteLine(k);
}

So for example I want to add an attribute to the ship with value 12_12, how do I do that?

Upvotes: 2

Views: 995

Answers (2)

ocuenca
ocuenca

Reputation: 39326

You could also do this:

   int x = 12, y = 12;
   var doc =  XDocument.Load("[path of your xml]");

   //Finding the playerboard, by your structure I suppose you have one
   var playerBoard= doc.Descendants("Playerboard").FirstOrDefault();

  var ship = playerBoard.Element("Ships").Elements("ship").FirstOrDefault(e => e.Value == x + "_" + y);

  //Adding an attribute to the ship
  ship.Add(new XAttribute("Foo", "Boo")); 

Upvotes: 1

DaveShaw
DaveShaw

Reputation: 52788

This works fine for me:

var doc = XDocument.Parse(xml);

var elements =
    doc
    .Root                       //Ignore the root
    .Element("Playerboard")     //The Playerboard element.
    .Element("Ships")           //There's only one Ships element.
    .Elements("ship")           //Get all the ship elements from Ships.
    .Where(ship => ship.Value == "12_12");  //.Value is a little more explicit but you
                                            //want strings anyway.

foreach (var element in elements)
{
    Console.WriteLine(element);
    element.Add(new XAttribute("Name", "Value")); //Adding your new attribute.
    Console.WriteLine(element); 
}

I'm using the lambda syntax because I prefer it (sorry, it just makes it much clearer what I'm doing).

If you only expect one ship element to match the given value, you can just use .Single() at the end to avoid the collection too.

Upvotes: 2

Related Questions