Well, that might depend on how you do it. Using DOM is quite easy, although it might be a bit tedious if you have to traverse the whole DOM tree to create your application specific data structure (and of course it’s slow). Using SAX is faster, but programming all those handlers can be just as tedious. In any case you’ll likely have a lot of code which looks like this:

if (tagname == “SCRIBUSXML”) {
   doc = new ScribusDoc();
}
else if (tagname == “PAGE”) {
   doc.addPage(new Page());
}
else if (tagname == “STYLE”) {
   …

Not nice at all. Of course Java developers will smirk now and say “that’s no problem for us; we can use Jakarta Commons Digester.” The curious C++ programmer might check out their webpage or the introductory article on JavaWorld and get envious. Really envious.

An example program with Digester might look like this:

Digester digester = new Digester();
digester.setValidating( false );

digester.addObjectCreate(“SCRIBUSXML”, ScribusDoc.class);

digester.addObjectCreate(“STYLE”, ParagraphStyle.class);
digester.addSetNext(“STYLE”, “addStyle”);

digester.addObjectCreate(“PAGE”, Page.class);
digester.addSetNext(“PAGE”, “addPage”);
digester.addSetProperties(“PAGE”, “NUM”, “number”);

ScribusDoc result =
   (ScribusDoc) digester.parse( “example.sla” );

So instead of programming all those tedious if-cases, you just add rules which tell
Digester what element tags and attribute names to look for and what to do if found: create new objects, call setter methods, or do some other stuff. Then you call the parse method and at the correct times the digester uses your rules to create your datastructure. At the end you just query the root object and there you go.

Unfortunately, my current pet projects are hooked on C++, so I tried to achieve a similar solution with C++ templates. This is what I came up with:

Digester digester = new Digester();

digester.addRule(“SCRIBUSXML”, Factory<ScribusDoc>());

digester.addRule(“STYLE”, Factory<ParagraphStyle>());
digester.addRule(“STYLE”, Setter( & ScribusDoc::addStyle ));

digester.addRule(“PAGE”, Factory<Page>());
digester.addRule(“PAGE”, Setter( & ScribusDoc::addPage ));
digester.addRule(“PAGE”,
    SetAttribute( & Page::setNumber, “NUM” ));

digester.parse(“example.sla”);
ScribusDoc result = digester.result<ScribusDoc>();

Do you like it? Me too. 🙂
The initial version of the library is available in current CVS in the “desaxe” directory. I’ll add some documentation and examples soon.

Some internals:
The deSAXe library uses a SAX parser which reads the XML document and creates events each time a start tag, end tag or a string of characters is read.
Setter/Factory/SetAttribute are examples of Actions. When a rule fires, the SAX events are forwarded to the corresponding Action. If more than one rule fires, all Actions reveive the events in the order they were added to the digester. Internally deSAXe uses a finite automaton to keep track on which rules are active, so it’s pretty fast (unlike Jakarta Commons Digester 🙂 ).

Looking forward to your comments (please use the mailing list since atm comments are disabled here).

/Andreas

P.S. Yes, I do enjoy parsing XML, now! 🙂
P.P.S. Apart from the pun on SAX the library is named after the coolest Scribus user in Australia, Elaine de Saxe. 🙂 Hi Elaine!