Advertisement Jump to content
Sign in to follow this  
MARS_999

tinyxml2 and how to read files

This topic is 1740 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am trying to use tinyxml2 to read in a file like this...

<resources>
<resource UID="1" type="graphic" filename="smoke.png" scenescope="0"></resource>
<resource UID="2" type="graphic" filename="face_colorkey.png" scenescope="0"></resource>
<resource UID="3" type="graphic" filename="Tiles.png" scenescope="0"></resource>
<resource UID="4" type="audio" filename="myaudio.mp3" scenescope="0" audio_type="stream"></resource>
<resource UID="5" type="audio" filename="music.ogg" scenescope="0" audio_type="sample"></resource>
</resources>

tinyxml2::XMLDocument doc;
    if(doc.LoadFile(Filename.c_str()) == tinyxml2::XML_NO_ERROR)
    {
   int v0 = 0; 
tinyxml2::XMLElement* ResourceElement = doc.FirstChildElement("resources")->FirstChildElement("resource");
ResourceElement->QueryIntAttribute("UID", &v0);
std::cout << v0 << std::endl;
ResourceElement->QueryIntAttribute("scenescope", & v0);
std::cout << v0 << std::endl;
}

I don't see any ResourceElement->QueryStringAttribute() abilities so I am confused...

 

Thanks!

Share this post


Link to post
Share on other sites
Advertisement

Ive only done a small test of tinyxml2 havent moved to it yet, but that looks like it should work the interface didnt change that much. Does it load correctly? If you set a break in the if statement is it reached? What about "doc.RootElement()->FirstChildElement("resource");" ?

Share this post


Link to post
Share on other sites

There is const char* Attribute(const char* attribName) method in XMLElement you could use.

Edited by imoogiBG

Share this post


Link to post
Share on other sites

thanks guys I found this to work so far...

 

 
for(tinyxml2::XMLElement* child = doc.FirstChildElement("resources")->FirstChildElement("resource"); 
child != 0; child = child->NextSiblingElement())
{
if(child->ToElement()->Attribute("UID"))
std::cout << "UID = "        << child->ToElement()->Attribute("UID")        << std::endl;
if(child->ToElement()->Attribute("type"))
std::cout << "type = "      << child->ToElement()->Attribute("type")       << std::endl;
if(child->ToElement()->Attribute("filename"))
std::cout << "filename = "   << child->ToElement()->Attribute("filename")   << std::endl;
if(child->ToElement()->Attribute("scenescope"))
std::cout << "scenescope = " << child->ToElement()->Attribute("scenescope") << std::endl;
if(child->ToElement()->Attribute("audio_type"))
std::cout << "audio_type = " << child->ToElement()->Attribute("audio_type") << std::endl;
std::cout << std::endl;
} 

Share this post


Link to post
Share on other sites

There is no need for you to call ToElement on child, because the for loop makes sure its an element already. And with FirstAttribute on an element you can actually iterate over the attributes of an element cleaning this code up a bit. Also it is better to use FindAttribute on element than just Attribute, you are not trying to match an Attribute with name and value, so FindAttribute actually expresses your intent better and makes your code more maintainable.

Share this post


Link to post
Share on other sites

Cleaning up the 'const', removing the extra casts (as NightCreature83 suggests) and using a QueryAttribute to get an unsigned, the main loop looks like:

tinyxml2::XMLDocument doc;
if(doc.LoadFile("resources.xml") == tinyxml2::XML_NO_ERROR)
{
	for( const tinyxml2::XMLElement* child = doc.FirstChildElement("resources")->FirstChildElement("resource"); 
		 child; 
		 child = child->NextSiblingElement())
	{
		if(child->Attribute("UID"))
			std::cout << "UID = "        << child->Attribute("UID")        << std::endl;

		// assuming you want UID as an unsigned:
		unsigned uid = 0;
		child->QueryAttribute( "UID", &uid);
		std::cout << "UID = "        << uid        << std::endl;

		std::cout << std::endl;
	}
}

Share this post


Link to post
Share on other sites
One more suggestion: save the results to non-constant-time functions like Attribute() in local variables. There's no good reason to ask the data structure to do the search twice. This isn't just a TinyXML-specific hint but in general a very good practice to get into. Don't look up twice what you can look up once.

unsigned uid = 0;
const char* uidString = child->Attribute("UID");
if (uidString != nullptr)
{
  uid = parseInteger(uidString);
  std::cout << "UID = " << uid << " (\"" << uidString << "\")\n";
}
While not critical in real game code, note also that I am _not_ using std::endl. That manipulator not only ends a line but also requests that output be flushed from internal buffers to the OS, which is not an efficient thing to do. It should only be used for logging output or other output that you need output even in case of a crash or if you need the output to appear immediately. For general output, use "\n" instead, and call std::cout << std::flush after performing a chunk of operations (for example, after you process the document) so that the output shows up even if the program goes off to do other things.

I know a lot of learning resources tell you to use std::endl at the end of a line but they are simply wrong. http://en.cppreference.com/w/cpp/io/manip/endl Note also how the example code at that link calls std::cout.sync_with_stdio(false) at the start of main, since even using only \n can cause unnecessary flushes for some runtime library implementations.

Share this post


Link to post
Share on other sites

There is no need to use string parsing on your own, the XMLAttribute in tinyXml has function to get the value of an attribute as an Int, Float and bool. So store a XMLAttribute* instead when you query for the attribute and you now have both tag name and attribute value stored in one handy reference.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!