]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Use exceptions when reading XML parameter files.
authorDavid Wells <wellsd2@rpi.edu>
Thu, 15 Sep 2016 23:05:33 +0000 (19:05 -0400)
committerDavid Wells <wellsd2@rpi.edu>
Wed, 28 Sep 2016 13:48:07 +0000 (09:48 -0400)
include/deal.II/base/parameter_handler.h
source/base/parameter_handler.cc
tests/parameter_handler/parameter_handler_read_xml.cc
tests/parameter_handler/parameter_handler_read_xml_error_01.cc
tests/parameter_handler/parameter_handler_read_xml_error_01.output
tests/parameter_handler/parameter_handler_read_xml_error_02.cc
tests/parameter_handler/parameter_handler_read_xml_error_02.output
tests/parameter_handler/parameter_handler_read_xml_error_03.cc
tests/parameter_handler/parameter_handler_read_xml_error_03.output
tests/parameter_handler/parameter_handler_read_xml_error_04.cc
tests/parameter_handler/parameter_handler_read_xml_error_04.output

index a4347b2f3264e30fb88be15047102ffed54ed8a5..659ed2c77f259886ea67f007c0dece10b0f1d299 100644 (file)
@@ -1674,9 +1674,20 @@ public:
    * method and then modified by the graphical parameter GUI (see the general
    * documentation of this class).
    *
-   * Return whether the read was successful.
+   * @deprecated This function has been deprecated in favor of the replacement
+   * ParameterHandler::parse_input_from_xml, which raises exceptions to indicate
+   * errors instead of returning an error code.
+   */
+  virtual bool read_input_from_xml (std::istream &input) DEAL_II_DEPRECATED;
+
+  /**
+   * Parse input from an XML stream to populate known parameter fields. This
+   * could be from a file originally written by the print_parameters() function
+   * using the XML output style and then modified by hand as necessary, or from
+   * a file written using this method and then modified by the graphical
+   * parameter GUI (see the general documentation of this class).
    */
-  virtual bool read_input_from_xml (std::istream &input);
+  virtual void parse_input_from_xml (std::istream &input);
 
   /**
    * Clear all contents.
@@ -2038,6 +2049,27 @@ public:
                   "    does not match the given pattern:\n" << "        " <<
                   arg5);
 
+  /**
+   * Exception for when an XML file cannot be read at all. This happens when
+   * there is no top-level XML element called "ParameterHandler" or when there
+   * are multiple top level elements.
+   */
+  DeclExceptionMsg (ExcInvalidXMLParameterFile,
+                    "The provided file could not be parsed as a "
+                    "ParameterHandler description.");
+
+  /**
+   * Exception for when an entry in an XML parameter file does not match the
+   * provided pattern. The arguments are, in order, the entry value, entry
+   * name, and a description of the pattern.
+   */
+  DeclException3 (ExcInvalidEntryForPatternXML,
+                  std::string, std::string, std::string,
+                  << "    The entry value \n" << "        " << arg1 << '\n' <<
+                  "    for the entry named\n" << "        " << arg2 << '\n' <<
+                  "    does not match the given pattern:\n" << "        " <<
+                  arg3);
+
   /**
    * Exception for when the file given in an include statement cannot be
    * open. The arguments are, in order, the line number of the include
index 54f719518b3d311428a0b56c37d98d42034fc05d..fe611210ccaf09135d2d04396205526aee031bdb 100644 (file)
@@ -1746,15 +1746,12 @@ bool ParameterHandler::read_input_from_string (const char *s,
 
 namespace
 {
-  // Recursively go through the 'source' tree
-  // and see if we can find corresponding
-  // entries in the 'destination' tree. If
-  // not, error out (i.e. we have just read
-  // an XML file that has entries that
-  // weren't declared in the ParameterHandler
-  // object); if so, copy the value of these
+  // Recursively go through the 'source' tree and see if we can find
+  // corresponding entries in the 'destination' tree. If not, error out
+  // (i.e. we have just read an XML file that has entries that weren't
+  // declared in the ParameterHandler object); if so, copy the value of these
   // nodes into the destination object
-  bool
+  void
   read_xml_recursively (const boost::property_tree::ptree &source,
                         const std::string                 &current_path,
                         const char                         path_separator,
@@ -1765,107 +1762,81 @@ namespace
     for (boost::property_tree::ptree::const_iterator p = source.begin();
          p != source.end(); ++p)
       {
-        // a sub-tree must either be a
-        // parameter node or a subsection
+        // a sub-tree must either be a parameter node or a subsection
         if (p->second.get_optional<std::string>("value"))
           {
-            // make sure we have a
-            // corresponding entry in the
-            // destination object as well
+            // make sure we have a corresponding entry in the destination
+            // object as well
             const std::string full_path
               = (current_path == ""
                  ?
                  p->first
                  :
                  current_path + path_separator + p->first);
-            if (destination.get_optional<std::string> (full_path)
-                &&
-                destination.get_optional<std::string> (full_path +
-                                                       path_separator +
-                                                       "value"))
-              {
-                // first make sure that the
-                // new entry actually
-                // satisfies its constraints
-                const std::string new_value
-                  = p->second.get<std::string>("value");
-
-                const unsigned int pattern_index
-                  = destination.get<unsigned int> (full_path +
-                                                   path_separator +
-                                                   "pattern");
-                if (patterns[pattern_index]->match(new_value) == false)
-                  {
-                    std::cerr << "    The entry value" << std::endl
-                              << "        " << new_value << std::endl
-                              << "    for the entry named" << std::endl
-                              << "        " << full_path << std::endl
-                              << "    does not match the given pattern" << std::endl
-                              << "        " << patterns[pattern_index]->description()
-                              << std::endl;
-                    return false;
-                  }
-
-                // set the found parameter in
-                // the destination argument
-                destination.put (full_path + path_separator + "value",
-                                 new_value);
-
-                // this node might have
-                // sub-nodes in addition to
-                // "value", such as
-                // "default_value",
-                // "documentation", etc. we
-                // might at some point in the
-                // future want to make sure
-                // that if they exist that
-                // they match the ones in the
-                // 'destination' tree
-              }
-            else
-              {
-                std::cerr << "The entry <" << full_path
-                          << "> with value <"
-                          << p->second.get<std::string>("value")
-                          << "> has not been declared."
-                          << std::endl;
-                return false;
-              }
+
+            const std::string new_value
+              = p->second.get<std::string>("value");
+            AssertThrow (destination.get_optional<std::string> (full_path)
+                         &&
+                         destination.get_optional<std::string>
+                         (full_path + path_separator + "value"),
+                         ParameterHandler::ExcEntryUndeclared (p->first));
+
+            // first make sure that the new entry actually satisfies its
+            // constraints
+            const unsigned int pattern_index
+              = destination.get<unsigned int> (full_path +
+                                               path_separator +
+                                               "pattern");
+            AssertThrow (patterns[pattern_index]->match(new_value),
+                         ParameterHandler::ExcInvalidEntryForPatternXML
+                         // XML entries sometimes have extra surrounding
+                         // newlines
+                         (Utilities::trim(new_value),
+                          p->first,
+                          patterns[pattern_index]->description()));
+
+            // set the found parameter in the destination argument
+            destination.put (full_path + path_separator + "value",
+                             new_value);
+
+            // this node might have sub-nodes in addition to "value", such as
+            // "default_value", "documentation", etc. we might at some point
+            // in the future want to make sure that if they exist that they
+            // match the ones in the 'destination' tree
           }
         else if (p->second.get_optional<std::string>("alias"))
           {
-            // it is an alias node. alias nodes are static and
-            // there is nothing to do here (but the same applies as
-            // mentioned in the comment above about the static
-            // nodes inside parameter nodes
+            // it is an alias node. alias nodes are static and there is
+            // nothing to do here (but the same applies as mentioned in the
+            // comment above about the static nodes inside parameter nodes
           }
         else
           {
             // it must be a subsection
-            const bool result
-              = read_xml_recursively (p->second,
-                                      (current_path == "" ?
-                                       p->first :
-                                       current_path + path_separator + p->first),
-                                      path_separator,
-                                      patterns,
-                                      destination);
-
-            // see if the recursive read
-            // succeeded. if yes, continue,
-            // otherwise exit now
-            if (result == false)
-              return false;
+            read_xml_recursively (p->second,
+                                  (current_path == "" ?
+                                   p->first :
+                                   current_path + path_separator + p->first),
+                                  path_separator,
+                                  patterns,
+                                  destination);
           }
       }
-
-    return true;
   }
 }
 
 
 
-bool ParameterHandler::read_input_from_xml (std::istream &in)
+bool ParameterHandler::read_input_from_xml(std::istream &in)
+{
+  parse_input_from_xml(in);
+  return true;
+}
+
+
+
+void ParameterHandler::parse_input_from_xml (std::istream &in)
 {
   AssertThrow(in, ExcIO());
   // read the XML tree assuming that (as we
@@ -1873,47 +1844,29 @@ bool ParameterHandler::read_input_from_xml (std::istream &in)
   // a single top-level node called
   // "ParameterHandler"
   boost::property_tree::ptree single_node_tree;
-  try
-    {
-      read_xml (in, single_node_tree);
-    }
-  catch (...)
-    {
-      std::cerr << "This input stream appears not to be valid XML"
-                << std::endl;
-      return false;
-    }
+  // This boost function will raise an exception if this is not a valid XML
+  // file.
+  read_xml (in, single_node_tree);
 
-  // make sure there is a top-level element
+  // make sure there is a single top-level element
   // called "ParameterHandler"
-  if (!single_node_tree.get_optional<std::string>("ParameterHandler"))
-    {
-      std::cerr << "There is no top-level XML element called \"ParameterHandler\"."
-                << std::endl;
-      return false;
-    }
-
-  // ensure that there is only a single
-  // top-level element
-  if (std::distance (single_node_tree.begin(), single_node_tree.end()) != 1)
-    {
-      std::cerr << "The top-level XML element \"ParameterHandler\" is "
-                << "not the only one."
-                << std::endl;
-      std::cerr << "(There are "
-                << std::distance (single_node_tree.begin(),
-                                  single_node_tree.end())
-                << " top-level elements.)"
-                << std::endl;
-      return false;
-    }
+  AssertThrow (single_node_tree.get_optional<std::string>("ParameterHandler"),
+               ExcInvalidXMLParameterFile ("There is no top-level XML element "
+                                           "called \"ParameterHandler\"."));
+
+  const std::size_t n_top_level_elements = std::distance (single_node_tree.begin(),
+                                                          single_node_tree.end());
+  AssertThrow (n_top_level_elements == 1,
+               ExcInvalidXMLParameterFile ("There are "
+                                           + Utilities::to_string(n_top_level_elements)
+                                           + " top-level elements, but there "
+                                           "should only be one."));
 
   // read the child elements recursively
   const boost::property_tree::ptree
   &my_entries = single_node_tree.get_child("ParameterHandler");
 
-  return read_xml_recursively (my_entries, "", path_separator, patterns,
-                               *entries);
+  read_xml_recursively (my_entries, "", path_separator, patterns, *entries);
 }
 
 
index 1e71ed9f1571a443d6724331d6a30ede479aff53..6e4920155262e10e3615cb7d13a42d505225ed01 100644 (file)
@@ -15,7 +15,7 @@
 
 
 
-// check ParameterHandler::read_input_from_xml
+// check ParameterHandler::parse_input_from_xml
 
 #include "../tests.h"
 #include <deal.II/base/logstream.h>
@@ -75,8 +75,7 @@ int main ()
 
   // read from XML
   std::ifstream in (SOURCE_DIR "/prm/parameter_handler_read_xml.prm");
-  bool result = prm.read_input_from_xml (in);
-  AssertThrow (result == true, ExcInternalError());
+  prm.parse_input_from_xml (in);
 
   // write it out again
   prm.print_parameters (deallog.get_file_stream(), ParameterHandler::XML);
index db4199be774e031aea050ae0c948cdc81bba9e30..cedb86b839a2b58fcc90aaba5811c73a385505d0 100644 (file)
@@ -15,7 +15,7 @@
 
 
 
-// check ParameterHandler::read_input_from_xml. try to read a file with a
+// check ParameterHandler::parse_input_from_xml. try to read a file with a
 // parameter that has not been declared
 
 #include "../tests.h"
@@ -76,10 +76,15 @@ int main ()
 
   // read from XML
   std::ifstream in (SOURCE_DIR "/prm/parameter_handler_read_xml_error_01.prm");
-  bool result = prm.read_input_from_xml (in);
-  Assert (result == false, ExcInternalError());
-
-  deallog << "OK" << std::endl;
+  try
+    {
+      prm.parse_input_from_xml (in);
+    }
+  catch (ParameterHandler::ExcEntryUndeclared &exc)
+    {
+      deallog << exc.get_exc_name() << std::endl;
+      exc.print_info(deallog.get_file_stream());
+    }
 
   return 0;
 }
index 0fd8fc12f0b442283edd8868867114c242b04d11..5e12ed85b0e39785423b07230efc98a03991826f 100644 (file)
@@ -1,2 +1,3 @@
 
-DEAL::OK
+DEAL::ParameterHandler::ExcEntryUndeclared (p->first)
+You can't ask for entry <int1234> you have not yet declared.
index 69c3b96844e13be37f3394a3b8baefcd4257d1de..5547725b0d51881b2efe02c726681a1bab1288f4 100644 (file)
@@ -15,7 +15,7 @@
 
 
 
-// check ParameterHandler::read_input_from_xml. try to read a file that is not
+// check ParameterHandler::parse_input_from_xml. try to read a file that is not
 // valid XML (the last end-tag is missing)
 
 #include "../tests.h"
@@ -76,10 +76,15 @@ int main ()
 
   // read from XML
   std::ifstream in (SOURCE_DIR "/prm/parameter_handler_read_xml_error_02.prm");
-  bool result = prm.read_input_from_xml (in);
-  AssertThrow (result == false, ExcInternalError());
-
-  deallog << "OK" << std::endl;
+  try
+    {
+      prm.parse_input_from_xml (in);
+    }
+  catch (const ParameterHandler:: ExcInvalidEntryForPatternXML &exc)
+    {
+      deallog << exc.get_exc_name() << std::endl;
+      exc.print_info(deallog.get_file_stream());
+    }
 
   return 0;
 }
index 0fd8fc12f0b442283edd8868867114c242b04d11..4589349dd1f8625a2f5f67c057b2b69305a414bf 100644 (file)
@@ -1,2 +1,8 @@
 
-DEAL::OK
+DEAL::ParameterHandler::ExcInvalidEntryForPatternXML (Utilities::trim(new_value), p->first, patterns[pattern_index]->description())
+    The entry value
+        __2
+    for the entry named
+        int_2aint
+    does not match the given pattern:
+        [Integer range -2147483648...2147483647 (inclusive)]
index 065d372fbcb90207df388141937772f2e865fcae..bca1ed568e9933a96e55739f4d597e1b52e096a3 100644 (file)
@@ -76,10 +76,15 @@ int main ()
 
   // read from XML
   std::ifstream in (SOURCE_DIR "/prm/parameter_handler_read_xml_error_03.prm");
-  bool result = prm.read_input_from_xml (in);
-  AssertThrow (result == false, ExcInternalError());
-
-  deallog << "OK" << std::endl;
+  try
+    {
+      prm.parse_input_from_xml (in);
+    }
+  catch (const ParameterHandler::ExcInvalidXMLParameterFile &exc)
+    {
+      deallog << exc.get_exc_name() << std::endl;
+      exc.print_info(deallog.get_file_stream());
+    }
 
   return 0;
 }
index 0fd8fc12f0b442283edd8868867114c242b04d11..71bf9d00491a09295d1a60bf3b4a9d5132a86f6b 100644 (file)
@@ -1,2 +1,3 @@
 
-DEAL::OK
+DEAL::ExcInvalidXMLParameterFile ("There are " + Utilities::to_string(n_top_level_elements) + " top-level elements, but there " "should only be one.")
+There are 2 top-level elements, but there should only be one.
index 013643deec565dfa398d29e4f5f0551e400ad970..604ceb30e891ea399b839c693a11f58304ffdb9e 100644 (file)
@@ -15,7 +15,7 @@
 
 
 
-// check ParameterHandler::read_input_from_xml. try to read a file with a
+// check ParameterHandler::parse_input_from_xml. try to read a file with a
 // parameter that does not satisfy its pattern
 
 #include "../tests.h"
@@ -76,10 +76,15 @@ int main ()
 
   // read from XML
   std::ifstream in (SOURCE_DIR "/prm/parameter_handler_read_xml_error_04.prm");
-  bool result = prm.read_input_from_xml (in);
-  AssertThrow (result == false, ExcInternalError());
-
-  deallog << "OK" << std::endl;
+  try
+    {
+      prm.parse_input_from_xml (in);
+    }
+  catch (const ParameterHandler::ExcInvalidEntryForPatternXML &exc)
+    {
+      deallog << exc.get_exc_name() << std::endl;
+      exc.print_info(deallog.get_file_stream());
+    }
 
   return 0;
 }
index 0fd8fc12f0b442283edd8868867114c242b04d11..d93a0cbaf51fe169035a15e92503a2cfe18b8b3b 100644 (file)
@@ -1,2 +1,8 @@
 
-DEAL::OK
+DEAL::ParameterHandler::ExcInvalidEntryForPatternXML (Utilities::trim(new_value), p->first, patterns[pattern_index]->description())
+    The entry value
+        2x
+    for the entry named
+        int1
+    does not match the given pattern:
+        [Integer range -2147483648...2147483647 (inclusive)]

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.