What are folks using under QNX 6 to parse and create XML docs? I’ve used Xerces under Linux and MS’s parsers under windows. I know there is libxml in the contrib repo but I’d prefer some small native QNX parser, C++ if possible.
Thanks
Hi,
I’ve used libxml and libexpat (c/c++) , libexpat is native and qnx is shipped with it, you can find the xml header files under /usr/include/.
Hope it helps
regards
Thanks!
So far looks like libxml2 off the russian community site has the xmlReader (the one on the pub cd is too old and does not have the xmlReader api).
A non-validating small (claims to be fast and efficient) library is irrXML. it is also free/open source. I’ve tested it briefly.
I found a sax and dom API in poco (again free/open source)
POCO contains a bunch of other stuff (portable C++ components).
It built quite easily - there is a QNX config file - just change the compiler version from 3.3.1 to 3.3.5.
I have not verified that their SAX api validates against XML schemas, which is what i need.
There is a commercial solution for embedded XML parsing that is supposed to be fast/efficient and costs about $5k or $10k I don’t recall which, with no runtime fees.
I’ll add anything else I find here.
Qnxlyzer, Ncostes,
We just want to do some simple XML parsing of configuration files/data at startup time. These files will be created offline on a Windows machine and since we control what’s in them I don’t plan on using anything as complex as a schema.
I’m not an XML guru so will the libxml/libexpat that’s shipped with 6.3 be sufficent for doing basic parsing of these files?
I’d be especially grateful for any C/C++ code snippets that show how to use libxml/libexpat as there is nothing in the helpviewer and the .h files aren’t the easiest thing to code from.
TIA,
Tim
you can find good sample codes from xmlsoft.org/examples/index.html
I would look at parsing and xmlreader sample code. But before you compile make sure the project is linked to the correct xml library such as libxml2, libz, libiconv.
It seems like you need a simple lightweight parser for your application,libxml (as the other posts mention) is a fully functional xml parser with all the niceties of xml programming. Libxml builds a DOM (document object model) tree from the XML (I believe the size of DOM in memory is 12 times the size of incoming XML), the DOM can be used access/modify the various attributes/data from the xml.
On the other hand, libexpat is small lightweight xml parser, and that is what it does, it does not build a DOM tree and cannot be used to create/modify xml documents, i personally found it very simple and easy to use. It is also shipped with qnx, which is good thing if you run into audits and issues like that. There are some examples on the web,
xml.com/pub/a/1999/09/expat/index.html
that illustrate the use of libexpat, and basically what you see in the example (4- 5 functions)is almost 90% of what you will be doing with libexpat.
All the best !
Xyz,
Your right about my needs, I don’t need the DOM and libexpat is all I do need (esp from the audit point of view).
I found this link yesterday when I looked up the expat parser in google.
Now maybe I am such a newbie when it comes to parsing XML, but I was hoping (expecting) that the examples at this link would have included a small XML file and also the C code that parsed it showing how to obtain all the values.
I understand what the code on page 2 does as far as reading line by line but I have no idea how one translates that simple example into reading actual XML files to obtain values. It looks like you have to manage the depths and everything else manually yourself to know how deep you’ve gone. That seems like it will be a lot of code which is why I was sure something would be nicely posted on the web that I could use as a starting point.
Tim
I found a PHP example of using expat and from that I was able to construct a very simple C++ program that I wanted to test. So I created the following simple XML file based on the PHP example I saw:
<Names>
<Name>
<First>John</First>
<Last>Doe</Last>
</Name>
<Name>
<First>Jane</First>
<Last>Doe</Last>
</Name>
</Names>
Then my simple C++ code is:
#include <stdio.h>
#include <stdlib.h>
#include <xmlparse.h>
using namespace std;
int state = 0;
string firstName;
string lastName;
void startElement(void *userData, const char *elementName, const char **attributes)
{
cout << "startElement called" << endl;
if (strcmp(elementName, "Names") == 0)
{
state = 1;
cout << "The following people are in the list:" << endl;
}
else if (strcmp(elementName, "Name") == 0)
{
state = 2;
totalNames++;
cout << totalNames << ")";
}
else if (strcmp(elementName, "First") == 0)
{
state = 3;
}
else if (strcmp(elementName, "Last") == 0)
{
state = 4;
}
}
void endElement(void *userData, const char *elementName)
{
cout << "endElement called" << endl;
if (strcmp(elementName, "/Name") == 0)
{
cout << lastName.c_str() << ", " << firstName.c_str() << endl;
}
}
void dataHandler(void *userData, const char *xmlData, int length)
{
char buffer[length+1];
memset(buffer, 0, sizeof(buffer));
memcpy(buffer, xmlData, length);
cout << "dataHandler called" << endl;
if (state == 3)
{
firstName = buffer;
}
else if (state == 4)
{
lastName = buffer;
}
}
int main( void )
{
FILE *fp = fopen("names.xml", "r");
XML_Parser p = XML_ParserCreate(NULL);
char buffer[80];
XML_SetElementHandler(p, startElement, endElement);
XML_SetCharacterDataHandler(p, dataHandler);
if (fp && p)
{
while (!feof(fp))
{
if (fgets(buffer, sizeof(buffer), fp) != NULL)
{
string s = buffer;
cout << "Parsing: " << buffer << endl;
if (!XML_Parse(p, buffer, s.length(), 1))
{
cout << "XML parse error at line " << XML_GetCurrentLineNumber(p) << endl;
cout << "Error is " << XML_ErrorString(XML_GetErrorCode(p)) << endl;
cout << buffer << endl;
exit(-1);
}
else
{
cout << "Parsed: " << buffer << endl;
}
}
}
}
fclose(fp);
XML_ParserFree(p);
return EXIT_SUCCESS;
}
But when I run I crap out right away on the first line with the following:
Parsing:
startElement called
The following people are in the list:
dataHandler called
XML parse error at line 2
Error is no element found
If I change line 1 to be foo then line 1 parses but line 2 fails. So why is the parser failing to recurse properly if the end tag isn’t on the same line as the start one?
TIA,
Tim
Hi Tim,
I believe you need to tell the parser when you are done with parsing, and 1 tells the parser its done. I have made the change in your code below and it works (compiled using g++ )
#include
#include
#include <stdio.h>
#include
#include
#include <xmlparse.h>
using namespace std;
int state =0;
string firstName;
string lastName;
int totalNames = 0;
void startElement(void *userData, const char *elementName, const char **attributes)
{
cout << “startElement called” << endl;
if (strcmp(elementName, “Names”) == 0)
{
state = 1;
cout << “The following people are in the list:” << endl;
}
else if (strcmp(elementName, “Name”) == 0)
{
state = 2;
totalNames++;
cout << totalNames << “)”;
}
else if (strcmp(elementName, “First”) == 0)
{
state = 3;
}
else if (strcmp(elementName, “Last”) == 0)
{
state = 4;
}
}
void endElement(void *userData, const char *elementName)
{
cout << “endElement called” << endl;
if (strcmp(elementName, “/Name”) == 0)
{
cout << lastName.c_str() << ", " << firstName.c_str() << endl;
}
}
void dataHandler(void *userData, const char *xmlData, int length)
{
char buffer[length+1];
memset(buffer, 0, sizeof(buffer));
memcpy(buffer, xmlData, length);
cout << “dataHandler called” << endl;
if (state == 3)
{
firstName = buffer;
}
else if (state == 4)
{
lastName = buffer;
}
}
int main( void )
{
FILE *fp = fopen(“names.xml”, “r”);
XML_Parser p = XML_ParserCreate(NULL);
char buffer[80];
XML_SetElementHandler(p, startElement, endElement);
XML_SetCharacterDataHandler(p, dataHandler);
if (fp && p)
{
while (!feof(fp))
{
if (fgets(buffer, sizeof(buffer), fp) != NULL)
{
string s = buffer;
cout << "Parsing: " << buffer << endl;
if (!XML_Parse(p, buffer, s.length(), 0))
{
cout << "XML parse error at line " << XML_GetCurrentLineNumber(p) << endl;
cout << "Error is " << XML_ErrorString(XML_GetErrorCode(p)) << endl;
cout << buffer << endl;
exit(-1);
}
else
{
cout << "Parsed: " << buffer << endl;
}
}
}
}
fclose(fp);
XML_ParserFree(p);
return EXIT_SUCCESS;
}
All the best
Qnxlyzer,
Thanks, it works fine now.
I wonder why you need to tell the parser you are done. Why can’t you just free it since you control everything else about it?
Tim
Tim,
You can stop/start the parser at any time during the parsing operation, also you can free the parser by xmlfreeparser call. I found this website useful in explaining the API.
Qnxlyzer,
Thanks, I already found that link. I am really only using the 3 functions I had in my C example since that does the parsing I need.
Unfortunately, the bigger issue for me now, is how to actually fold this into C++ land. Those C style callbacks are quite annoying to use because what I really want to do is call back into my classes to set internal variables. There’s just no way to pass class member functions as the callback functions for the parser so I’m going to end up with a lot of specialized convoluted code to actually use this parser (ie. create C callback functions, one set of 3 for every class that needs XML config files. Then create a global pointer for each class that I can assign a my current object to, then in the C callbacks use that global pointer to call member functions in the object. Plus wrap all that up with semaphores for the global pointers. Just yucky code all around).
Tim
Tim,
Thats getting complex, there are some c++ wrappers available for expat, did you check them out.
Qnxlyzer,
Yes, I did. Some of them aren’t very thread safe using static class variables
After looking at a couple of them, I wrote some small test programs to implement my own very simple wrappers just to get it working. I then ended up opening my Design Patterns & Meyers Effective C++ books and implemented the whole thing as a strategy pattern where the classes doing the final work of interpreting the tags are the algorithms part of the pattern. This nicely de-couples my very simple parser class from the rest of my code.
Tim