<html><head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta name="description" content="XML-Formatted Bakery Documents"> <meta name="keywords" content="Bakery, C++, Document/View, Document_XML, libxml++"> <title>Bakery: XML-based Documents</title><style type="text/css"></style></head> <body bgcolor="#ffffff"> <h1 align="center">XML-Formatted Bakery Documents</h1> <h2>Contents</h2> <ul> <li><a href="#Introduction">Introduction</a></li> <li><a href="#Document">Create the Document class</a></li> </ul> <h2><a name="Introduction"></a>Introduction</h2> <blockquote> <p>The <a href="bakery_document_view.html">Document/View With Bakery</a> page explains how to derive a Document class for your application. But Bakery::Document doesn't help you to organise or parse the data in the file. And f you achieve that by using a custom data format then other applications will not be able to easily use the same document. To solve this problem, the Bakery::Document_XML class helps you to use an XML format to store your data. This has the following advantages: <ul> <li>You don't need to write complex document-parsing-and-building code - just use the XML parser's API. This means less code and more readable code.</li> <li>Instead of checking the document's structure with complicated code, you can validate it with a DTD.</li> <li>Other applications can work with your document.</li> <li>The file is human-readable, so you can investigate problems in the file.</li> </ul> </p> </blockquote> <h2><a name="Document"></a>Create the Document class</h2> <blockquote> <p>Derive a Document class from Bakery::Document_XML. You don't need to override load_after() and save_after(), because Document_XML can do that for XML documents in general.</p> <p>e.g.</p> <blockquote> <pre> class DocExample : public Bakery::Document_XML { public: DocExample(); virtual ~DocExample(); void set_something(const std::string& strSomething); std::string get_something(); protected: xmlpp::Node* get_node_something(); //Gets <something> }; </pre> </blockquote> <p>As in the other examples, you should specify the file extension in the constructor. But you should also specify the name of the XML file's DTD, and the name of the top-level XML node. These will be used to create new empty Documents.</p> <blockquote> <pre> DocExample::DocExample() { set_file_extension("bakery_example_xml"); set_DTD_Name("example_xml_doc.dtd"); set_DTD_RootNodeName("example_xml_doc"); } </pre> </blockquote> <p>As in the other examples, when you implement methods like set_something(), which changes data in your document, you should call Document::set_modified(true).</p> <p>In this example there is also a get_node_something() convenience method, just to reduce code duplication. Notice that we use the libxml++ Node class from the xmlpp namespace.</p> <blockquote> <pre> void DocExample::set_something(const std::string& strSomething) { try { set_node_attribute_value(get_node_something(), "someval", strSomething); set_modified(); } catch(const std::exception& ex) { //HandleError(ex); } } std::string DocExample::get_something() { std::string strValue; try { strValue = get_node_attribute_value(get_node_something(), "someval"); } catch(const std::exception& ex) { //HandleError(ex); } return strValue; } xmlpp::Node* DocExample::get_node_something() { try { xmlpp::Node* nodeRoot = get_node_document(); return get_node_child_named_with_add(nodeRoot, "something"); } catch(const std::exception& ex) { //HandleError(ex); return 0; } } </pre> </blockquote> <p>You just need to use the libxml++ xmlpp::DomParser API, along with some convenience methods in Bakery::Document_XML, to navigate, read, and build your document. Bakery::Document_XML will take care of actually reading the XML into memory and writing it back to disk at the appropriate time.</p> </blockquote> </h2> <p align="center"><font size="1">Copyright © 2001, Murray Cumming. Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.</font></p> </body></html>