Sign in to follow this  
ninmonkeys

TinyXML: basic file reading

Recommended Posts

I've been reading the TinyXml documentation, and examples, but I'm having trouble getting it to read the values of elements, and attributes. I'm trying to read the values and attributes of the children if item elements. What am I doing wrong? Here's my example todo xml file. If the way I structered it seems wrong, say something. (Wasn't really sure how to structure it)
<TodoList>
	<item group="group1" title="script">
		<date year="2006" month="04" day="17"/>
		<text>make some script
		</text>
	</item>

	<item group="misc" title="tinyxml">
		<date year="2006" month="04" day="23"/>
		<text>fix it
		</text>
	</item>

</TodoList>
My real code is a mess, so here's the psuedo code.
	//root of document, in this case I'm taking root of item elements
	itemRoot = document.root().child("todolist");
	
	//grab first item element
 	curElem = itemRoot.Child("item");	
 	
 	//iterate through all item elements
	foreach(curElem = curElem.NextSibling())
	{
		cout << "Item: " << title << endl;
		cout << "date: " year << month << day;
		cout << "text: " << text << endl;
		
	}
Here's my current code to read the file. It's a real mess.
	//Item: each child 'item' of root
	//block: item/string? table
	{		
		todo_list.clear();
		
		//get first 'item' element
		//pElem=hRoot.FirstChild( "item" ).FirstChild().Element();
		//pElem=hRoot.FirstChild( "item" ).FirstChild("text").Element();
		
		//iterate through all items
		for(pElem=hRoot.FirstChild("item").Element(); pElem;
  			pElem->NextSiblingElement()) {
  			
  			//read children 'date', and 'text'
  
     		//attributes of date
  			//const char* attrib = pElem->FirstChild("year")->Attribute();
  			//if(attrib) { cout << "item->year: attribute=" << attrib << endl; }
  			
  			//text value
  			TiXmlElement* pCur = 0;
  			pCur = hRoot.Element();
  			if(!pCur) break;
  			pCur = pCur->FirstChildElement("item");
  			if(!pCur) break;
  			pCur = pCur->FirstChildElement("date");
  			if(!pCur) break;
  			if(pCur->Attribute("day")) {
  				cout << "\tAttribute=" << pCur->Attribute("day") << endl;
  			}
  			
  			
		}
		
		/*
		//iterate through all 'item' elements
		for( pElem; pElem; pElem=pElem->NextSiblingElement())
  		{
  			//append text to vector
  			const char* pText = pElem->GetText();
  			if(pText) {
  				cout << "key=" << pElem->Value() << ", "
  					<< "item: text=" << pText << endl;
			}
	 
		}*/
		
	
	}//end block
The output I get is repeated forever. It doesn't look like an endless loop to me. Unless next sibling doesn't ever end returning valid elements?
[tab]Attribute=17
[tab]Attribute=17
[tab]Attribute=17
[tab]Attribute=17
...etc...

Share this post


Link to post
Share on other sites
A stab in the dark, try changing:

for(pElem=hRoot.FirstChild("item").Element(); pElem;
pElem->NextSiblingElement())



to


for(pElem=hRoot.FirstChild("item").Element(); pElem;
pElem=pElem->NextSiblingElement())

Share this post


Link to post
Share on other sites
That was it.

Incase it will help someone else, here's my code to read the above xml file. I'm not error checking everything, and if I could get the number of children I wouldn't need to use pElem just as a counter for "item"'s offset.
using namespace std;

//! Date structure, member of TodoData, used for element 'item'->'date' attributes
struct Date {
Date() : year(0), month(0), day(0) {}
int year; //! year
int month;//! month
int day; //! day
};

//! holds data from an 'item' element in the todo list
class TodoData {
public:
std::string text; //!item text
std::string group; //!item group name
std::string title; //!item title
Date date; //! Date of 'item'

TodoData() : text("no text"), group("no group"), title("no title") {}

//!prints data to stdout
void Print(void) {
cout << "\ttitle=" << title << endl
<< "\tgroup=" << group << endl
<< "\tdate=" << date.year << "/" << date.month << "/"
<< date.day << endl
<< "\ttext=" << text << endl;

}
private:
};

//! read the xml todo file into vector of TodoData
void xmlRead(std::string filename) {

TiXmlDocument doc(filename.c_str());
if(!doc.LoadFile()){
cout << "Error: could not load file: " << filename << endl;
return;
}

TiXmlElement* pElem; //!current element
TiXmlElement* pChild; //!current child of pElem
TiXmlHandle hDoc(&doc); //!handle to xml document
TiXmlHandle hRoot(0); //! handle to root element 'TodoList'

vector<TodoData> todo_list; //! todo list, data of all 'item' elements in xml
int count=0; //! item count, starts at 0. used for index of 'item' element

//get root element 'TodoList', set to hRoot
pElem = hDoc.FirstChildElement().Element();
if(!pElem) { cout << "no valid root! quit-ing function!" << endl; return; }
//debug: cout << "root: " << pElem->Value() << endl;
hRoot = TiXmlHandle(pElem);


//Item: each child element named 'item' of hRoot ('TodoList')
{//block: main loop (block not required)
todo_list.clear();//clear vector

count = 0;
//element: 'item', get attributes 'group', 'title', then iterate
//through siblings of 'item'
for(pElem=hRoot.FirstChild("item").Element(); pElem;
pElem = pElem->NextSiblingElement())
{
//todo: not right, since pElem isn't used, but works for now?
TodoData cur; //current data in this 'item' element

//get 'item' element
pChild = hRoot.Child("item",count).Element();
//debug: cout << "count: " << count << endl;
if(pChild) {
//debug: cout << "\tpChild: ok" << endl;
}else {
cout << "\tpChild: invalid!" << endl;
}
//read element 'item' attributes
cur.group = pChild->Attribute("group");
cur.title = pChild->Attribute("title");
/*debug:
cout << "\titem group=" << pChild->Attribute("group")
<< " title=" << pChild->Attribute("title") << endl; */



//get element 'date', child of 'item'
TiXmlElement* pCur = pChild->FirstChildElement("date");
//debug: cout << "\tpCur = pChild->FirstChildElement('date');" << endl;
if(pCur) {
//debug: cout << "\tpCur: ok" << endl;
}else {
cout << "\tpCur: invalid!" << endl;
}
//read attributes of element 'date'
/* debug:
cout << "\tyear=" << pCur->Attribute("year")
<< " month=" << pCur->Attribute("month")
<< " day=" << pCur->Attribute("day") << endl; */


//read date attributes, ints
pCur->Attribute("year",&cur.date.year);
pCur->Attribute("month",&cur.date.month);
pCur->Attribute("day",&cur.date.day);

//get element 'text', child of 'item'
pCur = pChild->FirstChildElement("text");
//debug: cout << "\tpCur = pChild->FirstChildElement('text');" << endl;
if(pCur) {
//debug: cout << "\tpCur: ok" << endl;
}else {
cout << "\tpCur: invalid!" << endl;
}


//read element 'text' value
const char* pText = pCur->GetText();
if(pText) {
/* debug:
cout << "\ttext=";
cout << pText << endl; */


cur.text = pText;
}else{
cout << "pText: invalid!" << endl;
}


//append current 'item' data to todo_list, and increment counter
todo_list.push_back(cur);
count++;
}

cout << "iterate through vector:" << endl;
//iterate through vector
count=0;
for(vector<TodoData>::iterator iter=todo_list.begin();
iter != todo_list.end(); iter++)
{
cout << count << ")" << endl;
iter->Print();
count++;
}
cout << count+1 << " items parsed." << endl;

}//end: block main loop (shouldn't be here, reminant from tut)


}//end: function


int main(int argc, char *argv[]) {

xmlRead("demo.todo.xml");

cout << "Done." << endl;
system("pause"); //remove #include <cstdio> and this line unless you want it
return 0;
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this