[libxml++] Node::find(): Propagate const qualifier to found nodes



commit f940edf2829d8d53284c42a35b8a46bf3a5a1e7f
Author: Kjell Ahlstedt <kjell ahlstedt bredband net>
Date:   Thu Sep 17 10:26:32 2015 +0200

    Node::find(): Propagate const qualifier to found nodes
    
    * libxml++/nodes/node.[h|cc]: Add const_NodeSet. Add non-const versions of
    find() and let the const versions return const_NodeSet.
    * examples/dom_xpath/main.cc: Add some const. Bug #338907.

 examples/dom_xpath/main.cc |   10 +--
 libxml++/nodes/node.cc     |  162 +++++++++++++++++++++++---------------------
 libxml++/nodes/node.h      |   22 ++++++-
 3 files changed, 109 insertions(+), 85 deletions(-)
---
diff --git a/examples/dom_xpath/main.cc b/examples/dom_xpath/main.cc
index 96bf663..8000df8 100644
--- a/examples/dom_xpath/main.cc
+++ b/examples/dom_xpath/main.cc
@@ -1,5 +1,3 @@
-// -*- C++ -*-
-
 /* main.cc
  *
  * Copyright (C) 2002 The libxml++ development team
@@ -59,19 +57,19 @@ bool xpath_test(const xmlpp::Node* node, const Glib::ustring& xpath)
     {
       std::cout << " " << child->get_path();
 
-      auto attribute = dynamic_cast<xmlpp::Attribute*>(child);
+      auto attribute = dynamic_cast<const xmlpp::Attribute*>(child);
       if (attribute)
         std::cout << ", value=\"" << attribute->get_value() << "\"";
 
-      auto content_node = dynamic_cast<xmlpp::ContentNode*>(child);
+      auto content_node = dynamic_cast<const xmlpp::ContentNode*>(child);
       if (content_node)
         std::cout << ", content=\"" << content_node->get_content() << "\"";
 
-      auto entity_reference = dynamic_cast<xmlpp::EntityReference*>(child);
+      auto entity_reference = dynamic_cast<const xmlpp::EntityReference*>(child);
       if (entity_reference)
         std::cout << ", text=\"" << entity_reference->get_original_text() << "\"";
 
-      auto element = dynamic_cast<xmlpp::Element*>(child);
+      auto element = dynamic_cast<const xmlpp::Element*>(child);
       if (element)
       {
         auto text_node = element->get_child_text();
diff --git a/libxml++/nodes/node.cc b/libxml++/nodes/node.cc
index 5042a39..2b494ec 100644
--- a/libxml++/nodes/node.cc
+++ b/libxml++/nodes/node.cc
@@ -53,6 +53,81 @@ Tlist get_children_common(const Glib::ustring& name, xmlNode* child)
   return children;
 }
 
+// Common part of all overloaded xmlpp::Node::find() methods.
+template <typename Tvector>
+Tvector find_common(const Glib::ustring& xpath,
+  const xmlpp::Node::PrefixNsMap* namespaces, xmlNode* node)
+{
+  auto ctxt = xmlXPathNewContext(node->doc);
+  if (!ctxt)
+    throw xmlpp::internal_error("Could not create XPath context for " + xpath);
+  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()));
+  }
+
+  auto result = xmlXPathEval((const xmlChar*)xpath.c_str(), ctxt);
+
+  if (!result)
+  {
+    xmlXPathFreeContext(ctxt);
+
+    throw xmlpp::exception("Invalid XPath: " + xpath);
+  }
+
+  if (result->type != XPATH_NODESET)
+  {
+    xmlXPathFreeObject(result);
+    xmlXPathFreeContext(ctxt);
+
+    throw xmlpp::internal_error("Only nodeset result types are supported.");
+  }
+
+  auto nodeset = result->nodesetval;
+  Tvector nodes;
+  if (nodeset && !xmlXPathNodeSetIsEmpty(nodeset))
+  {
+    const int count = xmlXPathNodeSetGetLength(nodeset);
+    nodes.reserve(count);
+    for (int i = 0; i != count; ++i)
+    {
+      auto cnode = xmlXPathNodeSetItem(nodeset, i);
+      if (!cnode)
+      {
+        std::cerr << "Node::find(): The xmlNode was null." << std::endl;
+        continue;
+      }
+
+      if (cnode->type == XML_NAMESPACE_DECL)
+      {
+        //In this case we would cast it to a xmlNs*,
+        //but this C++ method only returns Nodes.
+        std::cerr << "Node::find(): Ignoring an xmlNs object." << std::endl;
+        continue;
+      }
+      
+      //TODO: Check for other cnode->type values?
+  
+      nodes.push_back(_convert_node(cnode));
+    }
+  }
+  else
+  {
+    // return empty set
+  }
+
+  xmlXPathFreeObject(result);
+  xmlXPathFreeContext(ctxt);
+
+  return nodes;
+}
+
 // Common part of xmlpp::Node::eval_to_[boolean|number|string]
 xmlXPathObject* eval_common(const Glib::ustring& xpath,
   const xmlpp::Node::PrefixNsMap* namespaces,
@@ -451,91 +526,24 @@ Glib::ustring Node::get_path() const
   return retn;
 }
 
-static NodeSet find_impl(xmlXPathContext* ctxt, const Glib::ustring& xpath)
+NodeSet Node::find(const Glib::ustring& xpath)
 {
-  auto result = xmlXPathEval((const xmlChar*)xpath.c_str(), ctxt);
-
-  if(!result)
-  {
-    xmlXPathFreeContext(ctxt);
-
-    throw exception("Invalid XPath: " + xpath);
-  }
-
-  if(result->type != XPATH_NODESET)
-  {
-    xmlXPathFreeObject(result);
-    xmlXPathFreeContext(ctxt);
-
-    throw internal_error("Only nodeset result types are supported.");
-  }
-
-  auto nodeset = result->nodesetval;
-  NodeSet nodes;
-  if( nodeset && !xmlXPathNodeSetIsEmpty(nodeset))
-  {
-    const int count = xmlXPathNodeSetGetLength(nodeset);
-    nodes.reserve(count);
-    for (int i = 0; i != count; ++i)
-    {
-      auto cnode = xmlXPathNodeSetItem(nodeset, i);
-      if(!cnode)
-      {
-        std::cerr << "Node::find_impl: The xmlNode was null." << std::endl;
-        continue;
-      }
-
-      if(cnode->type == XML_NAMESPACE_DECL)
-      {
-        //In this case we would cast it to a xmlNs*,
-        //but this C++ method only returns Nodes.
-        std::cerr << "Node::find_impl: ignoring an xmlNs object." << std::endl;
-        continue;
-      }
-      
-      //TODO: Check for other cnode->type values?
-  
-      Node::create_wrapper(cnode);
-      auto cppNode = static_cast<Node*>(cnode->_private);
-      nodes.push_back(cppNode);
-    }
-  }
-  else
-  {
-    // return empty set
-  }
-
-  xmlXPathFreeObject(result);
-  xmlXPathFreeContext(ctxt);
-
-  return nodes;
+  return find_common<NodeSet>(xpath, 0, impl_);
 }
 
-NodeSet Node::find(const Glib::ustring& xpath) const
+const_NodeSet Node::find(const Glib::ustring& xpath) const
 {
-  auto ctxt = xmlXPathNewContext(impl_->doc);
-  if (!ctxt)
-    throw internal_error("Could not create XPath context for " + xpath);
-  ctxt->node = impl_;
-  
-  return find_impl(ctxt, xpath);
+  return find_common<const_NodeSet>(xpath, 0, impl_);
 }
 
-NodeSet Node::find(const Glib::ustring& xpath,
-                  const PrefixNsMap& namespaces) const
+NodeSet Node::find(const Glib::ustring& xpath, const PrefixNsMap& namespaces)
 {
-  auto 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();
-       it != namespaces.end(); it++)
-    xmlXPathRegisterNs(ctxt,
-                      reinterpret_cast<const xmlChar*>(it->first.c_str()),
-                      reinterpret_cast<const xmlChar*>(it->second.c_str()));
+  return find_common<NodeSet>(xpath, &namespaces, impl_);
+}
 
-  return find_impl(ctxt, xpath);
+const_NodeSet Node::find(const Glib::ustring& xpath, const PrefixNsMap& namespaces) const
+{
+  return find_common<const_NodeSet>(xpath, &namespaces, impl_);
 }
 
 bool Node::eval_to_boolean(const Glib::ustring& xpath, XPathResultType* result_type) const
diff --git a/libxml++/nodes/node.h b/libxml++/nodes/node.h
index 825a103..fe70152 100644
--- a/libxml++/nodes/node.h
+++ b/libxml++/nodes/node.h
@@ -29,6 +29,7 @@ class Attribute;
 
 class Node;
 typedef std::vector<Node*> NodeSet;
+typedef std::vector<const Node*> const_NodeSet;
 
 // xmlpp::XPathResultType is similar to xmlXPathObjectType in libxml2.
 /** An XPath expression is evaluated to yield a result, which
@@ -282,7 +283,15 @@ public:
    * @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;
+  NodeSet find(const Glib::ustring& xpath);
+
+  /** Find nodes from an XPath expression.
+   * @param xpath The XPath of the nodes.
+   * @returns The resulting const_NodeSet.
+   * @throws xmlpp::exception If the XPath expression cannot be evaluated.
+   * @throws xmlpp::internal_error If the result type is not nodeset.
+   */
+  const_NodeSet find(const Glib::ustring& xpath) const;
 
   /** A map of namespace prefixes to namespace URIs.
    */
@@ -295,7 +304,16 @@ public:
    * @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;
+  NodeSet find(const Glib::ustring& xpath, const PrefixNsMap& namespaces);
+
+  /** 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.
+   * @returns The resulting const_NodeSet.
+   * @throws xmlpp::exception If the XPath expression cannot be evaluated.
+   * @throws xmlpp::internal_error If the result type is not nodeset.
+   */
+  const_NodeSet find(const Glib::ustring& xpath, const PrefixNsMap& namespaces) const;
 
   /** Evaluate an XPath expression.
    * @param xpath The XPath expression.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]