[libxml++] Document, Schema: Improve the error handling.
- From: Kjell Ahlstedt <kjellahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libxml++] Document, Schema: Improve the error handling.
- Date: Sun, 5 Aug 2012 14:23:50 +0000 (UTC)
commit f2767328abcb86fc0b0a4998676d9e4db72b2f1f
Author: Kjell Ahlstedt <kjell ahlstedt bredband net>
Date: Sun Aug 5 15:53:34 2012 +0200
Document, Schema: Improve the error handling.
* libxml++/document.[h|cc]:
* libxml++/schema.[h|cc]: Check more return codes from libxml2 functions.
Improve the description of errors in the reference documentation. Bug #635846.
ChangeLog | 8 ++++++
libxml++/document.cc | 65 ++++++++++++++++++++++++++++++++++++--------------
libxml++/document.h | 62 ++++++++++++++++++++++++++++++++++++----------
libxml++/schema.cc | 29 +++++++++++----------
libxml++/schema.h | 20 ++++++++++----
5 files changed, 132 insertions(+), 52 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 04e7ab7..5f3a5f0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2012-08-05 Kjell Ahlstedt <kjell ahlstedt bredband net>
+
+ Document, Schema: Improve the error handling.
+
+ * libxml++/document.[h|cc]:
+ * libxml++/schema.[h|cc]: Check more return codes from libxml2 functions.
+ Improve the description of errors in the reference documentation. Bug #635846.
+
2012-08-02 Kjell Ahlstedt <kjell ahlstedt bredband net>
Element, Node: Improve the error handling.
diff --git a/libxml++/document.cc b/libxml++/document.cc
index 06cf137..d07f07d 100644
--- a/libxml++/document.cc
+++ b/libxml++/document.cc
@@ -59,6 +59,8 @@ Document::Init Document::init_;
Document::Document(const Glib::ustring& version)
: impl_(xmlNewDoc((const xmlChar*)version.c_str()))
{
+ if (!impl_)
+ throw internal_error("Could not create Document.");
impl_->_private = this;
}
@@ -125,7 +127,16 @@ Element* Document::create_root_node(const Glib::ustring& name,
const Glib::ustring& ns_prefix)
{
xmlNode* node = xmlNewDocNode(impl_, 0, (const xmlChar*)name.c_str(), 0);
- xmlDocSetRootElement(impl_, node);
+ if (!node)
+ throw internal_error("Could not create root element node " + name);
+
+ node = xmlDocSetRootElement(impl_, node);
+ if (node)
+ {
+ // An old root element node has been replaced.
+ Node::free_wrappers(node);
+ xmlFreeNode(node);
+ }
Element* element = get_root_node();
@@ -141,28 +152,39 @@ Element* Document::create_root_node(const Glib::ustring& name,
Element* Document::create_root_node_by_import(const Node* node,
bool recursive)
{
+ if (!node)
+ return 0;
+
//Create the node, by copying:
xmlNode* imported_node = xmlDocCopyNode(const_cast<xmlNode*>(node->cobj()), impl_, recursive);
if (!imported_node)
{
- throw exception("Unable to import node");
+ throw exception("Unable to copy the node that shall be imported");
}
- xmlDocSetRootElement(impl_, imported_node);
+ xmlNode* old_node = xmlDocSetRootElement(impl_, imported_node);
+ if (old_node)
+ {
+ // An old root element node has been replaced.
+ Node::free_wrappers(old_node);
+ xmlFreeNode(old_node);
+ }
return get_root_node();
}
CommentNode* Document::add_comment(const Glib::ustring& content)
{
- xmlNode* node = xmlNewComment((const xmlChar*)content.c_str());
- if(!node)
+ xmlNode* child = xmlNewComment((const xmlChar*)content.c_str());
+
+ // Use the result, because child can be freed when merging text nodes:
+ xmlNode* node = xmlAddChild((xmlNode*)impl_, child);
+ if (!node)
{
- throw internal_error("Cannot create comment node");
+ if (child)
+ xmlFreeNode(child);
+ throw internal_error("Could not add comment node \"" + content + "\"");
}
-
- // Use the result, because node can be freed when merging text nodes:
- node = xmlAddChild( (xmlNode*)impl_, node);
Node::create_wrapper(node);
return static_cast<CommentNode*>(node->_private);
}
@@ -170,14 +192,16 @@ CommentNode* Document::add_comment(const Glib::ustring& content)
ProcessingInstructionNode* Document::add_processing_instruction(
const Glib::ustring& name, const Glib::ustring& content)
{
- xmlNode* node = xmlNewDocPI(impl_, (const xmlChar*)name.c_str(), (const xmlChar*)content.c_str());
- if(!node)
+ xmlNode* child = xmlNewDocPI(impl_, (const xmlChar*)name.c_str(), (const xmlChar*)content.c_str());
+ xmlNode* node = xmlAddChild((xmlNode*)impl_, child);
+ if (!node)
{
- throw internal_error("Cannot create processing instruction node");
+ if (child)
+ xmlFreeNode(child);
+ throw internal_error("Could not add processing instruction node " + name);
}
- node = xmlAddChild((xmlNode*)impl_, node);
Node::create_wrapper(node);
- return node ? static_cast<ProcessingInstructionNode*>(node->_private) : 0;
+ return static_cast<ProcessingInstructionNode*>(node->_private);
}
void Document::write_to_file(const Glib::ustring& filename, const Glib::ustring& encoding)
@@ -217,12 +241,13 @@ void Document::do_write_to_file(
{
KeepBlanks k(KeepBlanks::Default);
xmlIndentTreeOutput = format?1:0;
+ xmlResetLastError();
const int result = xmlSaveFormatFileEnc(filename.c_str(), impl_,
get_encoding_or_utf8(encoding), format?1:0);
if(result == -1)
{
- throw exception("do_write_to_file() failed.");
+ throw exception("do_write_to_file() failed.\n" + format_xml_error());
}
}
@@ -235,12 +260,13 @@ Glib::ustring Document::do_write_to_string(
xmlChar* buffer = 0;
int length = 0;
+ xmlResetLastError();
xmlDocDumpFormatMemoryEnc(impl_, &buffer, &length,
get_encoding_or_utf8(encoding), format?1:0);
if(!buffer)
{
- throw exception("do_write_to_string() failed.");
+ throw exception("do_write_to_string() failed.\n" + format_xml_error());
}
// Create a Glib::ustring copy of the buffer
@@ -260,12 +286,13 @@ void Document::do_write_to_stream(std::ostream& output, const Glib::ustring& enc
{
// TODO assert document encoding is UTF-8 if encoding is different than UTF-8
OStreamOutputBuffer buffer(output, encoding);
+ xmlResetLastError();
const int result = xmlSaveFormatFileTo(buffer.cobj(), impl_,
get_encoding_or_utf8(encoding), format ? 1 : 0);
if(result == -1)
{
- throw exception("do_write_to_stream() failed.");
+ throw exception("do_write_to_stream() failed.\n" + format_xml_error());
}
}
@@ -273,10 +300,12 @@ void Document::set_entity_declaration(const Glib::ustring& name, XmlEntityType t
const Glib::ustring& publicId, const Glib::ustring& systemId,
const Glib::ustring& content)
{
- xmlAddDocEntity( impl_, (const xmlChar*) name.c_str(), type,
+ xmlEntity* entity = xmlAddDocEntity( impl_, (const xmlChar*) name.c_str(), type,
publicId.empty() ? (const xmlChar*)0 : (const xmlChar*)publicId.c_str(),
systemId.empty() ? (const xmlChar*)0 : (const xmlChar*)systemId.c_str(),
(const xmlChar*) content.c_str() );
+ if (!entity)
+ throw internal_error("Could not add entity declaration " + name);
}
_xmlEntity* Document::get_entity(const Glib::ustring& name)
diff --git a/libxml++/document.h b/libxml++/document.h
index 5c2e50e..d68675c 100644
--- a/libxml++/document.h
+++ b/libxml++/document.h
@@ -58,8 +58,13 @@ class Document : NonCopyable
friend class DomParser;
friend class SaxParser;
+ friend class Schema;
public:
+ /** Create a new document.
+ * @param version XML version.
+ * @throws xmlpp::internal_error If memory allocation fails.
+ */
explicit Document(const Glib::ustring& version = "1.0");
protected:
@@ -69,11 +74,20 @@ public:
virtual ~Document();
/** @return The encoding used in the source from which the document has been loaded.
- */
+ */
Glib::ustring get_encoding() const;
+ /** Get the internal subset of this document.
+ * @returns A pointer to the DTD, or <tt>0</tt> if not found.
+ */
Dtd* get_internal_subset() const;
+ /** Create the internal subset of this document.
+ * If the document already has an internal subset, a new one is not created.
+ * @param name The DTD name.
+ * @param external_id The external (PUBLIC) ID, or an empty string.
+ * @param system_id The system ID, or an empty string.
+ */
void set_internal_subset(const Glib::ustring& name,
const Glib::ustring& external_id,
const Glib::ustring& system_id);
@@ -81,27 +95,36 @@ public:
//TODO: There should be a const and non-const version.
//See the patch here: https://bugzilla.gnome.org/show_bug.cgi?id=632522
/** Return the root node.
- * This function does _not_ create a default root node if it doesn't exist.
- * @return A pointer to the root node if it exists, 0 otherwise.
+ * This function does @b not create a default root node if it doesn't exist.
+ * @return A pointer to the root node if it exists, <tt>0</tt> otherwise.
*/
Element* get_root_node() const;
- /** Creates the root node.
+ /** Create the root element node.
+ * If the document already contains a root element node, it is replaced, and
+ * the old root element node and all its descendants are deleted.
* @param name The node's name.
- * @param ns_uri The namespace URI. A namespace declaration will be added to this node, because it could not have
- been declared before.
- * @param ns_prefix The namespace prefix to associate with the namespace. If no namespace prefix is specified then
- the namespace URI will be the default namespace.
- * @return A pointer to the new root node
+ * @param ns_uri The namespace URI. A namespace declaration will be added to
+ * this node, because it could not have been declared before.
+ * @param ns_prefix The namespace prefix to associate with the namespace.
+ * If no namespace prefix is specified then the namespace URI will be the default namespace.
+ * @return A pointer to the new root node.
+ * @throws xmlpp::internal_error If memory allocation fails.
+ * @throws xmlpp::exception If a new namespace node cannot be created.
*/
Element* create_root_node(const Glib::ustring& name,
const Glib::ustring& ns_uri = Glib::ustring(),
const Glib::ustring& ns_prefix = Glib::ustring() );
- /** Creates a root node by importing the node from another document, without affecting the source node.
- * @param node The node to copy and insert as the root node of the document
+ /** Create a root element node by importing the node from another document,
+ * without affecting the source node.
+ * If the document already contains a root element node, it is replaced, and
+ * the old root element node and all its descendants are deleted.
+ * @param node The node to copy and insert as the root node of the document.
+ * It must be an element node.
* @param recursive Whether to import the child nodes also. Defaults to true.
* @return A pointer to the new root node
+ * @throws xmlpp::exception If the node can't be copied.
*/
Element* create_root_node_by_import(const Node* node,
bool recursive = true);
@@ -109,6 +132,7 @@ public:
/** Append a new comment node.
* @param content The text. This should be unescaped - see ContentNode::set_content().
* @returns The new comment node.
+ * @throws xmlpp::internal_error
*/
CommentNode* add_comment(const Glib::ustring& content);
@@ -119,7 +143,7 @@ public:
* @param name The name of the application to which the instruction is directed.
* @param content The content of the instruction. This should be unescaped - see ContentNode::set_content().
* @returns The new processing instruction node.
- * @throws internal_error
+ * @throws xmlpp::internal_error
*/
ProcessingInstructionNode* add_processing_instruction(
const Glib::ustring& name, const Glib::ustring& content);
@@ -128,6 +152,7 @@ public:
/** Write the document to a file.
* @param filename
* @param encoding If not provided, UTF-8 is used
+ * @throws xmlpp::exception
*/
void write_to_file(const Glib::ustring& filename, const Glib::ustring& encoding = Glib::ustring());
@@ -136,11 +161,14 @@ public:
* but may insert unwanted significant whitespaces. Use with care !
* @param filename
* @param encoding If not provided, UTF-8 is used
+ * @throws xmlpp::exception
*/
void write_to_file_formatted(const Glib::ustring& filename, const Glib::ustring& encoding = Glib::ustring());
/** Write the document to the memory.
* @param encoding If not provided, UTF-8 is used
+ * @returns The written document.
+ * @throws xmlpp::exception
*/
Glib::ustring write_to_string(const Glib::ustring& encoding = Glib::ustring());
@@ -148,13 +176,16 @@ public:
* The output is formatted by inserting whitespaces, which is easier to read for a human,
* but may insert unwanted significant whitespaces. Use with care !
* @param encoding If not provided, UTF-8 is used
- * @return The written document.
+ * @returns The written document.
+ * @throws xmlpp::exception
*/
Glib::ustring write_to_string_formatted(const Glib::ustring& encoding = Glib::ustring());
/** Write the document to a std::ostream.
* @param output A reference to the stream in which the document will be written
* @param encoding If not provided, UTF-8 is used
+ * @throws xmlpp::exception
+ * @throws xmlpp::internal_error
* @warning This method is much less efficient than write_to_string if you want to dump the
* document to a buffer or the standard output. Writing to a fstream is almost as fast as write_to_file
*/
@@ -165,6 +196,8 @@ public:
* but may insert unwanted significant whitespaces. Use with care !
* @param output A reference to the stream in which the document will be written
* @param encoding If not provided, UTF-8 is used
+ * @throws xmlpp::exception
+ * @throws xmlpp::internal_error
* @warning See write_to_stream
*/
void write_to_stream_formatted(std::ostream & output, const Glib::ustring& encoding = Glib::ustring());
@@ -176,6 +209,7 @@ public:
* @param systemId The system ID of the subset.
* @param content The value of the Entity. In entity reference substitutions, this
* is the replacement value.
+ * @throws xmlpp::internal_error
*/
virtual void set_entity_declaration(const Glib::ustring& name, XmlEntityType type,
const Glib::ustring& publicId, const Glib::ustring& systemId,
@@ -191,7 +225,7 @@ protected:
/** Retrieve an Entity.
* The entity can be from an external subset or internally declared.
* @param name The name of the entity to get.
- * @returns A pointer to the libxml2 entity structure.
+ * @returns A pointer to the libxml2 entity structure, or <tt>0</tt> if not found.
*/
_xmlEntity* get_entity(const Glib::ustring& name);
diff --git a/libxml++/schema.cc b/libxml++/schema.cc
index 581bb55..17c7f78 100644
--- a/libxml++/schema.cc
+++ b/libxml++/schema.cc
@@ -36,18 +36,19 @@ void Schema::set_document(Document* document, bool embed)
{
release_underlying();
+ xmlResetLastError();
xmlSchemaParserCtxtPtr context = xmlSchemaNewDocParserCtxt( document->cobj() );
if(!context)
{
- throw parse_error("Schema could not be parsed");
+ throw parse_error("Schema could not be parsed.\n" + format_xml_error());
}
impl_ = xmlSchemaParse(context);
if(!impl_)
{
xmlSchemaFreeParserCtxt(context);
- throw parse_error("Schema could not be parsed");
+ throw parse_error("Schema could not be parsed.\n" + format_xml_error());
}
impl_->_private = this;
@@ -57,22 +58,22 @@ void Schema::set_document(Document* document, bool embed)
Glib::ustring Schema::get_name() const
{
- return (char*)impl_->name;
+ return impl_ ? (char*)impl_->name : "";
}
Glib::ustring Schema::get_target_namespace() const
{
- return (char*)impl_->targetNamespace;
+ return impl_ ? (char*)impl_->targetNamespace : "";
}
Glib::ustring Schema::get_version() const
{
- return (char*)impl_->version;
+ return impl_ ? (char*)impl_->version : "";
}
void Schema::release_underlying()
{
- if(embedded_doc_ && impl_ && impl_->doc->_private)
+ if(embedded_doc_ && impl_ && impl_->doc && impl_->doc->_private)
{
delete (Document*) impl_->doc->_private;
embedded_doc_ = false;
@@ -87,18 +88,18 @@ void Schema::release_underlying()
Document* Schema::get_document()
{
- if(impl_)
- return (Document*) impl_->doc->_private;
- else
+ if (!(impl_ && impl_->doc))
return 0;
+
+ if (!impl_->doc->_private) // Possible if *this was created with Schema(xmlSchema* schema).
+ new Document(impl_->doc); // Sets impl_->doc->_private
+
+ return (Document*) impl_->doc->_private;
}
-const Document* Schema::get_document()const
+const Document* Schema::get_document() const
{
- if(impl_)
- return (Document*) impl_->doc->_private;
- else
- return 0;
+ return const_cast<Schema*>(this)->get_document();
}
_xmlSchema* Schema::cobj()
diff --git a/libxml++/schema.h b/libxml++/schema.h
index 3f56059..52806e4 100644
--- a/libxml++/schema.h
+++ b/libxml++/schema.h
@@ -32,17 +32,21 @@ public:
*/
explicit Schema(_xmlSchema* schema);
- /** Create a schema from a XML document.
+ /** Create a schema from an XML document.
* @param document XMLSchema document, 0 to create an empty schema document.
* @param embed If true, the document will be deleted when
* the schema is deleted or another document is set.
+ * @throws xmlpp::parse_error
*/
explicit Schema(Document* document = 0, bool embed = false);
~Schema();
/** Set a new document to the schema.
+ * If the old schema document is owned by the schema (embed == true), the old
+ * schema document and all its nodes are deleted.
* @param document XMLSchema document, 0 to create an empty schema document.
* @param embed If true, the document will be deleted when the schema is deleted or another document is set.
+ * @throws xmlpp::parse_error
*/
virtual void set_document(Document* document = 0, bool embed = false);
@@ -50,8 +54,15 @@ public:
Glib::ustring get_target_namespace() const;
Glib::ustring get_version() const;
+ /** Get the schema document.
+ * @returns A pointer to the schema document, or <tt>0</tt> if none exists.
+ */
Document* get_document();
- const Document* get_document()const;
+
+ /** Get the schema document.
+ * @returns A pointer to the schema document, or <tt>0</tt> if none exists.
+ */
+ const Document* get_document() const;
/** Access the underlying libxml implementation. */
_xmlSchema* cobj();
@@ -65,13 +76,10 @@ protected:
private:
_xmlSchema* impl_;
- /** Is the base document is created with the schema. */
+ /** If the base document is created with the schema. */
bool embedded_doc_;
};
} // namespace xmlpp
#endif //__LIBXMLPP_SCHEMA_H
-
-
-
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]