a new library for traversing odf files and a new export filter

Inge Wallin inge at lysator.liu.se
Mon Mar 25 18:12:43 GMT 2013


On Monday, March 25, 2013 17:54:53 matus.uzak at gmail.com wrote:
> Hi,
> 
> sorry for not discussing earlier, but I did not have much free time last
> two weeks.
> 
> I think we should continue the parser type discussion in order to also
> improve state of things in libmsooxml.  What we have there is a PULL
> parser. And I identified the following problems (Would be cool is Lassi
> could check those):
> 
> 1. OOXML sometimes requires us to run the parser twice at one element in
> order to first collect selected information required to convert the content
> of child elements.
> 
> 2. There are situations when conversion of the 1st child of the root
> element requires information from the last child of the root element.

It would be interesting to see some examples of these two issues.

> 3. Interpretation of OOXML elements differs based on the namespace and that
> happens in scope of one single filter implementation (The namespace is not
> only limited to WordprocessingML, DrawingML and VML - that would be the
> docx filter for example).  That forces us to maintain a context in order to
> interpret attribute values properly.  There also might be totally different
> child elements.  It's good that namespace is always checked, because that
> avoids creation of invalid ODF, but it also ignores an element in an
> unexpected namespace.

That foo:xxx and bar:xxx are different tags is not a property of OOXML only. 
It's a property of any XML tree that uses namespaces. So yes, we need to check 
the namespace for all tags.

> 4. Variations of 1, 2 and 3.
> 
> It sounds like we need to adopt attributes of a SAX parser in order to
> solve point 3.  And the code becomes a bit fluffy when we try to solve 1, 2
> and 4, which is not an attribute of a PULL parser.

I don't see why this follows. As long as we make sure that we parse the 
tagnames including namespace correctly it shouldn't make any difference for the 
correctness alone which method (SAX, PULL, DOM) that we use to traverse the 
XML tree.

> We will also need to fight with this when doing the ODF->OOXML conversion.
>  As Inge wrote, the current plan is to export text and simple formatting
> into DOCX.  But I'm afraid we will hit one of the problems soon.
> 
> I have also read comments from Jos about using XSLT to do the conversion.
>  Do you think it would be easier to solve points 1,2,3 and 4 that way?
>  When I imagine the code in XSLT using XPath, it could be Ok.  But not that
> Ok in means of performance.

I am against using XSLT for this for several reasons:

1. It leads to unreadable code.  There are some famous XSLT filters that even 
those who wrote them fear to fix bugs in. 

2. As far as I know, it's a one-stop solution. I don't think you can mix XSLT 
and other types of data conversion.  And since both ODT and especially OOXML 
spread the data into many different subfiles it doesn't fit very well. 

3. As Jos wrote (I think in the review request),XSLT has difficulties with some 
constructs, especially those that you solve by sending in a context.

To show some of the big picture of what I'm trying to do:

I want to create a so called recursive descent parser for ODF. This type of 
parser has one funciton per non-terminal in the grammar and normally uses 1 
token look-ahead. In the XML case we can simulate this by using an XML parser 
as the tokenizer and analyze the XML tree. The parser functions call each 
other recursively as the input is parsed. In the epub and html filter in 
filters/words/epub/ you can see this applied to ODT and with HTML as output.

But the odfparser library takes this one step further: Instead of using the 
parser functions themselves to generate the output it allows a "backend" to be 
plugged into it, where the actuall output is generated. This allows us to use 
the same ODF parser for all export filters. Some filters with very simple output 
can even ignore most of the input by not implementing the corresponding 
backend functions. A good example of this can be seen in the ascii (actually 
text) export filter in filters/words/ascii.

Now, there have been discussions of how to parse the XML of ODF to implement 
the tokenizer to this recursive descent parser. Jos suggested that the DOM 
approach taken by the KoXmlReader is not very efficient in a case like this, and 
he is right. It would be more efficient to use QXmlStreamReader which uses a 
PULL approach. It might even be even more efficient to use SAX, but my 
experience is that that would lead to more difficult to read code. 

It has also been suggested that the parser should be autogenerated from the 
RelaxNg schema and that too is right. But that's a big project which could 
perhaps be a good GSoC project.

In any case, I don't see that it would change the API to the backend, which is 
where the actual file conversion will take place. So whether we will use PULL 
or SAX in the long term or whether we will stick with the KoXml DOM approach 
out of laziness, the actual filter in the backend can still be written without 
concern.

And I suspect that it's also correct that some constructs need to be parsed 
twice: once to collect information and once when the output is generated.  
This can also be seen in the EPUB export filter since EPUB contains several 
HTML files in a ZIP container and before the odt is parsed once it's not clear 
which of these HTMLfiles that internal links should point to. This can be done 
by using two different backends in the two passes.

	-Inge

> br,
> 
> Matus Uzak



More information about the calligra-devel mailing list