Urho3D Wiki
mNo edit summary
Tags: Visual edit apiedit
(Removed C++11)
Tags: Visual edit apiedit
Line 8: Line 8:
 
 
 
// loads a level, the given filename could be "maps/level_1.xml"
 
// loads a level, the given filename could be "maps/level_1.xml"
level::level(std::string level_filename)<br>{<br> pugi::xml_document doc;<br> pugi::xml_parse_result result=doc.load_file(("Data/"+level_filename).c_str());<br> if(!result)<br> {<br> std::cout<<"XML parsed with errors, attr value: ["<<doc.child("node").attribute("attr").value()<<"]\n";<br> std::cout<<"Error description: "<<result.description()<<"\n";<br> std::cout<<"Error offset: "<<result.offset<<" (error at [..."<<(result.offset)<<"]\n\n";<br> }<br><br> for(auto& c:doc.children())<br> {<br> for(pugi::xml_node& child:c.children())<br> {<br> std::string name(child.name());
+
level::level(std::string level_filename)<br>{<br> pugi::xml_document doc;<br> pugi::xml_parse_result result=doc.load_file(("Data/"+level_filename).c_str());<br> if(!result)<br> {<br> std::cout<<"XML parsed with errors, attr value: ["<<doc.child("node").attribute("attr").value()<<"]\n";<br> std::cout<<"Error description: "<<result.description()<<"\n";<br> std::cout<<"Error offset: "<<result.offset<<" (error at [..."<<(result.offset)<<"]\n\n";<br> }<br><br> for(pugi::xml_node_iterator it=doc.children().begin();it!=doc.children().end();it++)<br>
  +
{
if(name=="flag")<br> {<br> float pos_x=0;<br> float pos_y=0;<br> float pos_z=0;<br><br> for(pugi::xml_attribute& attr:child.attributes())<br> {<br> if(std::string(attr.name())=="pos_x")<br> pos_x=std::stof(std::string(attr.value()));<br> else if(std::string(attr.name())=="pos_y")<br> pos_y=std::stof(std::string(attr.value()));<br> else if(std::string(attr.name())=="pos_z")<br> pos_z=std::stof(std::string(attr.value()));<br> }<br> // flag_positions is a std::vector<Urho3D::Vector3><br> flag_positions.emplace_back(pos_x,pos_y,pos_z);<br> }
 
  +
pugi::xml_node& c=*it;<br> for(pugi::xml_node_iterator it=c.children().begin();it!=c.children().end();it++)<br>
  +
{
  +
pugi::xml_node& child=*it; <br><br> std::string name(child.name());
  +
if(name=="flag")<br> {<br> float pos_x=0;<br> float pos_y=0;<br> float pos_z=0;<br><br> for(pugi::xml_attribute_iterator it=child.attributes().begin();it!=child.attributes().end();it++)<br>
  +
{<br>
  +
pugi::xml_attribute& attr=*it;
 
<br> if(std::string(attr.name())=="pos_x")<br> pos_x=std::stof(std::string(attr.value()));<br> else if(std::string(attr.name())=="pos_y")<br> pos_y=std::stof(std::string(attr.value()));<br> else if(std::string(attr.name())=="pos_z")<br> pos_z=std::stof(std::string(attr.value()));<br> }<br> // flag_positions is a std::vector<Urho3D::Vector3><br> flag_positions.emplace_back(pos_x,pos_y,pos_z);<br> }
 
else if(name=="sound")<br> {
 
else if(name=="sound")<br> {
// sound_name is a Urho3D::String<br> for(pugi::xml_attribute& attr:child.attributes())<br> if(std::string(attr.name())=="name")<br> sound_name=attr.value();<br> }
+
// sound_name is a Urho3D::String<br> for(pugi::xml_attribute_iterator it=child.attributes().begin();it!=child.attributes().end();it++)<br>
  +
{<br>
  +
pugi::xml_attribute& attr=*it;
  +
<br> if(std::string(attr.name())=="name")<br> sound_name=attr.value();
  +
}<br> }
 
...<br> }<br> }<br>}
 
...<br> }<br> }<br>}
 
'''Note:''' std::stof converts a std::string to a float, there is also stoi for string -> int.
 
'''Note:''' std::stof converts a std::string to a float, there is also stoi for string -> int.

Revision as of 10:55, 7 March 2016

Urho3D uses PugiXML (http://pugixml.org/) and offers wrapping objects for that. I used PugiXML here directly because I used it before and the interface is already quite good and is relatively good documented. Maybe Urho's wrapper has some advantages, maybe not.

Parsing a XML file like this (a map file for USP):

<xml>
<static_model name="Data/Models/level_1" pos_x="0" pos_y="0" pos_z="-10" />
<player pos_x="4" pos_y="10" pos_z="-5" />
<flag pos_x="20.35" pos_y="14" pos_z="-47.6" />
<flag pos_x="-9.9" pos_y="14" pos_z="-47.7" />
<torch pos_x="-244" pos_y="36.2" pos_z="-104" />
<torch pos_x="-199" pos_y="28" pos_z="-138" />
<sound name="Music/Drums of the Deep.ogg" />
</xml>

Can be done like this:

#include <Urho3D/ThirdParty/PugiXml/pugixml.hpp>
...

// loads a level, the given filename could be "maps/level_1.xml"
level::level(std::string level_filename)
{
pugi::xml_document doc;
pugi::xml_parse_result result=doc.load_file(("Data/"+level_filename).c_str());
if(!result)
{
std::cout<<"XML parsed with errors, attr value: ["<<doc.child("node").attribute("attr").value()<<"]\n";
std::cout<<"Error description: "<<result.description()<<"\n";
std::cout<<"Error offset: "<<result.offset<<" (error at [..."<<(result.offset)<<"]\n\n";
}

for(pugi::xml_node_iterator it=doc.children().begin();it!=doc.children().end();it++)
{ pugi::xml_node& c=*it;
for(pugi::xml_node_iterator it=c.children().begin();it!=c.children().end();it++)
{ pugi::xml_node& child=*it;

std::string name(child.name()); if(name=="flag")
{
float pos_x=0;
float pos_y=0;
float pos_z=0;

for(pugi::xml_attribute_iterator it=child.attributes().begin();it!=child.attributes().end();it++)
{
pugi::xml_attribute& attr=*it;
if(std::string(attr.name())=="pos_x")
pos_x=std::stof(std::string(attr.value()));
else if(std::string(attr.name())=="pos_y")
pos_y=std::stof(std::string(attr.value()));
else if(std::string(attr.name())=="pos_z")
pos_z=std::stof(std::string(attr.value()));
}
// flag_positions is a std::vector<Urho3D::Vector3>
flag_positions.emplace_back(pos_x,pos_y,pos_z);
} else if(name=="sound")
{ // sound_name is a Urho3D::String
for(pugi::xml_attribute_iterator it=child.attributes().begin();it!=child.attributes().end();it++)
{
pugi::xml_attribute& attr=*it;
if(std::string(attr.name())=="name")
sound_name=attr.value(); }
} ...
}
}
}

Note: std::stof converts a std::string to a float, there is also stoi for string -> int.

Handy Print Function

This recursive function uses PugiXML to print everything in an XML file in a nice tree-ish view with indentation:

void xml_print(const pugi::xml_node& n,int depth)
{
    std::string name(n.name());
    if(name!="")
    {
        for(int i=0;i<depth;i++)
            std::cout<<"  ";
        std::cout<<"name: "<<name<<endl;
    }

    std::string value(n.value());
    if(value!="")
    {
        for(int i=0;i<depth;i++)
            std::cout<<"  ";
        std::cout<<"value: "<<value<<endl;
    }

    for(pugi::xml_attribute& attr:n.attributes())
    {
        for(int i=0;i<depth;i++)
            std::cout<<"  ";
        std::cout<<"attribute '"<<attr.name()<<"': '"<<attr.value()<<"'"<<std::endl;
    }
    for(pugi::xml_node& child:n.children())
    {
        for(int i=0;i<depth;i++)
            std::cout<<"  ";
        std::cout<<"child"<<std::endl;
        xml_print(child,depth+1);
    }
}

Usage:

pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file("test.xml");
if(!result)
{
    std::cout<<"XML parsed with errors, attr value: ["<<doc.child("node").attribute("attr").value()<<"]\n";
    std::cout<<"Error description: "<<result.description()<<"\n";
    std::cout<<"Error offset: "<<result.offset<<" (error at [..."<<(result.offset)<<"]\n\n";
    return;
}

for(auto& c:doc.children())
    xml_print(c,0);

Example output (from a totally different but more complex XML file):

name: rdf:RDF
attribute 'xmlns:foaf': 'http://xmlns.com/foaf/0.1/'
attribute 'xmlns:rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
attribute 'xmlns:ussec': 'http://www.rdfabout.com/rdf/schema/ussec/'
attribute 'xmlns:corp': 'http://xmlns.com/foaf/corp#'
child
  name: corp:Company
  attribute 'rdf:about': 'http://www.rdfabout.com/rdf/usgov/sec/id/cik0000037996'
  child
    name: ussec:tradingSymbol
    child
      value: F
  child
    name: foaf:name
    child
      value: FORD MOTOR CO
  child
    name: ussec:tenPercentOwnerOf
    attribute 'rdf:resource': 'http://www.rdfabout.com/rdf/usgov/sec/id/cik0001075056'
    attribute 'foaf:name': 'VASTERA INC'
  child
    name: ussec:cik
    child
      value: 0000037996