I've been working on learning how to use TinyXML. The tutorial done by Ellers has been a great help. However, I've exceeded the scope of the examples and I'm not sure how to go beyond it.
I'm able to successfully create an XML file, but I'm unable to read it back completely.
I've tried hRoot.FirstChild("Page").FirstChild("Function").Element() as well with
the same result. Could someone point out what I've done wrong and help clear up what I'm obviously misunderstanding about how this works?
Thanks for your time!
g.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks for the nice words about the tutorial and for explaining your problem so clearly.
It looks to me like the problem is in getting the element vs the first child. The first child is a text node containing whitespace. Annoying, but all DOM parsers will (or should) do that. What you need is FirstChildElement(), I think.
After making the changes you suggested, I'm still not getting the result I expected.
The lines that use FirstChildElement() should end with .Element() otherwise I get a compiler error (I'm using CodeGear's C++ Builder 2007). It complains that it cannot convert TiXmlHandle to TiXmlElement. I thought this was a bit odd because FirstChildElement() sounds like it should be a TiXmlElement type.
I've uploaded the whole LoadConfig() routine that I've written so you can see the snippet within the context of the whole routine.
I started thinking about how the whole thing worked as a heirarchy of elements.
In tracing the logical flow of the XML in my head, it dawned on me that the reason it was grabbing the data from the first page element twice is because that's exactly what it was told to do.
What I needed to do is figure out how to make the section that processes eage page element to START from within the current page, not from the top. That got me thinking about whether or not I could use the pPageNode element as a starting point instead of the hRoot element. That lead to the line:
..then I would be left working within the current function element of the current page element.
I'm hoping my blind stumbling around will help someone else with a similar problem, but I'm sure there are more elegant solutions to the "hit it with a hammer" method I'm using. :)
thanks all!
g.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I've been working on learning how to use TinyXML. The tutorial done by Ellers has been a great help. However, I've exceeded the scope of the examples and I'm not sure how to go beyond it.
I'm able to successfully create an XML file, but I'm unable to read it back completely.
Here's the output generated:
<?xml version="1.0" ?>
<SpecialApp>
<!-- Settings for SpecialApp -->
<Messages>
<Farewell>Second Message</Farewell>
<Welcome>First Message</Welcome>
</Messages>
<Pages>
<Page name="Main Page" id="1">
<Function name="switch one" script="test1.lua" />
<Function name="switch two" script="test2.lua" />
</Page>
<Page name="Next Page" id="2">
<Function name="fake func" script="fake script " />
<Function name="fake func" script="fake script " />
</Page>
</Pages>
</SpecialApp>
Now I'm able to read the Messages section and part of the Pages section, but I'm not able to read the Function elements.
Here's the code that I'm using to read the file in - this just covers the "Page" section:
TiXmlElement *pPageNode = hRoot.FirstChild("Pages").FirstChild().Element();
for(pPageNode; pPageNode; pPageNode = pPageNode->NextSiblingElement()) {
const char *pPageName = pPageNode->Attribute("name");
if (pPageName)
page_name = pPageName;
pPageNode->QueryIntAttribute("id", &page_id);
TiXmlElement *pPage = hRoot.FirstChild("Page").FirstChild().Element();
for(pPage; pPage; pPage = pPage->NextSiblingElement()) {
const char *pFuncName = pPage->Attribute("name");
if(pFuncName) {
function_count++;
function_name[function_count] = pFuncName;
}
}
}
pPage is _always_ NULL.
I've tried hRoot.FirstChild("Page").FirstChild("Function").Element() as well with
the same result. Could someone point out what I've done wrong and help clear up what I'm obviously misunderstanding about how this works?
Thanks for your time!
g.
After poking at it for a while, I've had some limited success:
Changing the line:
TiXmlElement *pPage = hRoot.FirstChild("Page").FirstChild().Element();
to:
TiXmlElement *pPage = hRoot.FirstChild("Pages").FirstChild("Page").Child("Function",0).Element();
Now allows me access to the Function elements. HOWEVER, it's not correctly iterating through the Page elements.
It grabs the first page name and it's function elements, it grabs the second pages' name but then returns the function elements from the "first" page.
What little bit of magic am I missing?
thanks all!
g.
Thanks for the nice words about the tutorial and for explaining your problem so clearly.
It looks to me like the problem is in getting the element vs the first child. The first child is a text node containing whitespace. Annoying, but all DOM parsers will (or should) do that. What you need is FirstChildElement(), I think.
Code something like this should work:
TiXmlElement *pPageNode
= hRoot.FirstChild("Pages").FirstChildElement(); // <-- CHANGED HERE
for(pPageNode; pPageNode; pPageNode = pPageNode->NextSibling())
{
const char *pPageName = pPageNode->Attribute("name");
if (pPageName)
page_name = pPageName;
pPageNode->QueryIntAttribute("id", &page_id);
TiXmlElement *pPage =
hRoot.FirstChild("Page").FirstChildElement(); // <-- CHANGED HERE
for(pPage; pPage; pPage = pPage->NextSiblingElement()) {
const char *pFuncName = pPage->Attribute("name");
if(pFuncName) {
function_count++;
function_name[function_count] = pFuncName;
}
}
}
HTH
Ellers
Ellers, you're quite welcome.
After making the changes you suggested, I'm still not getting the result I expected.
The lines that use FirstChildElement() should end with .Element() otherwise I get a compiler error (I'm using CodeGear's C++ Builder 2007). It complains that it cannot convert TiXmlHandle to TiXmlElement. I thought this was a bit odd because FirstChildElement() sounds like it should be a TiXmlElement type.
I've uploaded the whole LoadConfig() routine that I've written so you can see the snippet within the context of the whole routine.
The url is http://rafb.net/p/Ye2KfZ65.html
I very much appriciate your taking the time to help me out with this!
g.
Ok, I've been picking at this some more and I think I've actually come up with a solution!
The code link is here: http://rafb.net/p/ICThUX90.html
I started thinking about how the whole thing worked as a heirarchy of elements.
In tracing the logical flow of the XML in my head, it dawned on me that the reason it was grabbing the data from the first page element twice is because that's exactly what it was told to do.
What I needed to do is figure out how to make the section that processes eage page element to START from within the current page, not from the top. That got me thinking about whether or not I could use the pPageNode element as a starting point instead of the hRoot element. That lead to the line:
TiXmlElement *pPage = pPageNode->FirstChildElement("Function")->ToElement();
Since pPageNode is populated with the current page element, the above code works to extract the function elements from within the current page.
If I need to go deeper, it would be logical (but accurate?) to assume that if I were to declare a new element like:
TiXmlElement *pFoo = pPage->FirstChildElement("Foo")->ToElement();
..then I would be left working within the current function element of the current page element.
I'm hoping my blind stumbling around will help someone else with a similar problem, but I'm sure there are more elegant solutions to the "hit it with a hammer" method I'm using. :)
thanks all!
g.