Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XML in C# - hasAttribute, getAttribute is not there? Why?

Tags:

c#

parsing

xml

I'm working on a project that requires me to build a game's rooms, items and NPC in a separate database. I've chosen XML, but something prevents me from properly parsing the XML in my C# code. What am I doing wrong?

My errors are these:

System.xml.xmlnode does not contain a definition for HasAttribute 

(this goes for GetAttribute as well) and no extension method accepting 'HasAttribute' accepting a first argument of type System.Xml.XmlNode ?

This also goes for GetParentNode, and my very last line

string isMoveableStr = xmlRoom.GetAttribute("isMoveable");

somehow goes:

the name xmlRoom does not exist in the current context

Here's the method:

public void loadFromFile()
    {
        XmlDocument xmlDoc = new XmlDocument();              // create an xml document object in memory.
        xmlDoc.Load("gamedata.xml");                         // load the XML document from the specified file into the object in memory.

        // Get rooms, NPCs, and items.
        XmlNodeList xmlRooms = xmlDoc.GetElementsByTagName("room");
        XmlNodeList xmlNPCs = xmlDoc.GetElementsByTagName("npc");
        XmlNodeList xmlItems = xmlDoc.GetElementsByTagName("item");

        foreach(XmlNode xmlRoom in xmlRooms) {               // defaults for room:

        string roomID = ""; 
        string roomDescription = "this a standard room, nothing special about it.";                  

        if( !xmlRoom.HasAttribute("ID") )                   //http://msdn.microsoft.com/en-us/library/acwfyhc7.aspx
        {              
        Console.WriteLine("A room was in the xml file without an ID attribute. Correct this to use the room"); 
        continue;                                       //skips remaining code in loop 

            } else {
             roomID = xmlRoom.GetAttribute("id");           //http://msdn.microsoft.com/en-us/library/acwfyhc7.aspx
            }

        if( xmlRoom.hasAttribute("description") )              
        {
            roomDescription = xmlRoom.GetAttribute("description");
        }

        Room myRoom = new Room(roomDescription, roomID); //creates a room
        rooms.Add(myRoom); //adds to list with all rooms in game ;)

            } foreach(XmlNode xmlNPC in xmlNPCs)
            { bool isMoveable = false;

        if( !xmlNPC.hasAttribute("id") )
        {
            Console.WriteLine("A NPC was in the xml file, without an id attribute, correct this to spawn the npc");
            continue; //skips remaining code in loop
        }

        XmlNode inRoom = xmlNPC.getParentNode();
        string roomID = inRoom.GetAttribute("id");

        if( xmlNPC.hasAttribute("isMoveable") )
        {
            string isMoveableStr = xmlRoom.GetAttribute("isMoveable");
            if( isMoveableStr == "true" )
            isMoveable = true;
            }

        }
    }
like image 708
Ithaca Avatar asked Dec 11 '12 19:12

Ithaca


2 Answers

System.Xml.XmlElement has the function you are looking for. You are getting XMLNode's. You will need to cast the nodes to XmlElement to get that function.

xmlElement = (System.Xml.XmlElement)xmlRoom;
like image 82
Bryan Roberts Avatar answered Oct 13 '22 03:10

Bryan Roberts


This is not specifically germane to your question, but a response to @ChaosPandion's suggestion and your question in the comments, here is your code example using Linq to XML:

var xdoc = XDocument.Load("gamedata.xml");
var xRooms = xdoc.Descendants("room");
List<Room> rooms;

//If an element doesn't have a given attribute, the Attribute method will return null for that attribute
//Here we first check if any rooms are missing the ID attribute
if (xRooms.Any( xRoom => (string)xRoom.Attribute("ID") == null )) {
    Console.WriteLine("A room was in the xml file without an ID attribute...");
} else {
    rooms = (
        from xRoom in xRooms
        select new Room(
            xRoom.Attribute("description") ?? "this a standard room, nothing special about it.",
            (int)xRoom.Attribute("ID")
        )
    ).ToList();
}

var xNPCs = xdoc.Descendants("npc");
if (xNPCs.Any( xNPC => (string)xNPC.Attribute("id") == null )) {
    Console.WriteLine("A NPC was in the xml file, without an id attribute, correct this to spawn the npc");
} else {
    var npcs = (
        from xNPC in xNPCs
        let inRoom = xNPC.Parent
        select new {
            xNPC,
            inRoom,
            isMoveable = (string)xNPC.Attribute("isMoveable") != null &&
                         (string)inRoom.Attribute("isMoveable") == true
        }
    ).ToList();
}

Then you can use a simple foreach on the npcs collection:

foreach (var npc in npcs) {
    Console.WriteLine(inRoom.Attribute("ID"));
    Console.WriteLine(npc.IsMoveable);
}

OTOH since this code makes use of the Descendants method, which returns an collection of XElement (the type corresponding to an XML element) and not of XNode (the type corresponding to an XML node), the whole issue of a node object not having attributes is neatly sidestepped.

like image 41
Zev Spitz Avatar answered Oct 13 '22 04:10

Zev Spitz