[libxml++] Node: Add functions eval_to_[boolean|number|string]().
- From: Kjell Ahlstedt <kjellahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libxml++] Node: Add functions eval_to_[boolean|number|string]().
- Date: Fri, 20 Apr 2012 11:41:10 +0000 (UTC)
commit 478a5bd59ca4e932cb3d4d43853a350b0fa76692
Author: Kjell Ahlstedt <kjell ahlstedt bredband net>
Date: Fri Apr 20 13:27:50 2012 +0200
Node: Add functions eval_to_[boolean|number|string]().
* examples/dom_xpath/example.xml: Add an element with numeric value.
* examples/dom_xpath/main.cc: Add calls to the new functions.
* libxml++/nodes/node.[h|cc]:
Add the functions eval_to_[boolean|number|string](). Bug #316244.
ChangeLog | 9 +++
examples/dom_xpath/example.xml | 7 +-
examples/dom_xpath/main.cc | 86 +++++++++++++++++++++++++---
libxml++/nodes/node.cc | 120 ++++++++++++++++++++++++++++++++++++++++
libxml++/nodes/node.h | 109 ++++++++++++++++++++++++++++++++++--
5 files changed, 311 insertions(+), 20 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 694af7f..4279a7d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2012-04-20 Kjell Ahlstedt <kjell ahlstedt bredband net>
+
+ Node: Add functions eval_to_[boolean|number|string]().
+
+ * examples/dom_xpath/example.xml: Add an element with numeric value.
+ * examples/dom_xpath/main.cc: Add calls to the new functions.
+ * libxml++/nodes/node.[h|cc]:
+ Add the functions eval_to_[boolean|number|string](). Bug #316244.
+
2012-04-19 Kjell Ahlstedt <kjell ahlstedt bredband net>
Node: Make the previous fix thread-safe.
diff --git a/examples/dom_xpath/example.xml b/examples/dom_xpath/example.xml
index 7e10580..6dfa280 100644
--- a/examples/dom_xpath/example.xml
+++ b/examples/dom_xpath/example.xml
@@ -11,8 +11,9 @@
<title>Another section</title>
<section id="section3">
<title>A sub-section</title>
- <para>This paragraph refers to <xref linkend="section1"/>,
- <xref linkend="section2"/>, and <xref linkend="section4"/>.</para>
+ <para>This paragraph refers to <literal>3</literal> sections:
+ <xref linkend="section1"/>, <xref linkend="section2"/>, and
+ <xref linkend="section4"/>.</para>
</section>
</section>
-</article>
\ No newline at end of file
+</article>
diff --git a/examples/dom_xpath/main.cc b/examples/dom_xpath/main.cc
index f8722e0..e713a2b 100644
--- a/examples/dom_xpath/main.cc
+++ b/examples/dom_xpath/main.cc
@@ -24,23 +24,78 @@
#endif
#include <libxml++/libxml++.h>
-
+#include <stdlib.h>
#include <iostream>
+Glib::ustring result_type_to_ustring(xmlpp::XPathResultType result_type)
+{
+ switch (result_type)
+ {
+ case xmlpp::XPATH_RESULT_NODESET: return "nodeset";
+ case xmlpp::XPATH_RESULT_BOOLEAN: return "boolean";
+ case xmlpp::XPATH_RESULT_NUMBER: return "number";
+ case xmlpp::XPATH_RESULT_STRING: return "string";
+
+ case xmlpp::XPATH_RESULT_UNDEFINED:
+ default:
+ return "undefined";
+ }
+}
void xpath_test(const xmlpp::Node* node, const Glib::ustring& xpath)
{
std::cout << std::endl; //Separate tests by an empty line.
std::cout << "searching with xpath '" << xpath << "' in root node: " << std::endl;
- xmlpp::NodeSet set = node->find(xpath);
-
- std::cout << set.size() << " nodes have been found:" << std::endl;
+ try
+ {
+ xmlpp::NodeSet set = node->find(xpath);
+
+ std::cout << set.size() << " nodes have been found:" << std::endl;
+
+ //Print the structural paths and the values:
+ for(xmlpp::NodeSet::iterator i = set.begin(); i != set.end(); ++i)
+ {
+ std::cout << " " << (*i)->get_path();
+
+ xmlpp::Attribute* attribute = dynamic_cast<xmlpp::Attribute*>(*i);
+ if (attribute)
+ std::cout << ", value=\"" << attribute->get_value() << "\"";
- //Print the structural paths:
- for(xmlpp::NodeSet::iterator i = set.begin(); i != set.end(); ++i)
+ xmlpp::ContentNode* content_node = dynamic_cast<xmlpp::ContentNode*>(*i);
+ if (content_node)
+ std::cout << ", content=\"" << content_node->get_content() << "\"";
+
+ xmlpp::EntityReference* entity_reference = dynamic_cast<xmlpp::EntityReference*>(*i);
+ if (entity_reference)
+ std::cout << ", text=\"" << entity_reference->get_original_text() << "\"";
+
+ xmlpp::Element* element = dynamic_cast<xmlpp::Element*>(*i);
+ if (element)
+ {
+ xmlpp::TextNode* text_node = element->get_child_text();
+ if (text_node)
+ std::cout << ", child_text=\"" << text_node->get_content() << "\"";
+ }
+ std::cout << std::endl;
+ }
+ }
+ catch (const xmlpp::exception& ex)
+ {
+ std::cout << "Exception caught from find: " << ex.what() << std::endl;
+ }
+
+ try
{
- std::cout << " " << (*i)->get_path() << std::endl;
+ xmlpp::XPathResultType result_type;
+ std::cout << "Boolean=" << (node->eval_to_boolean(xpath) ? "true" : "false")
+ << ", Number=" << node->eval_to_number(xpath, &result_type)
+ << ", String=\"" << node->eval_to_string(xpath) << "\"";
+ std::cout << ", Result_type=" << result_type_to_ustring(result_type) << std::endl;
+ }
+ catch (const xmlpp::exception& ex)
+ {
+ std::cout << "Exception caught from eval: " << ex.what() << std::endl;
}
}
@@ -51,7 +106,7 @@ int main(int argc, char* argv[])
std::locale::global(std::locale(""));
std::string filepath;
- if(argc > 1 )
+ if (argc > 1)
filepath = argv[1]; //Allow the user to specify a different XML file to parse.
else
filepath = "example.xml";
@@ -71,6 +126,17 @@ int main(int argc, char* argv[])
// Find the title node (if there is one):
xpath_test(root, "title");
+ // Find all literal text, in any paragraph:
+ xpath_test(root, "//para/literal");
+
+ // Evaluate some XPath expressions with result types other than nodeset:
+ xpath_test(root, "boolean(//para/literal)");
+ xpath_test(root, "number(//para/literal)+2");
+ xpath_test(root, "concat(string(title),\" !\")");
+
+ // Don't find anything:
+ xpath_test(root, "/wont_find");
+
std::cout << std::endl;
// And finally test whether intra-document links are well-formed.
@@ -82,6 +148,7 @@ int main(int argc, char* argv[])
std::cout << "searching for unresolved internal references "
<< "(see docbook manual):" << std::endl;
+ xpath_test(root, "//@id");
xpath_test(root, "//xref/@linkend");
}
}
@@ -91,6 +158,5 @@ int main(int argc, char* argv[])
std::cout << "Exception caught: " << ex.what() << std::endl;
}
- return 0;
+ return EXIT_SUCCESS;
}
-
diff --git a/libxml++/nodes/node.cc b/libxml++/nodes/node.cc
index e34a0be..8f2344a 100644
--- a/libxml++/nodes/node.cc
+++ b/libxml++/nodes/node.cc
@@ -22,6 +22,93 @@
#include <iostream>
+namespace // anonymous
+{
+// Common part of xmlpp::Node::eval_to_[boolean|number|string]
+xmlXPathObject* eval_common(const Glib::ustring& xpath,
+ const xmlpp::Node::PrefixNsMap* namespaces,
+ xmlpp::XPathResultType* result_type, xmlNode* node)
+{
+ xmlXPathContext* ctxt = xmlXPathNewContext(node->doc);
+ ctxt->node = node;
+
+ if (namespaces)
+ {
+ for (xmlpp::Node::PrefixNsMap::const_iterator it = namespaces->begin();
+ it != namespaces->end(); ++it)
+ xmlXPathRegisterNs(ctxt,
+ reinterpret_cast<const xmlChar*>(it->first.c_str()),
+ reinterpret_cast<const xmlChar*>(it->second.c_str()));
+ }
+
+ xmlXPathObject* xpath_value = xmlXPathEvalExpression(
+ reinterpret_cast<const xmlChar*>(xpath.c_str()), ctxt);
+
+ xmlXPathFreeContext(ctxt);
+
+ if (!xpath_value)
+ {
+ if (result_type)
+ *result_type = xmlpp::XPATH_RESULT_UNDEFINED;
+
+ throw xmlpp::exception("Invalid XPath: " + xpath);
+ }
+
+ if (result_type)
+ {
+ if (xpath_value->type == XPATH_NODESET ||
+ xpath_value->type == XPATH_BOOLEAN ||
+ xpath_value->type == XPATH_NUMBER ||
+ xpath_value->type == XPATH_STRING)
+ *result_type = static_cast<xmlpp::XPathResultType>(xpath_value->type);
+ else
+ *result_type = xmlpp::XPATH_RESULT_UNDEFINED;
+ }
+
+ return xpath_value;
+}
+
+// Common part of all overloaded xmlpp::Node::eval_to_boolean() methods.
+bool eval_common_to_boolean(const Glib::ustring& xpath,
+ const xmlpp::Node::PrefixNsMap* namespaces,
+ xmlpp::XPathResultType* result_type, xmlNode* node)
+{
+ xmlXPathObject* xpath_value = eval_common(xpath, namespaces, result_type, node);
+ const int result = xmlXPathCastToBoolean(xpath_value);
+ xmlXPathFreeObject(xpath_value);
+ return static_cast<bool>(result);
+}
+
+// Common part of all overloaded xmlpp::Node::eval_to_number() methods.
+double eval_common_to_number(const Glib::ustring& xpath,
+ const xmlpp::Node::PrefixNsMap* namespaces,
+ xmlpp::XPathResultType* result_type, xmlNode* node)
+{
+ xmlXPathObject* xpath_value = eval_common(xpath, namespaces, result_type, node);
+ const double result = xmlXPathCastToNumber(xpath_value);
+ xmlXPathFreeObject(xpath_value);
+ return result;
+}
+
+// Common part of all overloaded xmlpp::Node::eval_to_string() methods.
+Glib::ustring eval_common_to_string(const Glib::ustring& xpath,
+ const xmlpp::Node::PrefixNsMap* namespaces,
+ xmlpp::XPathResultType* result_type, xmlNode* node)
+{
+ xmlXPathObject* xpath_value = eval_common(xpath, namespaces, result_type, node);
+ xmlChar* result = xmlXPathCastToString(xpath_value);
+ xmlXPathFreeObject(xpath_value);
+ if (result)
+ {
+ const Glib::ustring uresult(reinterpret_cast<const char*>(result));
+ xmlFree(result);
+ return uresult;
+ }
+ return Glib::ustring();
+}
+
+} // anonymous namespace
+
namespace xmlpp
{
@@ -379,6 +466,39 @@ NodeSet Node::find(const Glib::ustring& xpath,
return find_impl(ctxt, xpath);
}
+bool Node::eval_to_boolean(const Glib::ustring& xpath, XPathResultType* result_type) const
+{
+ return eval_common_to_boolean(xpath, 0, result_type, impl_);
+}
+
+bool Node::eval_to_boolean(const Glib::ustring& xpath, const PrefixNsMap& namespaces,
+ XPathResultType* result_type) const
+{
+ return eval_common_to_boolean(xpath, &namespaces, result_type, impl_);
+}
+
+double Node::eval_to_number(const Glib::ustring& xpath, XPathResultType* result_type) const
+{
+ return eval_common_to_number(xpath, 0, result_type, impl_);
+}
+
+double Node::eval_to_number(const Glib::ustring& xpath, const PrefixNsMap& namespaces,
+ XPathResultType* result_type) const
+{
+ return eval_common_to_number(xpath, &namespaces, result_type, impl_);
+}
+
+Glib::ustring Node::eval_to_string(const Glib::ustring& xpath, XPathResultType* result_type) const
+{
+ return eval_common_to_string(xpath, 0, result_type, impl_);
+}
+
+Glib::ustring Node::eval_to_string(const Glib::ustring& xpath, const PrefixNsMap& namespaces,
+ XPathResultType* result_type) const
+{
+ return eval_common_to_string(xpath, &namespaces, result_type, impl_);
+}
+
Glib::ustring Node::get_namespace_prefix() const
{
if(impl_->type == XML_DOCUMENT_NODE || impl_->type == XML_ENTITY_DECL)
diff --git a/libxml++/nodes/node.h b/libxml++/nodes/node.h
index 746bab2..b54fdb3 100644
--- a/libxml++/nodes/node.h
+++ b/libxml++/nodes/node.h
@@ -30,6 +30,23 @@ class Attribute;
class Node;
typedef std::vector<Node*> NodeSet;
+// xmlpp::XPathResultType is similar to xmlXPathObjectType in libxml2.
+/** An XPath expression is evaluated to yield a result, which
+ * has one of the following four basic types:
+ * - node-set
+ * - boolean
+ * - number
+ * - string
+ */
+enum XPathResultType
+{
+ XPATH_RESULT_UNDEFINED = 0,
+ XPATH_RESULT_NODESET = 1,
+ XPATH_RESULT_BOOLEAN = 2,
+ XPATH_RESULT_NUMBER = 3,
+ XPATH_RESULT_STRING = 4
+};
+
/** Represents XML Nodes.
* You should never new or delete Nodes. The Parser will create and manage them for you.
*/
@@ -111,13 +128,13 @@ public:
Node* get_first_child(const Glib::ustring& name = Glib::ustring());
/** Obtain the list of child nodes. You may optionally obtain a list of only the child nodes which have a certain name.
- * @param name The names of the child nodes to get. If you do not specigy a name, then the list will contain all nodes, regardless of their names.
+ * @param name The names of the child nodes to get. If you do not specify a name, then the list will contain all nodes, regardless of their names.
* @returns The list of child nodes.
*/
NodeList get_children(const Glib::ustring& name = Glib::ustring());
/** Obtain the list of child nodes. You may optionally obtain a list of only the child nodes which have a certain name.
- * @param name The names of the child nodes to get. If you do not specigy a name, then the list will contain all nodes, regardless of their names.
+ * @param name The names of the child nodes to get. If you do not specify a name, then the list will contain all nodes, regardless of their names.
* @returns The list of child nodes.
*/
const NodeList get_children(const Glib::ustring& name = Glib::ustring()) const;
@@ -183,7 +200,7 @@ public:
*/
Glib::ustring get_path() const;
- /** Find nodes from a XPath expression.
+ /** Find nodes from an XPath expression.
* @param xpath The XPath of the nodes.
* @throws exception
*/
@@ -193,13 +210,91 @@ public:
*/
typedef std::map<Glib::ustring, Glib::ustring> PrefixNsMap;
- /** Find nodes from a XPath expression.
+ /** 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
*/
NodeSet find(const Glib::ustring& xpath, const PrefixNsMap& namespaces) const;
+ /** Evaluate an XPath expression.
+ * @param xpath The XPath expression.
+ * @param[out] result_type Result type of the XPath expression before conversion
+ * to boolean. If 0, the result type is not returned.
+ * @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.
+ *
+ * @newin{2,36}
+ */
+ bool eval_to_boolean(const Glib::ustring& xpath, XPathResultType* result_type = 0) const;
+
+
+ /** Evaluate an XPath expression.
+ * @param xpath The XPath expression.
+ * @param namespaces A map of namespace prefixes to namespace URIs to be used while evaluating.
+ * @param[out] result_type Result type of the XPath expression before conversion
+ * to boolean. If 0, the result type is not returned.
+ * @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.
+ *
+ * @newin{2,36}
+ */
+ bool eval_to_boolean(const Glib::ustring& xpath, const PrefixNsMap& namespaces,
+ XPathResultType* result_type = 0) const;
+
+ /** Evaluate an XPath expression.
+ * @param xpath The XPath expression.
+ * @param[out] result_type Result type of the XPath expression before conversion
+ * to number. If 0, the result type is not returned.
+ * @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.
+ *
+ * @newin{2,36}
+ */
+ double eval_to_number(const Glib::ustring& xpath, XPathResultType* result_type = 0) const;
+
+ /** Evaluate an XPath expression.
+ * @param xpath The XPath expression.
+ * @param namespaces A map of namespace prefixes to namespace URIs to be used while evaluating.
+ * @param[out] result_type Result type of the XPath expression before conversion
+ * to number. If 0, the result type is not returned.
+ * @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.
+ *
+ * @newin{2,36}
+ */
+ double eval_to_number(const Glib::ustring& xpath, const PrefixNsMap& namespaces,
+ XPathResultType* result_type = 0) const;
+
+ /** Evaluate an XPath expression.
+ * @param xpath The XPath expression.
+ * @param[out] result_type Result type of the XPath expression before conversion
+ * to string. If 0, the result type is not returned.
+ * @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.
+ *
+ * @newin{2,36}
+ */
+ Glib::ustring eval_to_string(const Glib::ustring& xpath, XPathResultType* result_type = 0) const;
+
+ /** Evaluate an XPath expression.
+ * @param xpath The XPath expression.
+ * @param namespaces A map of namespace prefixes to namespace URIs to be used while evaluating.
+ * @param[out] result_type Result type of the XPath expression before conversion
+ * to string. If 0, the result type is not returned.
+ * @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.
+ *
+ * @newin{2,36}
+ */
+ Glib::ustring eval_to_string(const Glib::ustring& xpath, const PrefixNsMap& namespaces,
+ XPathResultType* result_type = 0) const;
///Access the underlying libxml implementation.
_xmlNode* cobj();
@@ -211,7 +306,7 @@ public:
*
* This is only for use by the libxml++ implementation.
*
- * @para node A pointer to an xmlNode or a "derived" struct, such as xmlDoc, xmlAttr, etc.
+ * @param node A pointer to an xmlNode or a "derived" struct, such as xmlDoc, xmlAttr, etc.
*/
static void create_wrapper(_xmlNode* node);
@@ -219,9 +314,9 @@ public:
* recursively destroy the C++ instances for any children.
*
* This is only for use by the libxml++ implementation.
- * @para node A pointer to an xmlNode or a "derived" struct, such as xmlDoc, xmlAttr, etc.
+ * @param node A pointer to an xmlNode or a "derived" struct, such as xmlDoc, xmlAttr, etc.
*/
- static void free_wrappers(_xmlNode* attr);
+ static void free_wrappers(_xmlNode* node);
protected:
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]