XML Parsing

Sage
Posts: 1,066
Joined: 2004.07
Post: #1
I'm currently looking into XML Parsing. I'm trying to figure out TinyXML but really I just need a cross platform way of parsing in some XML. Below is a sample file. I've never done anything with XML before so I'm not sure 1) if the following is "legal" XML or 2) how to set the code into action.

Code:
<level number="1">
    <level_width>50</level_width>
    <level_height>20</level_height>
    <number_blocks>10</number_blocks>
    <block><x>0</x><y>0</y><z>0</z><w>50</w><h>1</h></block>
    <block><x>7</x><y>3</y><z>0</z><w>4</w><h>1</h></block>
    <block><x>10</x><y>2</y><z>0</z><w>4</w><h>1</h></block>
    <block><x>29</x><y>3</y><z>0</z><w>1</w><h>1</h></block>
    <block><x>33</x><y>3</y><z>0</z><w>1</w><h>1</h></block>
    <block><x>31</x><y>7</y><z>0</z><w>1</w><h>1</h></block>
    <block><x>22</x><y>1</y><z>0</z><w>1</w><h>1</h></block>
    <block><x>42</x><y>1</y><z>0</z><w>1</w><h>1</h></block>
    <block><x>50</x><y>1</y><z>0</z><w>1</w><h>20</h></block>
    <block><x>0</x><y>1</y><z>0</z><w>1</w><h>20</h></block>
    <player><x>2</x><y>2</y><z>0</z><w>1</w><h>2</h></player>
</level>

An example of the code using these numbers:
block.Init(x,y,z,w,h);
player.Init(x,y,z,w,h);
LevelWidth = <level_width>
MyLevel = number


If anyone could help me or point me in the right direction to start importing this, I would really appreciate it.
Quote this message in a reply
Member
Posts: 156
Joined: 2002.11
Post: #2
Cross-platform is going to be a headache. I've got some sample code that uses Carbon, if you change your mind.

This seems to be a good reference, if you want to know more about XML: http://www.alistapart.com/topics/xml/
Quote this message in a reply
Sage
Posts: 1,066
Joined: 2004.07
Post: #3
I think TinyXML is cross platform but I'm really new so what do I know? I'll look at that page a bit. It isn't so much the concept of XML but the actual code portion that I was unable to find good help with. Hopefully this link helps me out.
Quote this message in a reply
Moderator
Posts: 608
Joined: 2002.04
Post: #4
The Yoink source code uses TinyXML, if you can find it.
Quote this message in a reply
Sage
Posts: 1,066
Joined: 2004.07
Post: #5
Yes I tried to look at that but between what he admits is sloppy coding along with the complexity of the code (or at least by appearance) it doesn't make for a good beginner's material.
Quote this message in a reply
Member
Posts: 156
Joined: 2002.11
Post: #6
The Apple developer's web-site has documentation on how to use Carbon or Cocoa to parse XML files, with some good examples and sample code. I got my stuff from there.

Now, there's a way to save and retrieve CF (Core Foundations) objects directly to and from XML files that is very convenient. It uses a proprietary scheme from Apple, but it's more than enough for games. For instance, if you have a CFString, or a CFArray (or their NS counterparts), you can put that all into a file. Check it out.
Quote this message in a reply
Member
Posts: 131
Joined: 2004.10
Post: #7
1/ yup that's proper XML.

2/ I haven't dealt with tinyxml so I can't comment on that. I have used libxml2 ( http://www.xmlsoft.org used by the gnome guys ) but I haven't tried to compile it on the mac yet. It should compile as far as I know as it's cross platform with windows and linux and shouldn't really be using anything other than standard 'C'. You might just want to use the basic build of the lib and not get into the uglies of iconv and gettext to make this lib really complete.

I code on windows at work but noobie coder for the mac at home so my opinion may be bogus.
Quote this message in a reply
Moderator
Posts: 365
Joined: 2002.04
Post: #8
SimReality/Nick Wrote:Yes I tried to look at that but between what he admits is sloppy coding along with the complexity of the code (or at least by appearance) it doesn't make for a good beginner's material.
Hey, that's the good, non-disorganised part of the program! Wink

A few suggestions:

Don't make your XML hierarchy really complicated unless you really have to. The more your objects are nested inside one another, the harder it is to make sense of them when you iterate through them.

Do everything with attributes rather than child elements if you can. For example:

Code:
<level number="1">
    <level width="50" height="20"/>

    <block x="0" y="0" z="0" w="50" h="1"/>
    <block x="7" y="3" z="0" w="4" h="1"/>
    ...
        <player x="2" y="2" z="0" w="1" h="2"/>
</level>
That's a lot terser and it's easier to parse with TinyXML. I also omitted the <number_blocks>10</number_blocks> element because in my opinion, you shouldn't have to specify how many blocks there will be in advance; just count them and allocate memory for them as appropriate.

Here's a snippet of my TinyXML-based preferences code from Rescue:

Code:
TiXmlDocument document(filename);
bool success = document.LoadFile();
if(not success)
    return;

int value = 0;
const char *text = NULL;
TiXmlElement *element = document.RootElement();
if(element)
    element = element->FirstChildElement();

while(element)
{
    std::string element_name(element->Value());
    if(element_name == "window")
    {
        if(element->Attribute("width", &value))
        {
            if(value >= 640)
                mWindowWidth = value;
        }

        if(element->Attribute("height", &value))
        {
            if(value >= 480)
                mWindowHeight = value;
        }

        if(element->Attribute("depth", &value))
        {
            if(value == 16 or value == 32)
                mWindowDepth = value;
        }
    }
    else if(element_name == "mouse")
    {
        text = element->Attribute("scaling");
        if(text)
        {
            Ng::Float mouse_scaling = strtod(text, NULL);
            if(mouse_scaling > 0.0 and mouse_scaling < 20.0)
                mMouseScaling = mouse_scaling;
        }
    }
    else if(element_name == "stars")
    {
        if(element->Attribute("quantity", &value))
        {
            if(value >= 0)
                mStarQuantity = value;
        }
    }

    element = element->NextSiblingElement();
}
It's pretty simple. You just create a TiXmlDocument, tell it to load the file, find the root element (and examine its attributes if you want), then iterate through the root's children. For each child, you examine its name (.Value()) and attributes and perform an action based on that information. You could also either recurse into the child's children or skip over them - it's up to you.

Don't forget to read the TinyXML documentation. There isn't really much to it, and you don't need to bother with most of the methods. The ones you see in the code above are quite adequate for most purposes.

Neil Carter
Nether - Mac games and comic art
Quote this message in a reply
Sage
Posts: 1,066
Joined: 2004.07
Post: #9
I've been working on TinyXML for a while now and I think I have the code all worked out but when I compile I get a linking error:

Code:
Building target “Sidescroller” with build style “Development” (optimization:level ‘0’, debug-symbols:on) — (1 error, 1 warning)
        /usr/bin/g++-3.3  -o "/Users/nicholasgravelyn/*Source Code*/Sidescroller/build/Sidescroller.app/Contents/MacOS/Sidescroller"  "-L/Users/nicholasgravelyn/*Source Code*/Sidescroller/build"  "-F/Users/nicholasgravelyn/*Source Code*/Sidescroller/build" "-F/Users/nicholasgravelyn/Library/Frameworks"  -filelist "/Users/nicholasgravelyn/*Source Code*/Sidescroller/build/Sidescroller.build/Sidescroller.build/Objects-normal/LinkFileList"  "-arch" "ppc" "-prebind" "-Wl,-no_arch_warnings" "-framework" "SDL"   "-framework" "Cocoa" "-framework" "OpenGL" "-framework" "SDL"
ld: multiple definitions of symbol _main
/Users/nicholasgravelyn/*Source Code*/Sidescroller/build/Sidescroller.build/Sidescroller.build/Objects-normal/ppc/SDLMain.o definition of _main in section (__TEXT,__text)
/Users/nicholasgravelyn/*Source Code*/Sidescroller/build/Sidescroller.build/Sidescroller.build/Objects-normal/ppc/xmltest.o definition of _main in section (__TEXT,__text)
ld: warning prebinding disabled because dependent library: /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit can't be searched
        ld: multiple definitions of symbol _main
        ld: warning prebinding disabled because dependent library: /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit can't be searched
Any ideas?
Quote this message in a reply
Moderator
Posts: 365
Joined: 2002.04
Post: #10
Just remove the file xmltest.cpp from your project. It's an example app with its own main() function, so you don't need it to use the library.

Neil Carter
Nether - Mac games and comic art
Quote this message in a reply
Sage
Posts: 1,066
Joined: 2004.07
Post: #11
I deleted xmltest.cpp and I'm still getting the error. Do I have to do more than just delete the file?
Quote this message in a reply
DoG
Moderator
Posts: 869
Joined: 2003.01
Post: #12
Clean & Rebuild the project. The already compiled .o isn't removed until then.
Quote this message in a reply
Sage
Posts: 1,066
Joined: 2004.07
Post: #13
I didn't do the clean and rebuild but I did shut down Xcode and restart my computer (for another reason) and now it works. My XML imports correctly and it's pretty cool. Now to continue on making a level editor to make my job easier.
Quote this message in a reply
Post Reply