[ fromfile: xml-dom.xml id: xmlgeneration ]
DOM documents are normally created by parsers to represent XML from an input stream, but DOM can also generate XML structures as output. It is preferable to generate XML through an API rather than by printing formatted strings because DOM generation guarantees that the resulting document will be parsable again.
In Figure 15.6, DocbookDoc
is a factory for QDomElement
s.
It is derived from QDomDocument and specialized for creating Docbook/XML documents.
In the header file for this class, excerpted in Example 15.11, we added a typedef
to improve readability.
In the DOM standard, all DOM classes have simple names; for example Node
, Element
, Document
, and Attribute
.
Example 15.11. src/libs/docbook/docbookdoc.h
As shown in Example 15.12, you can build documents by creating chapters, sections, and paragraphs.
Example 15.12. src/xml/dombuilder/zenflesh.cpp
#include <QTextStream> #include <docbookdoc.h> class ZenFlesh : public DocbookDoc { public: ZenFlesh(); }; ZenFlesh::ZenFlesh() : DocbookDoc("Zen Flesh, Zen Bones") { chapter("101 Zen Stories"); section("A cup of tea"); para("Nan-in served a cup of tea."); section("Great Waves"); QDomElement p = para("o-nami the wrestler sat in meditation and " "tried to imagine himself as a bunch of great waves."); setRole(p, "remark"); chapter("The Gateless Gate"); formalpara("The Gateless Gate", "In order to enter the gateless gate, you must have a "); bold(" mindless mind."); section("Joshu's dog"); para("Has a dog buddha nature or not?"); section("Haykujo's Fox"); QDomElement fp = formalpara("This is a special topic", "Which should have a role= remark attribute"); setRole(fp, "remark"); } int main() { QTextStream cout(stdout); ZenFlesh book; cout << book << endl; }
<include src="src/xml/dombuilder/zenflesh.cpp" href="src/xml/dombuilder/zenflesh.cpp" id="zenfleshcpp" allfiles="1" mode="cpp"/>
The constructor generates a little book in XML which, after pretty-printing, could look like Example 15.13.
Example 15.13. src/xml/zen.xml
<book> <title>Zen Flesh, Zen Bones</title> <chapter> <title>101 Zen Stories</title> <section> <title>A cup of tea</title> <para>Nan-in served a cup of tea.</para> </section> <section> <title>Great Waves</title> <para> o-nami the wrestler sat in meditation and tried to imagine himself as a bunch of great waves. </para> </section> </chapter> <chapter> <title>The Gateless Gate</title> <formalpara> <title>The Gateless Gate</title> In order to enter the gateless gate, you must have a <emphasis role="strong"> mindless mind</emphasis> </formalpara> <section> <title>Joshu's dog</title> <para>Has a dog buddha nature or not?</para> </section> <section> <title>Haykujo's Fox</title> <formalpara role="remark"> <title>This is a special topic</title> Which should have a role="remark" attribute </formalpara> </section> </chapter> </book>
<include src="src/xml/zen.xml" href="src/xml/zen.xml" id="zenxml" mode="txt"/>
The advantage of this format is that it can be easily converted into HTML (or PDF, or LaTEX) using xsltproc
and the Docbook/XSL stylesheets [docbookxsl].
Example 15.14 shows the invocation for generating
an HTML version.
Example 15.14. src/xml/zen2html
#!/bin/sh # Translates zen.xml into index.html. # Requires gnu xsltproc and docbook-xsl. # DOCBOOK=/usr/share/docbook-xsl xsltproc $DOCBOOK/html/onechunk.xsl zen.xml
<include src="src/xml/zen2html" href="src/xml/zen2html" id="zen2html" mode="txt"/>
Now look at Example 15.15, where the elements are created.
Each major Docbook language element has a corresponding Factory method in DocbookDoc
.
Example 15.15. src/libs/docbook/docbookdoc.cpp
[ . . . . ] Element DocbookDoc::bridgehead(QString titleStr) { Element retval = createElement("bridgehead"); Element titleEl = title(titleStr); currentParent.appendChild(retval); return retval; } Element DocbookDoc::title(QString name, Element parent) { Element retval = createElement("title"); QDomText tn = createTextNode(name); retval.appendChild(tn); if (parent != Element()) parent.appendChild(retval); return retval; } Element DocbookDoc::chapter(QString titleString) { Element chapter = createElement("chapter"); title(titleString, chapter); documentElement().appendChild(chapter); currentParent = chapter; currentChapter = chapter; return chapter; } Element DocbookDoc::para(QString textstr) { QDomText tn = createTextNode(textstr); Element para = createElement("para"); para.appendChild(tn); currentParent.appendChild(para); currentPara = para; return para; }
<include src="src/libs/docbook/docbookdoc.cpp" mode="cpp" href="src/libs/docbook/docbookdoc.cpp" id="docbookdoccpp" segid="elements"/>
In addition, there are some character-level elements that only modify text, as shown in Example 15.16.
Example 15.16. src/libs/docbook/docbookdoc.cpp
[ . . . . ] Element DocbookDoc::bold(QString text) { QDomText tn = createTextNode(text); Element emphasis = createElement("emphasis"); setRole(emphasis, "strong"); emphasis.appendChild(tn); currentPara.appendChild(emphasis); return emphasis; } void DocbookDoc::setRole(Element el, QString role) { el.setAttribute("role", role); }
<include src="src/libs/docbook/docbookdoc.cpp" mode="cpp" href="src/libs/docbook/docbookdoc.cpp" id="docbookdoccpptext" segid="text"/>
Because each QDomNode must be created by QDomDocument, it makes sense to extend QDomDocument to write our own DOM factory.
Depending on what kind of element is being created, DocbookDoc
adds newly created elements as children to previously created elements.
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |