Building an XML Parser Generator for Symbian (Part 4)
10 nov. 2004 - 18:29

Introduction

The previous set of articles described how an XML parser was ported to Symbian and turned into a set of classes that made dealing with parsing XML data substantially easier for the developer.

The other half of XML is the generation of the XML. The general approach is to use a large string(s) or to read these from a resource file. Both these approaches suffer from the limitation that they do not make the code easily legible.

Whilst generating XML is not hard and is, by and large pretty easily formed from text, there is much work that can be done to make it easier for the developer to generate, read and comprehend XML, especially when working with elements and namespaces

This is where the generator class comes in so that it makes the structure of the XML you are generating easier to understand and as such it can be easily understood and debugged as the code naturally maps to the XML format.

Below are the classes that comprise the generator classes are shipped with the SyExpat DLL and source code

Further documentation is included in the zip file which has the doxygen generated html files.

Classes

CSyGeneratorBase

This is the generator base class and is the class that all derived classes should be derived from. It provides the basic generation functionality that all derived classes should be able to use to generate pure XML.

It is expected that derived classes will inherit from this class and provide their own functionality. It is for this reason that the constructor and BaseConstructL functions are declared as protected so they cannot be explicitly constructed.

The primary role of this object is to generate xml in a clearer format than just strings or resources will allow.

This class generates all strings in unicode. It is up to you to povide your own transcoding functions to turn it into say an ASCII function and/or to write it out to a file.

CSyGenerator

This class provides a concrete implementation of the base class to provide a way to write the xml out. You need to provide an implementation of the MSyWrite::WriteL function in the mixin interface which is required allowing you to write the data to whatever you want in whatever format you need it in.

MSyWriter

This is the core handler for an XML item.

When ever an item needs to be written out the WriteL function is called. This will pass in a 16bit descriptor which then can be converted as needed to a format suitable for where it is being output to.

For example EscapeUtils::ConvertFromUnicodeToUtf8L can be used to convert the unicode descriptor to utf8/ascii suitable for passing as text to a web server or output to a readable file.

Samples

Currently I have included one sample that outputs the generated text to the console window.

Whilst this a bit of a simple sample, the actual structure of the XML is a lot more readable in this format than if it were kept in a big string or a resource string.

Downloads

There is an update version of the SyExpat library which has the generator already included in it.

The update to the library consists of making the mixin intefaces pure virtual and adding a method to attach the parser instance to the mixin interface if the user wants to save it.

SyExpat-2.zip
SyExpat-2.zip

Conclusion

This is the final part of the series to build an XML library for the Symbian platform. Developers can now generate XML and parse XML asynchronously from various sources on the device.

SyExpat is a free and open source XML library for Symbian, using Symbian standards and idioms.

Feel free to email me for more information or help

Tutorial posted novembre 10th, 2004 by paul

Soumis par PaulT (non vérifié) le ven, 2004-11-19 17:53.

A number of bugs were recently addressed as I think I might have put the wrong files on NewLC.

The latest version can always downloaded from toddsoftware.com

Paul


Soumis par Micky Menezes (non vérifié) le mer, 2004-12-01 13:48.

Hi, Please note ResumeParser form expat 1.95.8 is not available in the same.

so, I have added following in the SyExpat.cpp

EXPORT_C TSyExpatStatus CExpatParserBase::Resume()

return (TSyExpatStatus)XML_ResumeParser(REINTERPRET_CAST(XML_Parser,iParser));

Thanks and Regards, Micky


Soumis par Anonymous le jeu, 2005-12-22 09:35.

Hi Ashish,

Would it be possible for you to email me an example XML file showing the error?

Thanks

Paul (paul at toddsoftware.com)


Soumis par Twm Davies (non vérifié) le lun, 2006-01-16 22:02.

Good job on porting this expat. I've found it very useful However if the parser cannot be created due to OOM then it access violates when accessing iParser (it is null);

I added the lines in bold and it fixed the problem - a leave is generated to halt the operation on OOM.

void CExpatParserBase::BaseConstructL(const TDesC& aEncoding)

const TDesC& tmp = KSeperator;

const TChar c = tmp[0];

iParser = XML_ParserCreateNS( RECAST_TO_XML_CHAR(aEncoding.Ptr()), c);

if(!iParser)

User::Leave(KErrNoMemory);

TExpatDocumentHandlers* docHandlers = new (ELeave)

TExpatDocumentHandlers;

docHandlers->iDeclHandler = NULL;

docHandlers->iDocHandler = NULL;


Soumis par Max (non vérifié) le sam, 2006-04-01 11:29.

Hi,

did anyone manage to build for Symbian 9.1 or is there any public available download of the precompiled dll?

Regards Max


Soumis par Dario Consoli (non vérifié) le sam, 2006-04-22 12:03.

Hi Paul. I have the same problem like Ashish. If you try to parse a XML document with a default namespace (I mean xmlns="some:namespace:etc"), the parser goes in KERN-EXEC 3. It works if you specify the prefix (I mean xmlns:ns1="some:namespace:etc"). Hope you can give us some advice. Thank you

Soumis par swapna.saroja (non vérifié) le lun, 2006-08-07 12:57.

Hi Paul, I have the same problem like Ashish. If i try to parse a XML document with a default namespace for eg: xmlns="some:namespace:etc", the parser goes in KERN-EXEC 3. It works if you specify the prefix for eg: xmlnsQ = "urn:dvb:ipdc:esgbs:2005"). Hope you can help me on this.

Thank you


Soumis par Twm Davies (non vérifié) le ven, 2006-08-11 17:58.

I found a problem with writing attribute values. The writer only encodes entities for character content and not attribute values. This often leads to invalid XML output when < & and other characters are present in text being stores as an attribute. I've patched Sygen.cpp so that it generates valid XML and also made it deal with line feeds and tabs in attributes, which also need to be encoded as entities. Some silly XML file formats store line feeds within attributes, which is not elegent but is valid XML.

I have the patch to contribute back to this useful project. Who do I send it to?


Soumis par Ashish Chopra (non vérifié) le jeu, 2005-12-22 09:21.

hi Paul

I must say that you've done a commendable job in providing the C++ wrapper over Expat so that the integration in Symbian is made easier.

There is a small issue, though. I was trying to use SyExpat code from www.toddsoftware.com. I kept encountering a ‘Access Violation in EUSER.DLL' error whenever i tried to parse a certain XML document.

After a long debugging session, it turned out that in file "./lib/xmlparse.c" line no 2970, a call is made to the C++ wrapper as

if (attId && startNamespaceDeclHandler) startNamespaceDeclHandler(handlerArg, prefix->name, prefix->binding ? uri : 0);

the function called, in file "./Symbian/SyExpat.cpp" line no. 227, is

static void StartNamespaceHandler(void *userData, const XML_Char *aPrefix, const XML_Char *aURI)

if a default namespace is mentioned in XML document under the format xmlns="urn:namspace", then the code crashes with the access violation error mentioned above. This happens due to the fact that the "aPrefix" parameter in the function call is returned to be NULL in this case, resulting in access of a NULL pointer when "aPrefix" is tried to recast in next line:

const TPtrC prefix(RECAST_FROM_XML_CHAR(aPrefix))

In conclusion, it seems that although default namespace handling exists in code of Expat, the same is not ported correctly over C++ wrapper classes.

Can you please suggest what sort of changes should be made in the C++ code, so that this error is handled. I'm using Symbian SDK 8.0a.

hope to hear from you soon

thanks

Ashish


Soumis par Ashish Chopra (non vérifié) le jeu, 2005-12-22 10:26.

hi Paul

I must say that you've done a commendable job in providing the C++ wrapper over Expat so that the integration in Symbian is made easier.

There is a small issue, though. I was trying to use SyExpat code from www.toddsoftware.com. I kept encountering a ‘Access Violation in EUSER.DLL' error whenever i tried to parse a certain XML document.

After a long debugging session, it turned out that in file "./lib/xmlparse.c" line no 2970, a call is made to the C++ wrapper as

if (attId && startNamespaceDeclHandler) startNamespaceDeclHandler(handlerArg, prefix->name, prefix->binding ? uri : 0);

the function called, in file "./Symbian/SyExpat.cpp" line no. 227, is

static void StartNamespaceHandler(void *userData, const XML_Char *aPrefix, const XML_Char *aURI)

if a default namespace is mentioned in XML document under the format xmlns="urn:namspace", then the code crashes with the access violation error mentioned above. This happens due to the fact that the "aPrefix" parameter in the function call is returned to be NULL in this case, resulting in access of a NULL pointer when "aPrefix" is tried to recast in next line: const TPtr prefix(RECAST_FROM_XML_CHAR(aPrefix))

In conclusion, it seems that although default namespace handling exists in code of Expat, the same is not ported correctly over C++ wrapper classes.

Can you please suggest what sort of changes should be made in the C++ code, so that this error is handled. I'm using Symbian SDK 8.0a.

hope to hear from you soon

thanks

Ashish


Soumis par Anonymous le mar, 2006-06-27 13:37.

Hi Paul i am trying to use SyExpat. But it crashing inside function XML_Parse defined in xmlparse.c it is crashing on this line errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr); with panic code KERN-EXEC 3

I am using ParseFile example supplied along with SyExpat.

can any body please help me in making parser run.

Regards,

Saurabh


Soumis par Andrew Chung (non vérifié) le jeu, 2007-02-08 02:15.

I dug through this and even the latest SyExpat from toddsoftware.com has the same defualt namespace issue. I have fixed this by making a few slight changes to code in SyExpat.cpp. Three functions have been modified and their new forms are included here. Changes from the original are in bold.

I've also put this up as a page on my web site so that copy/paste of the code is easier. Pardon the horrible page. I'm just throwing the information up.

static void StartNamespaceHandler(void *userData, const XML_Char *aPrefix, const XML_Char *aURI) TPtrC prefix; if (aPrefix != NULL) prefix.Set(TPtrC(RECAST_FROM_XML_CHAR(aPrefix))); const TPtrC uri(RECAST_FROM_XML_CHAR(aURI)); MSyDeclHandler* handler = RECAST_TO_DECL_HANDLER(userData); if (handler != NULL) handler->StartNamespace(prefix, uri);

static void EndNamespaceHandler(void *userData, const XML_Char* aPrefix) TPtrC prefix; if (aPrefix != NULL) prefix.Set(TPtrC(RECAST_FROM_XML_CHAR(aPrefix)));

MSyDeclHandler* handler = RECAST_TO_DECL_HANDLER(userData); if (handler != NULL) handler->EndNamespace(prefix);

static void SplitElementName(const TText* aName, TQualified& aItem) TPtrC tmp(aName); //URI + sep + local_name + sep + prefix. const TInt EndURI = tmp.Find(KSeperator); if (EndURI != KErrNotFound) aItem.iURI.Set(tmp.Ptr(), EndURI); tmp.Set(aName + EndURI + KSeperator.BufferSize); const TInt EndLocalName = tmp.Find(KSeperator); if (EndLocalName != KErrNotFound) aItem.iLocalName.Set(tmp.Ptr(), EndLocalName); tmp.Set(tmp.Ptr() + EndLocalName + KSeperator.BufferSize); aItem.iPrefix.Set(tmp); else aItem.iLocalName.Set(tmp); // We couldn't find the seperator for the prefix // we will assume this is the default prefix of '' else ; // as there is no namespace information we assume we only have a local name so do nothing aItem.iLocalName.Set(tmp);

The changes in the start and end namespace handler fix the issue of the KERN-EXEC 3 or NULL pointer error. The fix in the SplitElement fixes an issue where the local name returned in the StartElement handler is incorrect. The splitelement function is looking for a string in the form of: [URI]\n[LocalName]\n[Prefix]. If there is no prefix the check for the second \n fails. In this case we really want to save the correct LocaName, which happens to be the rest of the string.


Soumis par venki_kv le jeu, 2008-05-22 07:47.

Hai Paul
I have been trying to use SyExpat Lib on Symbian V9.2. But i am unable to compile it. Any idea why its not generating the DLL?
Here is my error console output

mwldsym2.exe: Undefined symbol: '__declspec(dllimport) _XML_ParserFree (__imp__XML_ParserFree)'
mwldsym2.exe: referenced from 'CExpatParserBase::~CExpatParserBase(void) (??1CExpatParserBase@@UAE@XZ)' in SyExpat.cpp:304
mwldsym2.exe: Note: symbol '_XML_ParserFree' found in 'xmlparse.o';
mwldsym2.exe: your project may need the DLL import library instead of a static library

Thanks in advance,


Soumis par Varsha4u le lun, 2008-07-07 13:21.

Hi Paul,

I have been trying to use the SyExpat.zip available from your previous post, but when I build the project it gives me numerous errors similar to what venki_kv have been receiving. I'm using the SyExpat.zip with UIQ3.3 which is based off Symbian OS v9.3 with Carbide v1.3.

Please let me know if I need to do any modifications.

Thanks in Advance,
Varsha.



copyright 2003-2009 NewLC SARL