Improved ofxXmlSettings addon (Hopefully!)

Hi

I’ve been using the ofxXmlSettings in my work, along with Shotgunninja’s attribute changes. This setup makes xml reading very straightforward, so thanks to all those involved.

I did however notice a few small bugs and extensive use of temp string copying and dynamic memory allocations, which would result in inefficiency and memory fragmentation. Also, as tinyxml supports std::string, there was a bit of needless conversion from char* to string and vice versa. The new code fixes some problems I was seeing, which were (I think) related to memory fragmentation. The changes fix those problems.

I’ve uploaded a modified version, building on shotgunninja’s changes which is a drop in replacement for the ofxXmlSettings files. I also modified ofToDataPath to have a const string& argument. The archive can be found here.

This has been tested with my own code and with the addon example, but that’s not to say it’s been exhaustively tested. Let me know how you get on, or if you have any questions.

(…didn’t realise you could attach files to these messages. I’ve attached my changes to this message in addition to the link above.)

Thanks,
g

xmlSettingsChanges.zip

Again, very nice. Thanks for the optimizations! I’m kinda new to this, and I didn’t really have the time to optimize my code anyways. I’m planning on switching to use this new version from now on.

Hello!
Just wanted to say that I added two functions to ofxXMLSettings, to get a Error String and to get where the error occured, if loading a file returns false. As TinyXML document contains these functionality already it was basically just a little wrapping.
Here they are:

  
  
string ofxXmlSettings::getErrorString(){  
	return doc.ErrorDesc();  
}  
  
int ofxXmlSettings::getLineOfError(){  
	return doc.ErrorRow();  
}  
  

Say you have a file like

  
  
<HELLO>  
    <WORLD1>  
        <FOO></FOO>  
        <BAR></BAR>  
    </WORLD1>  
    <WORLD2>  
        <FOO><FOO>  
        <BAR></BAR>  
    </WORLD2>  
    <WORLD3>  
        <FOO></FOO>  
        <BAR></BAR>  
    </WORLD3>  
</HELLO>  
  

the line function would return 9 (as the error occured somewhere in the WORLD2 tag) and the error message would be ‘Error reading end tag.’ The error line seems to give you a hint, in which parent tag the error happend, not the exact line.

Hopefully someone else thinks it’s useful,
Regards,
Gestalt

Hey,

thanks for adding support for attributes. I am using your version of the addon at the moment, but reading and writing gives problems. I could use some help, to be honest.

This is what my file looks like:

  
  
<videoscaler>  
  <settings>  
    <view movie="movieID">  
      <corner x="0.1" y="0.2"/>  
      <corner x="0.9" y="0.0"/>  
      <corner x="0.7" y="1.0"/>  
      <corner x="0.2" y="0.8"/>  
    </view>  
  </settings>  
</videoscaler>  
  

This is the code I use to read the corner tags:

  
  
if( XML.loadFile("settings.xml") ){  
  if( XML.pushTag("videoscaler:settings:view", 0) ){  
    double zero = 0.0;  
    double one = 1.0;  
    corners[0].x = (float) XML.getAttribute("corner", "x", zero, 0);  
    corners[0].y = (float) XML.getAttribute("corner", "y", zero, 0);  
    corners[1].x = (float) XML.getAttribute("corner", "x", one, 1);  
    corners[1].y = (float) XML.getAttribute("corner", "y", zero, 1);  
    corners[2].x = (float) XML.getAttribute("corner", "x", one, 2);  
    corners[2].y = (float) XML.getAttribute("corner", "y", one, 2);  
    corners[3].x = (float) XML.getAttribute("corner", "x", zero, 3);  
    corners[3].y = (float) XML.getAttribute("corner", "y", one, 3);  
      
    XML.popTag();  
    ofLog(OF_LOG_NOTICE, "Settings read successfully");  
  }  
}  
  

But the corners always reset to their default values, as if the file isn’t read at all. Same with writing to the file: using setAttribute() doesn’t seem to work. When I set the attributes and then call ‘XML.saveFile(“settings.xml”);’, the changes are not saved to file.

I would appreciate some help and insights. Thanks in advance.

Hmmm, that’s interesting. I’ll have to take a look at that more in-depth. I’m thinking it might be one of the following issues:

  1. You used float instead of double (it might not have cast correctly or something)
  2. There is a bug in the readAttribute() or getAttribute() functions
  3. Your XML file is misplaced, or your program is reading the wrong one.
  4. The XML file is not being saved properly, or for some odd reason has no attributes being created in each of the tags you expect them to be in. This might be it, because I think I wrote it initially where you have to explicitly create attributes in tag, ie. with addAttribute(), before they are made. Unless you’re trying to read a premade XML file with attributes already in it…

EDIT:
5: There might be an issue with using values (int, double, const string) instead of references (int&, double&, const string&) for either the parameters of readAttribute() or getAttribute() or for the values passed into them to begin with. It might be a place to start looking…

I’ve seen this before, would make sense to fix it…

What’s happening is that when you call XML.pushTag(“videoscaler:settings:view”, 0), it only pushes the first tag. Step in with your debugger and you’ll see.

To work around this, call pushTag for each element individually:

  
  
    if( xml.loadFile("test.xml") ){  
        if( xml.pushTag("videoscaler", 0) ){  
            if( xml.pushTag("settings", 0) ){  
                if( xml.pushTag("view", 0) ){  
                    double zero = 0.0;  
                    double one = 1.0;  
                    corners[0].x = (float) xml.getAttribute("corner", "x", zero, 0);  
                    corners[0].y = (float) xml.getAttribute("corner", "y", zero, 0);  
                    corners[1].x = (float) xml.getAttribute("corner", "x", one, 1);  
                    corners[1].y = (float) xml.getAttribute("corner", "y", zero, 1);  
                    corners[2].x = (float) xml.getAttribute("corner", "x", one, 2);  
                    corners[2].y = (float) xml.getAttribute("corner", "y", one, 2);  
                    corners[3].x = (float) xml.getAttribute("corner", "x", zero, 3);  
                    corners[3].y = (float) xml.getAttribute("corner", "y", one, 3);  
                      
                    xml.popTag();  
                    ofLog(OF_LOG_NOTICE, "Settings read successfully");  
                }  
                xml.popTag();  
            }  
            xml.popTag();  
        }  
    }  
  

This should probably be fixed.

Cheers,
g

Hi Macdonag,

yes, that indeed solved the problem. The pushTag() function can’t handle multiple levels, it seems. I can now both read from, and write to, the xml.

Seems like pushTag needs to be fixed :slight_smile:

Thanks, this seems considerably faster!

The memory leaks haven’t entirely disappeared, but they’re considerably smaller than before.

All the best,

Jeremy

Yeah, just ran my app through Intstruments and noticed there was one last rogue new that wasn’t being deleted. I didn’t see the point of dynamically allocating the storedHandle, so I made it a class member allocated on the stack instead.

If you see any other leaks (or other issues), let me know.

Thanks

ofxXmlSettings.zip

Hey, has anything been done with this? I was kind of hoping this would be adopted as the new standard, but it seems that people just forgot about it. Also, I just saw that they came out with an ofxJavascript addon; anyone up for making a HTML renderer in openFrameworks?

There are a few variations on this right now.

  • Theo’s original addon
  • This version
  • An older revision that adds attribute support
  • Damian Stewart just rewrote it to add attribute support

Clearly something like this is needed, so people don’t keep rewriting it… but I don’t know when that will happen. Maybe contact someone on the OF team directly and they’ll add it?

I’m actually using this reversion for a project right now, implementing an SVG addon that allows SVG importing.

SVG addon!
Sorry to hijack the thread, but is that SVG to OpenGL primitives, or does it use Cairo or something?

Hmm, I wrote that original version back in high school, during lunch break. Glad to see that my lovely commenting (a la “// Do stuff with the element here”) has improved a bit since then. It’s just funny to look back now and see this as one of the earliest useful pieces of code I’ve ever written.

By the way, I’m now almost done with a software engineering degree. I’ve got one more year to go, then I can finally get back to fiddling with openFrameworks in my spare time.

hi,can you help me ?