From b29fe3803cbb4523a374686e4b85bd3d73307dd6 Mon Sep 17 00:00:00 2001 From: bangerth Date: Mon, 20 Dec 2010 13:57:15 +0000 Subject: [PATCH] Implement the ability to read XML files of parameters. git-svn-id: https://svn.dealii.org/trunk@23019 0785d39b-7218-0410-832d-ea1e28bc413d --- .../include/deal.II/base/parameter_handler.h | 17 +++ deal.II/source/base/parameter_handler.cc | 141 +++++++++++++++++- tests/bits/parameter_handler_read_xml.cc | 85 +++++++++++ .../parameter_handler_read_xml/cmp/generic | 3 + tests/bits/parameter_handler_read_xml/prm | 4 + 5 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 tests/bits/parameter_handler_read_xml.cc create mode 100644 tests/bits/parameter_handler_read_xml/cmp/generic create mode 100644 tests/bits/parameter_handler_read_xml/prm diff --git a/deal.II/include/deal.II/base/parameter_handler.h b/deal.II/include/deal.II/base/parameter_handler.h index 72b14ce920..c2c90671a0 100644 --- a/deal.II/include/deal.II/base/parameter_handler.h +++ b/deal.II/include/deal.II/base/parameter_handler.h @@ -1746,6 +1746,23 @@ class ParameterHandler : public Subscriptor */ virtual bool read_input_from_string (const char *s); + /** + * Read a parameter file in XML + * format. 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). + * + * Return whether the read was + * successful. + */ + virtual bool read_input_from_xml (std::istream &input); + /** * Clear all contents. */ diff --git a/deal.II/source/base/parameter_handler.cc b/deal.II/source/base/parameter_handler.cc index 04d12d4062..18a4b621c1 100644 --- a/deal.II/source/base/parameter_handler.cc +++ b/deal.II/source/base/parameter_handler.cc @@ -1141,13 +1141,152 @@ bool ParameterHandler::read_input_from_string (const char *s) if (!scan_line (line, lineno)) status = false; - }; + } return status; } +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 + // nodes into the destination object + bool + read_xml_recursively (const boost::property_tree::ptree &source, + const std::string ¤t_path, + const char path_separator, + boost::property_tree::ptree &destination) + { + 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 + if (p->second.get_optional("value")) + { + // 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 (full_path) + && + destination.get_optional (full_path + + path_separator + + "value")) + { + // set the found parameter in + // the destination argument + destination.put (full_path + path_separator + "value", + p->second.get_optional("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("value") + << "> has not been declared."; + return false; + } + } + 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, + destination); + + // see if the recursive read + // succeeded. if yes, continue, + // otherwise exit now + if (result == false) + return false; + } + } + + return true; + } +} + + + +bool ParameterHandler::read_input_from_xml (std::istream &in) +{ + // read the XML tree assuming that (as we + // do in print_parameters(XML) it has only + // 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; + } + + // make sure there is a top-level element + // called "ParameterHandler" + if (!single_node_tree.get_optional("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; + } + + // 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, *entries); +} + + + void ParameterHandler::clear () { entries.reset (new boost::property_tree::ptree()); diff --git a/tests/bits/parameter_handler_read_xml.cc b/tests/bits/parameter_handler_read_xml.cc new file mode 100644 index 0000000000..e32bfac71a --- /dev/null +++ b/tests/bits/parameter_handler_read_xml.cc @@ -0,0 +1,85 @@ +//---------------------------- parameter_handler_read_xml.cc --------------------------- +// $Id$ +// Version: $Name$ +// +// Copyright (C) 2002, 2003, 2004, 2005, 2010 by the deal.II authors +// +// This file is subject to QPL and may not be distributed +// without copyright and license information. Please refer +// to the file deal.II/doc/license.html for the text and +// further information on this license. +// +//---------------------------- parameter_handler_read_xml.cc --------------------------- + + +// check ParameterHandler::print_parameters (..., XML). have a few +// names that contain all sorts of weird (for XML) characters + +#include "../tests.h" +#include +#include +#include + + +int main () +{ + std::ofstream logfile("parameter_handler_read_xml/output"); + deallog.attach(logfile); + deallog.depth_console(0); + deallog.threshold_double(1.e-10); + + ParameterHandler prm; + prm.declare_entry ("int1", + "1", + Patterns::Integer(), + "doc 1"); + prm.declare_entry ("int2", + "2", + Patterns::Integer(), + "doc 2"); + prm.enter_subsection ("ss1"); + { + prm.declare_entry ("double 1", + "1.234", + Patterns::Double(), + "doc 3"); + + prm.enter_subsection ("ss2"); + { + prm.declare_entry ("double 2", + "4.321", + Patterns::Double(), + "doc 4"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + // things with strange characters + prm.enter_subsection ("Testing%testing"); + { + prm.declare_entry ("string&list", + "< & > ; /", + Patterns::Anything(), + "docs 1"); + prm.declare_entry ("int*int", + "2", + Patterns::Integer()); + prm.declare_entry ("double+double", + "6.1415926", + Patterns::Double(), + "docs 3"); + } + prm.leave_subsection (); + + // read from XML + std::ifstream in ("parameter_handler_read_xml/prm"); + bool result = prm.read_input_from_xml (in); + Assert (result == true, ExcInternalError()); + + // write it out again + prm.print_parameters (deallog.get_file_stream(), ParameterHandler::XML); + logfile << std::endl; + + return 0; +} diff --git a/tests/bits/parameter_handler_read_xml/cmp/generic b/tests/bits/parameter_handler_read_xml/cmp/generic new file mode 100644 index 0000000000..c9f5c7e983 --- /dev/null +++ b/tests/bits/parameter_handler_read_xml/cmp/generic @@ -0,0 +1,3 @@ + + + 21doc 10[Integer range -2147483648...2147483647 (inclusive)] 32doc 21[Integer range -2147483648...2147483647 (inclusive)] 2.2341.234doc 32[Double -1.79769e+308...1.79769e+308 (inclusive)] 5.3214.321doc 43[Double -1.79769e+308...1.79769e+308 (inclusive)] __< & > ; /< & > ; /docs 14[Anything] __225[Integer range -2147483648...2147483647 (inclusive)] 7.14159266.1415926docs 36[Double -1.79769e+308...1.79769e+308 (inclusive)] diff --git a/tests/bits/parameter_handler_read_xml/prm b/tests/bits/parameter_handler_read_xml/prm new file mode 100644 index 0000000000..cad7566e20 --- /dev/null +++ b/tests/bits/parameter_handler_read_xml/prm @@ -0,0 +1,4 @@ + + +21doc 10[Integer range -2147483648...2147483647 (inclusive)]32doc 21[Integer range -2147483648...2147483647 (inclusive)]2.2341.234doc 32[Double -1.79769e+308...1.79769e+308 (inclusive)]5.3214.321doc 43[Double -1.79769e+308...1.79769e+308 (inclusive)]__< & > ; /< & > ; /docs 14[Anything]__22 +5[Integer range -2147483648...2147483647 (inclusive)]7.14159266.1415926docs 36[Double -1.79769e+308...1.79769e+308 (inclusive)] -- 2.39.5