[libxml++] Element, Node: Improve the error handling.
- From: Kjell Ahlstedt <kjellahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libxml++] Element, Node: Improve the error handling.
- Date: Thu, 2 Aug 2012 16:54:47 +0000 (UTC)
commit a0483871fb13a5543c4e54f7d7ec25cc133ac32e
Author: Kjell Ahlstedt <kjell ahlstedt bredband net>
Date: Thu Aug 2 18:38:42 2012 +0200
Element, Node: Improve the error handling.
* libxml++/nodes/element.[h|cc]:
* libxml++/nodes/node.[h|cc]: Check more return codes from libxml2 functions.
Improve the description of errors in the reference documentation. Bug #635846.
ChangeLog | 8 +++
libxml++/nodes/element.cc | 111 +++++++++++++++++++++++++++++++--------------
libxml++/nodes/element.h | 18 ++++++-
libxml++/nodes/node.cc | 50 ++++++++++++--------
libxml++/nodes/node.h | 63 ++++++++++++++++++-------
5 files changed, 174 insertions(+), 76 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index f3a0d09..04e7ab7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2012-08-02 Kjell Ahlstedt <kjell ahlstedt bredband net>
+
+ Element, Node: Improve the error handling.
+
+ * libxml++/nodes/element.[h|cc]:
+ * libxml++/nodes/node.[h|cc]: Check more return codes from libxml2 functions.
+ Improve the description of errors in the reference documentation. Bug #635846.
+
2.35.3:
2012-06-19 Kjell Ahlstedt <kjell ahlstedt bredband net>
diff --git a/libxml++/nodes/element.cc b/libxml++/nodes/element.cc
index 2e3f786..0fac9fb 100644
--- a/libxml++/nodes/element.cc
+++ b/libxml++/nodes/element.cc
@@ -157,13 +157,18 @@ TextNode* Element::add_child_text(const Glib::ustring& content)
{
if(cobj()->type == XML_ELEMENT_NODE)
{
- xmlNode* node = xmlNewText((const xmlChar*)content.c_str());
+ xmlNode* child = xmlNewText((const xmlChar*)content.c_str());
- // Use the result, because node can be freed when merging text nodes:
- node = xmlAddChild(cobj(), node);
-
- Node::create_wrapper(node);
- return static_cast<TextNode*>(node->_private);
+ // Use the result, because child can be freed when merging text nodes:
+ xmlNode* node = xmlAddChild(cobj(), child);
+ if (!node)
+ {
+ if (child)
+ xmlFreeNode(child);
+ throw internal_error("Could not add text node \"" + content + "\"");
+ }
+ Node::create_wrapper(node);
+ return static_cast<TextNode*>(node->_private);
}
return 0;
}
@@ -175,13 +180,18 @@ TextNode* Element::add_child_text(xmlpp::Node* previous_sibling, const Glib::ust
if(cobj()->type == XML_ELEMENT_NODE)
{
- xmlNode* node = xmlNewText((const xmlChar*)content.c_str());
+ xmlNode* child = xmlNewText((const xmlChar*)content.c_str());
- // Use the result, because node can be freed when merging text nodes:
- node = xmlAddNextSibling(previous_sibling->cobj(), node);
-
- Node::create_wrapper(node);
- return static_cast<TextNode*>(node->_private);
+ // Use the result, because child can be freed when merging text nodes:
+ xmlNode* node = xmlAddNextSibling(previous_sibling->cobj(), child);
+ if (!node)
+ {
+ if (child)
+ xmlFreeNode(child);
+ throw internal_error("Could not add text node \"" + content + "\"");
+ }
+ Node::create_wrapper(node);
+ return static_cast<TextNode*>(node->_private);
}
return 0;
}
@@ -193,13 +203,18 @@ TextNode* Element::add_child_text_before(xmlpp::Node* next_sibling, const Glib::
if(cobj()->type == XML_ELEMENT_NODE)
{
- xmlNode* node = xmlNewText((const xmlChar*)content.c_str());
-
- // Use the result, because node can be freed when merging text nodes:
- node = xmlAddPrevSibling(next_sibling->cobj(), node);
+ xmlNode* child = xmlNewText((const xmlChar*)content.c_str());
- Node::create_wrapper(node);
- return static_cast<TextNode*>(node->_private);
+ // Use the result, because child can be freed when merging text nodes:
+ xmlNode* node = xmlAddPrevSibling(next_sibling->cobj(), child);
+ if (!node)
+ {
+ if (child)
+ xmlFreeNode(child);
+ throw internal_error("Could not add text node \"" + content + "\"");
+ }
+ Node::create_wrapper(node);
+ return static_cast<TextNode*>(node->_private);
}
return 0;
}
@@ -212,9 +227,12 @@ bool Element::has_child_text() const
void Element::set_namespace_declaration(const Glib::ustring& ns_uri, const Glib::ustring& ns_prefix)
{
//Create a new namespace declaration for this element:
- xmlNewNs(cobj(), (const xmlChar*)(ns_uri.empty() ? 0 : ns_uri.c_str()),
- (const xmlChar*)(ns_prefix.empty() ? 0 : ns_prefix.c_str()) );
- //We ignore the returned xmlNs*. Hopefully this is owned by the node. murrayc.
+ xmlNs* ns = xmlNewNs(cobj(), (const xmlChar*)(ns_uri.empty() ? 0 : ns_uri.c_str()),
+ (const xmlChar*)(ns_prefix.empty() ? 0 : ns_prefix.c_str()) );
+ if (!ns)
+ throw exception("Could not add namespace declaration with URI=" + ns_uri +
+ ", prefix=" + ns_prefix);
+ //We ignore the returned xmlNs*. It's owned by the XML_ELEMENT_NODE.
}
Glib::ustring Element::get_namespace_uri_for_prefix(const Glib::ustring& ns_prefix) const
@@ -236,10 +254,16 @@ Glib::ustring Element::get_namespace_uri_for_prefix(const Glib::ustring& ns_pref
CommentNode* Element::add_child_comment(const Glib::ustring& content)
{
- xmlNode* node = xmlNewComment((const xmlChar*)content.c_str());
+ xmlNode* child = xmlNewComment((const xmlChar*)content.c_str());
- // Use the result, because node can be freed when merging text nodes:
- node = xmlAddChild(cobj(), node);
+ // Use the result, because child can be freed when merging text nodes:
+ xmlNode* node = xmlAddChild(cobj(), child);
+ if (!node)
+ {
+ if (child)
+ xmlFreeNode(child);
+ throw internal_error("Could not add comment node \"" + content + "\"");
+ }
Node::create_wrapper(node);
return static_cast<CommentNode*>(node->_private);
}
@@ -247,8 +271,14 @@ CommentNode* Element::add_child_comment(const Glib::ustring& content)
CdataNode* Element::add_child_cdata(const Glib::ustring& content)
{
- xmlNode* node = xmlNewCDataBlock(cobj()->doc, (const xmlChar*)content.c_str(), content.bytes());
- node = xmlAddChild(cobj(), node);
+ xmlNode* child = xmlNewCDataBlock(cobj()->doc, (const xmlChar*)content.c_str(), content.bytes());
+ xmlNode* node = xmlAddChild(cobj(), child);
+ if (!node)
+ {
+ if (child)
+ xmlFreeNode(child);
+ throw internal_error("Could not add CDATA node \"" + content + "\"");
+ }
Node::create_wrapper(node);
return static_cast<CdataNode*>(node->_private);
}
@@ -262,24 +292,35 @@ EntityReference* Element::add_child_entity_reference(const Glib::ustring& name)
// Is it an entity reference or a character reference?
// libxml uses xmlNode::type == XML_ENTITY_REF_NODE for both.
- xmlNode* node = 0;
+ xmlNode* child = 0;
if (extended_name[ichar] == '#')
- node = xmlNewCharRef(cobj()->doc, (const xmlChar*)name.c_str());
+ child = xmlNewCharRef(cobj()->doc, (const xmlChar*)name.c_str());
else
- node = xmlNewReference(cobj()->doc, (const xmlChar*)name.c_str());
- node = xmlAddChild(cobj(), node);
+ child = xmlNewReference(cobj()->doc, (const xmlChar*)name.c_str());
+ xmlNode* node = xmlAddChild(cobj(), child);
+ if (!node)
+ {
+ if (child)
+ xmlFreeNode(child);
+ throw internal_error("Could not add entity reference node " + name);
+ }
Node::create_wrapper(node);
- return node ? static_cast<EntityReference*>(node->_private) : 0;
+ return static_cast<EntityReference*>(node->_private);
}
ProcessingInstructionNode* Element::add_child_processing_instruction(
const Glib::ustring& name, const Glib::ustring& content)
{
- xmlNode* node = xmlNewDocPI(cobj()->doc, (const xmlChar*)name.c_str(), (const xmlChar*)content.c_str());
- node = xmlAddChild(cobj(), node);
+ xmlNode* child = xmlNewDocPI(cobj()->doc, (const xmlChar*)name.c_str(), (const xmlChar*)content.c_str());
+ xmlNode* node = xmlAddChild(cobj(), child);
+ if (!node)
+ {
+ if (child)
+ xmlFreeNode(child);
+ throw internal_error("Could not add processing instruction node " + name);
+ }
Node::create_wrapper(node);
- return node ? static_cast<ProcessingInstructionNode*>(node->_private) : 0;
+ return static_cast<ProcessingInstructionNode*>(node->_private);
}
-
} //namespace xmlpp
diff --git a/libxml++/nodes/element.h b/libxml++/nodes/element.h
index c9e3082..a727989 100644
--- a/libxml++/nodes/element.h
+++ b/libxml++/nodes/element.h
@@ -29,8 +29,12 @@ public:
typedef std::list<Attribute*> AttributeList;
/** This adds a namespace declaration to this node which will apply to this node and all children.
- * @param ns_uri The namespace to associate with the prefix, or to use as the default namespace if no prefix is specified.
- * @param ns_prefix The namespace prefix. If no prefix is specified then the namespace URI will be the default namespace.
+ * @param ns_uri The namespace to associate with the prefix,
+ * or to use as the default namespace if no prefix is specified.
+ * @param ns_prefix The namespace prefix. If no prefix is specified then the
+ * namespace URI will be the default namespace.
+ * @throws xmlpp::exception If a new namespace node cannot be created,
+ * e.g. because a namespace with the same prefix already exists.
*/
void set_namespace_declaration(const Glib::ustring& ns_uri, const Glib::ustring& ns_prefix = Glib::ustring());
@@ -75,7 +79,7 @@ public:
* @param value The new value for the attribute
* @param ns_prefix Namespace prefix. If the prefix has not been declared then this method will throw an exception.
* @return The attribute that was changed, or 0 is no suitable Attribute was found.
- * @throws exception
+ * @throws xmlpp::exception
*/
Attribute* set_attribute(const Glib::ustring& name, const Glib::ustring& value,
const Glib::ustring& ns_prefix = Glib::ustring());
@@ -103,6 +107,7 @@ public:
/** Append a new text node.
* @param content The text. This should be unescaped - see ContentNode::set_content().
* @returns The new text node.
+ * @throws xmlpp::internal_error
*/
TextNode* add_child_text(const Glib::ustring& content = Glib::ustring());
@@ -113,6 +118,7 @@ public:
* @param previous_sibling An existing child node.
* @param content The text. This should be unescaped - see ContentNode::set_content().
* @returns The new text node.
+ * @throws xmlpp::internal_error
*/
TextNode* add_child_text(xmlpp::Node* previous_sibling, const Glib::ustring& content = Glib::ustring());
@@ -123,12 +129,14 @@ public:
* @param next_sibling An existing child node.
* @param content The text. This should be unescaped - see ContentNode::set_content().
* @returns The new text node.
+ * @throws xmlpp::internal_error
*/
TextNode* add_child_text_before(xmlpp::Node* next_sibling, const Glib::ustring& content = Glib::ustring());
/** Set the text of the first text node, adding one if necessary.
* This is a convenience method, meant as an alternative to iterating over all the child nodes to find the first suitable node then and setting the text directly.
* @param content The text. This should be unescaped - see ContentNode::set_content().
+ * @throws xmlpp::internal_error
*/
void set_child_text(const Glib::ustring& content);
@@ -141,12 +149,14 @@ 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_child_comment(const Glib::ustring& content);
/** Append a new CDATA node.
* @param content The raw text.
* @returns The new CDATA node.
+ * @throws xmlpp::internal_error
*/
CdataNode* add_child_cdata(const Glib::ustring& content);
@@ -162,6 +172,7 @@ public:
*
* @param name The name of the entity.
* @returns The new entity reference node.
+ * @throws xmlpp::internal_error
*/
EntityReference* add_child_entity_reference(const Glib::ustring& name);
@@ -172,6 +183,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 xmlpp::internal_error
*/
ProcessingInstructionNode* add_child_processing_instruction(
const Glib::ustring& name, const Glib::ustring& content);
diff --git a/libxml++/nodes/node.cc b/libxml++/nodes/node.cc
index 8f2344a..0ba6822 100644
--- a/libxml++/nodes/node.cc
+++ b/libxml++/nodes/node.cc
@@ -30,6 +30,8 @@ xmlXPathObject* eval_common(const Glib::ustring& xpath,
xmlpp::XPathResultType* result_type, xmlNode* node)
{
xmlXPathContext* ctxt = xmlXPathNewContext(node->doc);
+ if (!ctxt)
+ throw xmlpp::internal_error("Could not create XPath context for " + xpath);
ctxt->node = node;
if (namespaces)
@@ -221,13 +223,13 @@ Element* Node::add_child(const Glib::ustring& name,
const Glib::ustring& ns_prefix)
{
_xmlNode* child = create_new_child_node(name, ns_prefix);
- if(!child)
- return 0;
-
_xmlNode* node = xmlAddChild(impl_, child);
- if(!node)
- return 0;
-
+ if (!node)
+ {
+ if (child)
+ xmlFreeNode(child);
+ throw internal_error("Could not add child element node " + name);
+ }
Node::create_wrapper(node);
return static_cast<Element*>(node->_private);
}
@@ -240,13 +242,13 @@ Element* Node::add_child(xmlpp::Node* previous_sibling,
return 0;
_xmlNode* child = create_new_child_node(name, ns_prefix);
- if(!child)
- return 0;
-
_xmlNode* node = xmlAddNextSibling(previous_sibling->cobj(), child);
- if(!node)
- return 0;
-
+ if (!node)
+ {
+ if (child)
+ xmlFreeNode(child);
+ throw internal_error("Could not add child element node " + name);
+ }
Node::create_wrapper(node);
return static_cast<Element*>(node->_private);
}
@@ -259,13 +261,13 @@ Element* Node::add_child_before(xmlpp::Node* next_sibling,
return 0;
_xmlNode* child = create_new_child_node(name, ns_prefix);
- if(!child)
- return 0;
-
_xmlNode* node = xmlAddPrevSibling(next_sibling->cobj(), child);
- if(!node)
- return 0;
-
+ if (!node)
+ {
+ if (child)
+ xmlFreeNode(child);
+ throw internal_error("Could not add child element node " + name);
+ }
Node::create_wrapper(node);
return static_cast<Element*>(node->_private);
}
@@ -302,7 +304,8 @@ void Node::remove_child(Node* node)
{
//TODO: Allow a node to be removed without deleting it, to allow it to be moved?
//This would require a more complex memory management API.
-
+ if (!node)
+ return;
xmlNode* cnode = node->cobj();
Node::free_wrappers(cnode); //This delete the C++ node (not this) itself.
xmlUnlinkNode(cnode);
@@ -311,11 +314,14 @@ void Node::remove_child(Node* node)
Node* Node::import_node(const Node* node, bool recursive)
{
+ if (!node)
+ return 0;
+
//Create the node, by copying:
xmlNode* imported_node = xmlDocCopyNode(const_cast<xmlNode*>(node->cobj()), impl_->doc, recursive);
if (!imported_node)
{
- throw exception("Unable to import node");
+ throw exception("Unable to copy the node that shall be imported");
}
if (imported_node->type == XML_ATTRIBUTE_NODE && impl_->type == XML_ELEMENT_NODE)
@@ -446,6 +452,8 @@ static NodeSet find_impl(xmlXPathContext* ctxt, const Glib::ustring& xpath)
NodeSet Node::find(const Glib::ustring& xpath) const
{
xmlXPathContext* ctxt = xmlXPathNewContext(impl_->doc);
+ if (!ctxt)
+ throw internal_error("Could not create XPath context for " + xpath);
ctxt->node = impl_;
return find_impl(ctxt, xpath);
@@ -455,6 +463,8 @@ NodeSet Node::find(const Glib::ustring& xpath,
const PrefixNsMap& namespaces) const
{
xmlXPathContext* ctxt = xmlXPathNewContext(impl_->doc);
+ if (!ctxt)
+ throw internal_error("Could not create XPath context for " + xpath);
ctxt->node = impl_;
for (PrefixNsMap::const_iterator it=namespaces.begin();
diff --git a/libxml++/nodes/node.h b/libxml++/nodes/node.h
index b54fdb3..a60107e 100644
--- a/libxml++/nodes/node.h
+++ b/libxml++/nodes/node.h
@@ -71,11 +71,18 @@ public:
/** Set the namespace prefix used by the node.
* If no such namespace prefix has been declared then this method will throw an exception.
* @param ns_prefix The namespace prefix.
- * @throws exception
+ * @throws xmlpp::exception
*/
void set_namespace(const Glib::ustring& ns_prefix);
+ /** Get the namespace prefix of this node.
+ * @returns The node's namespace prefix. Can be an empty string.
+ */
Glib::ustring get_namespace_prefix() const;
+
+ /** Get the namespace URI of this node.
+ * @returns The node's namespace URI. Can be an empty string.
+ */
Glib::ustring get_namespace_uri() const;
/** Discover at what line number this node occurs in the XML file.
@@ -84,44 +91,48 @@ public:
int get_line() const;
/** Get the parent element for this node.
- * @returns The parent node
+ * @returns The parent node, or <tt>0</tt> if the node has no parent element.
*/
const Element* get_parent() const;
/** Get the parent element for this node.
- * @returns The parent node
+ * @returns The parent node, or <tt>0</tt> if the node has no parent element.
*/
Element* get_parent();
/** Get the next sibling for this node.
- * @returns The next sibling
+ * @returns The next sibling, or <tt>0</tt> if the node has no next sibling.
*/
const Node* get_next_sibling() const;
/** Get the next sibling for this node.
- * @returns The next sibling
+ * @returns The next sibling, or <tt>0</tt> if the node has no next sibling.
*/
Node* get_next_sibling();
/** Get the previous sibling for this node .
- * @returns The previous sibling
+ * @returns The previous sibling, or <tt>0</tt> if the node has no previous sibling.
*/
const Node* get_previous_sibling() const;
/** Get the previous sibling for this node.
- * @returns The previous sibling
+ * @returns The previous sibling, or <tt>0</tt> if the node has no previous sibling.
*/
Node* get_previous_sibling();
- /** Get the first child of this node. You may optionally get the first child node which has a certain name.
- * @returns The first child
+ /** Get the first child of this node.
+ * You may optionally get the first child node which has a certain name.
+ * @param name The name of the requested child node, or an empty string.
+ * @returns The first child, or <tt>0</tt> if no child node (with the specified name) exists.
*
* @newin{2,36}
*/
const Node* get_first_child(const Glib::ustring& name = Glib::ustring()) const;
- /** Get the first child of this node. You may optionally get the first child node which has a certain name.
- * @returns The first child
+ /** Get the first child of this node.
+ * You may optionally get the first child node which has a certain name.
+ * @param name The name of the requested child node, or an empty string.
+ * @returns The first child, or <tt>0</tt> if no child node (with the specified name) exists.
*
* @newin{2,36}
*/
@@ -140,15 +151,18 @@ public:
const NodeList get_children(const Glib::ustring& name = Glib::ustring()) const;
/** Add a child element to this node.
+ * This node must be an element node.
* @param name The new node name
* @param ns_prefix The namespace prefix. If the prefix has not been declared then this method will throw an exception.
* @returns The newly-created element
- * @throws exception
+ * @throws xmlpp::exception If a namespace prefix is specified, but has not been declared.
+ * @throws xmlpp::internal_error If this node is not an element node.
*/
Element* add_child(const Glib::ustring& name,
const Glib::ustring& ns_prefix = Glib::ustring());
/** Add a child element to this node after the specified existing child node.
+ * This node must be an element node.
*
* @newin{2,24}
*
@@ -156,12 +170,14 @@ public:
* @param name The new node name
* @param ns_prefix The namespace prefix. If the prefix has not been declared then this method will throw an exception.
* @returns The newly-created element
- * @throws exception
+ * @throws xmlpp::exception If a namespace prefix is specified, but has not been declared.
+ * @throws xmlpp::internal_error If this node is not an element node.
*/
Element* add_child(xmlpp::Node* previous_sibling, const Glib::ustring& name,
const Glib::ustring& ns_prefix = Glib::ustring());
/** Add a child element to this node before the specified existing child node.
+ * This node must be an element node.
*
* @newin{2,24}
*
@@ -169,7 +185,8 @@ public:
* @param name The new node name
* @param ns_prefix The namespace prefix. If the prefix has not been declared then this method will throw an exception.
* @returns The newly-created element
- * @throws exception
+ * @throws xmlpp::exception If a namespace prefix is specified, but has not been declared.
+ * @throws xmlpp::internal_error If this node is not an element node.
*/
Element* add_child_before(xmlpp::Node* next_sibling, const Glib::ustring& name,
const Glib::ustring& ns_prefix = Glib::ustring());
@@ -190,19 +207,21 @@ public:
* @param recursive Whether to import the child nodes also. Defaults to true.
* @returns Usually the newly created node, but adjacent text nodes are merged,
* and the old text node with merged contents is returned.
- * @throws exception
+ * @throws xmlpp::exception
*/
Node* import_node(const Node* node, bool recursive = true);
- /** Return the XPath of this node.
+ /** Get the XPath of this node.
* @result The XPath of the node.
*/
Glib::ustring get_path() const;
/** Find nodes from an XPath expression.
* @param xpath The XPath of the nodes.
- * @throws exception
+ * @returns The resulting NodeSet.
+ * @throws xmlpp::exception If the XPath expression cannot be evaluated.
+ * @throws xmlpp::internal_error If the result type is not nodeset.
*/
NodeSet find(const Glib::ustring& xpath) const;
@@ -213,7 +232,9 @@ public:
/** Find nodes from an XPath expression.
* @param xpath The XPath of the nodes.
* @param namespaces A map of namespace prefixes to namespace URIs to be used while finding.
- * @throws exception
+ * @returns The resulting NodeSet.
+ * @throws xmlpp::exception If the XPath expression cannot be evaluated.
+ * @throws xmlpp::internal_error If the result type is not nodeset.
*/
NodeSet find(const Glib::ustring& xpath, const PrefixNsMap& namespaces) const;
@@ -224,6 +245,7 @@ public:
* @returns The value of the XPath expression. If the value is not of type boolean,
* it is converted to boolean.
* @throws xmlpp::exception If the XPath expression cannot be evaluated.
+ * @throws xmlpp::internal_error
*
* @newin{2,36}
*/
@@ -238,6 +260,7 @@ public:
* @returns The value of the XPath expression. If the value is not of type boolean,
* it is converted to boolean.
* @throws xmlpp::exception If the XPath expression cannot be evaluated.
+ * @throws xmlpp::internal_error
*
* @newin{2,36}
*/
@@ -251,6 +274,7 @@ public:
* @returns The value of the XPath expression. If the value is not of type number,
* it is converted to number.
* @throws xmlpp::exception If the XPath expression cannot be evaluated.
+ * @throws xmlpp::internal_error
*
* @newin{2,36}
*/
@@ -264,6 +288,7 @@ public:
* @returns The value of the XPath expression. If the value is not of type number,
* it is converted to number.
* @throws xmlpp::exception If the XPath expression cannot be evaluated.
+ * @throws xmlpp::internal_error
*
* @newin{2,36}
*/
@@ -277,6 +302,7 @@ public:
* @returns The value of the XPath expression. If the value is not of type string,
* it is converted to string.
* @throws xmlpp::exception If the XPath expression cannot be evaluated.
+ * @throws xmlpp::internal_error
*
* @newin{2,36}
*/
@@ -290,6 +316,7 @@ public:
* @returns The value of the XPath expression. If the value is not of type string,
* it is converted to string.
* @throws xmlpp::exception If the XPath expression cannot be evaluated.
+ * @throws xmlpp::internal_error
*
* @newin{2,36}
*/
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]