[libxml++] Parser: Add [set|get]_include_default_attributes().



commit 06997287505cb50ec053b216bdc5912e93770a2d
Author: Kjell Ahlstedt <kjell ahlstedt bredband net>
Date:   Fri Aug 2 15:18:26 2013 +0200

    Parser: Add [set|get]_include_default_attributes().
    
    * libxml++/parsers/parser.[h|cc]: Add [set|get]_include_default_attributes()
    and [set|get]_parser_options().
    * examples/dom_parser/main.cc: Add command option -a for testing
    Parser::set_include_default_attributes().
    * examples/dom_read_write/example.dtd:
    * examples/dom_read_write/example.xml: Add an attribute with default value.
    * examples/dom_read_write/main.cc: Add an optional call to
    Parser::set_include_default_attributes(). Bug #701674.

 examples/dom_parser/main.cc         |   27 +++++++++----
 examples/dom_read_write/example.dtd |    1 +
 examples/dom_read_write/example.xml |    2 +-
 examples/dom_read_write/main.cc     |   21 ++++++++++-
 libxml++/parsers/parser.cc          |   70 +++++++++++++++++++++++++++++------
 libxml++/parsers/parser.h           |   52 +++++++++++++++++++++++++-
 6 files changed, 149 insertions(+), 24 deletions(-)
---
diff --git a/examples/dom_parser/main.cc b/examples/dom_parser/main.cc
index 81e32b1..d8dd8c8 100644
--- a/examples/dom_parser/main.cc
+++ b/examples/dom_parser/main.cc
@@ -93,7 +93,12 @@ void print_node(const xmlpp::Node* node, unsigned int indentation = 0)
     const xmlpp::Attribute* attribute = nodeElement->get_attribute("title");
     if(attribute)
     {
-      std::cout << indent << "title = " << CatchConvertError(attribute->get_value()) << std::endl;
+      std::cout << indent;
+      if (dynamic_cast<const xmlpp::AttributeNode*>(attribute))
+        std::cout << "AttributeNode ";
+      else if (dynamic_cast<const xmlpp::AttributeDeclaration*>(attribute))
+        std::cout << "AttributeDeclaration ";
+      std::cout << "title = " << CatchConvertError(attribute->get_value()) << std::endl;
     }
   }
   
@@ -118,6 +123,7 @@ int main(int argc, char* argv[])
   bool set_throw_messages = false;
   bool throw_messages = false;
   bool substitute_entities = true;
+  bool include_default_attributes = false;
 
   int argi = 1;
   while (argc > argi && *argv[argi] == '-') // option
@@ -128,22 +134,26 @@ int main(int argc, char* argv[])
         validate = true;
         break;
       case 't':
-       set_throw_messages = true;
-       throw_messages = true;
-       break;
+        set_throw_messages = true;
+        throw_messages = true;
+        break;
       case 'e':
-       set_throw_messages = true;
-       throw_messages = false;
-       break;
+        set_throw_messages = true;
+        throw_messages = false;
+        break;
       case 'E':
         substitute_entities = false;
         break;
+      case 'a':
+        include_default_attributes = true;
+        break;
      default:
        std::cout << "Usage: " << argv[0] << " [-v] [-t] [-e] [filename]" << std::endl
                  << "       -v  Validate" << std::endl
                  << "       -t  Throw messages in an exception" << std::endl
                  << "       -e  Write messages to stderr" << std::endl
-                 << "       -E  Do not substitute entities" << std::endl;
+                 << "       -E  Do not substitute entities" << std::endl
+                 << "       -a  Include default attributes in the node tree" << std::endl;
        return EXIT_FAILURE;
      }
      argi++;
@@ -163,6 +173,7 @@ int main(int argc, char* argv[])
       parser.set_throw_messages(throw_messages);
     //We can have the text resolved/unescaped automatically.
     parser.set_substitute_entities(substitute_entities);
+    parser.set_include_default_attributes(include_default_attributes);
     parser.parse_file(filepath);
     if(parser)
     {
diff --git a/examples/dom_read_write/example.dtd b/examples/dom_read_write/example.dtd
index 925f074..2b09522 100644
--- a/examples/dom_read_write/example.dtd
+++ b/examples/dom_read_write/example.dtd
@@ -8,6 +8,7 @@ DTD for libxml++ example.
 <!ELEMENT examplechild (child_of_child)+ >
 <!ATTLIST examplechild
   id   CDATA   #REQUIRED
+  title CDATA "No title"

 
 <!ELEMENT child_of_child EMPTY >
diff --git a/examples/dom_read_write/example.xml b/examples/dom_read_write/example.xml
index 95c9305..7037f79 100644
--- a/examples/dom_read_write/example.xml
+++ b/examples/dom_read_write/example.xml
@@ -2,7 +2,7 @@
 <!DOCTYPE example PUBLIC "" "example.dtd">
 
 <example>
-  <examplechild id="1">
+  <examplechild id="1" title="First child element">
     <child_of_child/>
   </examplechild>
   <examplechild id="2">
diff --git a/examples/dom_read_write/main.cc b/examples/dom_read_write/main.cc
index bf7f3fe..9dc4f8c 100644
--- a/examples/dom_read_write/main.cc
+++ b/examples/dom_read_write/main.cc
@@ -35,7 +35,9 @@ main(int argc, char* argv[])
   std::locale::global(std::locale(""));
 
   //Parse command-line arguments:
-  std::string filepath_in, filepath_out;
+  std::string filepath_in;
+  std::string filepath_out;
+  std::string filepath_out2; // With default attributes
   if(argc > 1 )
     filepath_in = argv[1]; //Allow the user to specify a different XML file to parse.
   else
@@ -46,6 +48,10 @@ main(int argc, char* argv[])
   else
     filepath_out = "example_output.xml";
 
+  //Allow the user to specify an extra output file with set_include_default_attributes(true).
+  if(argc > 3 )
+    filepath_out2 = argv[3];
+
   try
   {
     xmlpp::DomParser parser;
@@ -58,6 +64,19 @@ main(int argc, char* argv[])
       if(document)
         document->write_to_file(filepath_out);
     }
+
+    if (!filepath_out2.empty())
+    {
+      parser.set_include_default_attributes();
+      parser.parse_file(filepath_in);
+      if(parser)
+      {
+        //Write it out again.
+        xmlpp::Document* document = parser.get_document();
+        if(document)
+          document->write_to_file(filepath_out2);
+      }
+    }
   }
   catch(const std::exception& ex)
   {
diff --git a/libxml++/parsers/parser.cc b/libxml++/parsers/parser.cc
index 96250a5..e32567e 100644
--- a/libxml++/parsers/parser.cc
+++ b/libxml++/parsers/parser.cc
@@ -20,14 +20,19 @@ namespace // anonymous
 // because it would break ABI.
 struct ExtraParserData
 {
-  // Strange default values chosen for backward compatibility.
+  // Strange default values for throw_*_messages chosen for backward compatibility.
   ExtraParserData()
-  : throw_parser_messages_(false), throw_validity_messages_(true)
+  : throw_parser_messages_(false), throw_validity_messages_(true),
+  include_default_attributes_(false), set_options_(0), clear_options_(0)
   {}
+
   Glib::ustring parser_error_;
   Glib::ustring parser_warning_;
   bool throw_parser_messages_;
   bool throw_validity_messages_;
+  bool include_default_attributes_;
+  int set_options_;
+  int clear_options_;
 };
 
 std::map<const xmlpp::Parser*, ExtraParserData> extra_parser_data;
@@ -99,15 +104,54 @@ bool Parser::get_throw_messages() const
   return extra_parser_data[this].throw_parser_messages_;
 }
 
+void Parser::set_include_default_attributes(bool val)
+{
+  Glib::Threads::Mutex::Lock lock(extra_parser_data_mutex);
+  extra_parser_data[this].include_default_attributes_ = val;
+}
+
+bool Parser::get_include_default_attributes()
+{
+  Glib::Threads::Mutex::Lock lock(extra_parser_data_mutex);
+  return extra_parser_data[this].include_default_attributes_;
+}
+
+void Parser::set_parser_options(int set_options, int clear_options)
+{
+  Glib::Threads::Mutex::Lock lock(extra_parser_data_mutex);
+  extra_parser_data[this].set_options_ = set_options;
+  extra_parser_data[this].clear_options_ = clear_options;
+}
+
+void Parser::get_parser_options(int& set_options, int& clear_options)
+{
+  Glib::Threads::Mutex::Lock lock(extra_parser_data_mutex);
+  set_options = extra_parser_data[this].set_options_;
+  clear_options = extra_parser_data[this].clear_options_;
+}
+
 void Parser::initialize_context()
 {
+  Glib::Threads::Mutex::Lock lock(extra_parser_data_mutex);
+
+  //Clear these temporary buffers:
+  extra_parser_data[this].parser_error_.erase();
+  extra_parser_data[this].parser_warning_.erase();
+  validate_error_.erase();
+  validate_warning_.erase();
+
+  // Take a copy of the extra data, so we don't have to access
+  // the extra_parser_data map more than necessary.
+  const ExtraParserData extra_parser_data_this = extra_parser_data[this];
+  lock.release();
+
   //Disactivate any non-standards-compliant libxml1 features.
   //These are disactivated by default, but if we don't deactivate them for each context
   //then some other code which uses a global function, such as xmlKeepBlanksDefault(),
   // could cause this to use the wrong settings:
   context_->linenumbers = 1; // TRUE - This is the default anyway.
 
-  //Turn on/off validation and entity substitution.
+  //Turn on/off validation, entity substitution and default attribute inclusion.
   int options = context_->options;
   if (validate_)
     options |= XML_PARSE_DTDVALID;
@@ -119,10 +163,18 @@ void Parser::initialize_context()
   else
     options &= ~XML_PARSE_NOENT;
 
+  if (extra_parser_data_this.include_default_attributes_)
+    options |= XML_PARSE_DTDATTR;
+  else
+    options &= ~XML_PARSE_DTDATTR;
+
+  //Turn on/off any parser options.
+  options |= extra_parser_data_this.set_options_;
+  options &= ~extra_parser_data_this.clear_options_;
+
   xmlCtxtUseOptions(context_, options);
 
-  Glib::Threads::Mutex::Lock lock(extra_parser_data_mutex);
-  if (context_->sax && extra_parser_data[this].throw_parser_messages_)
+  if (context_->sax && extra_parser_data_this.throw_parser_messages_)
   {
     //Tell the parser context about the callbacks.
     context_->sax->fatalError = &callback_parser_error;
@@ -130,7 +182,7 @@ void Parser::initialize_context()
     context_->sax->warning = &callback_parser_warning;
   }
 
-  if (extra_parser_data[this].throw_validity_messages_)
+  if (extra_parser_data_this.throw_validity_messages_)
   {
     //Tell the validity context about the callbacks:
     //(These are only called if validation is on - see above)
@@ -140,12 +192,6 @@ void Parser::initialize_context()
 
   //Allow the callback_validity_*() methods to retrieve the C++ instance:
   context_->_private = this;
-
-  //Clear these temporary buffers too:
-  extra_parser_data[this].parser_error_.erase();
-  extra_parser_data[this].parser_warning_.erase();
-  validate_error_.erase();
-  validate_warning_.erase();
 }
 
 void Parser::release_underlying()
diff --git a/libxml++/parsers/parser.h b/libxml++/parsers/parser.h
index f2c2f3f..66297de 100644
--- a/libxml++/parsers/parser.h
+++ b/libxml++/parsers/parser.h
@@ -42,7 +42,7 @@ public:
    */
   virtual void set_validate(bool val = true);
 
-  /** See set_validate()
+  /** See set_validate().
    * @returns Whether the parser will validate the XML file.
    */
   virtual bool get_validate() const;
@@ -83,7 +83,51 @@ public:
    *          The default with only validation messages thrown is returned as false.
    */
   bool get_throw_messages() const;
-  
+
+  /** Set whether default attribute values from the DTD shall be included in the node tree.
+   * If set, attributes not assigned a value in the XML file, but with a default value
+   * in the DTD file, will be included in the node tree that the parser creates.
+   * These attributes will be represented by AttributeNode instances (not AttributeDeclaration
+   * instances), just like attributes which are assigned a value in the XML file.
+   *
+   * @newin{2,38}
+   *
+   * @param val Whether attributes with default values will be included in the node tree.
+   */
+  void set_include_default_attributes(bool val = true);
+
+  /** See set_include_default_attributes().
+   *
+   * @newin{2,38}
+   *
+   * @returns Whether attributes with default values will be included in the node tree.
+   */
+  bool get_include_default_attributes();
+
+  /** Set and/or clear parser option flags.
+   * See the libxml2 documentation, enum xmlParserOption, for a list of parser options.
+   * This method overrides other methods that set parser options, such as set_validate(),
+   * set_substitute_entities() and set_include_default_attributes(). Use set_parser_options()
+   * only if no other method can set the parser options you want.
+   *
+   * @newin{2,38}
+   *
+   * @param set_options Set bits correspond to flags that shall be set during parsing.
+   * @param clear_options Set bits correspond to flags that shall be cleared during parsing.
+   *        Bits that are set in neither @a set_options nor @a clear_options are not affected.
+   */
+  void set_parser_options(int set_options = 0, int clear_options = 0);
+
+  /** See set_parser_options().
+   *
+   * @newin{2,38}
+   *
+   * @param [out] set_options Set bits correspond to flags that shall be set during parsing.
+   * @param [out] clear_options Set bits correspond to flags that shall be cleared during parsing.
+   *        Bits that are set in neither @a set_options nor @a clear_options are not affected.
+   */
+  void get_parser_options(int& set_options, int& clear_options);
+
   /** Parse an XML document from a file.
    * @throw exception
    * @param filename The path to the file.
@@ -149,6 +193,10 @@ protected:
 
   bool validate_;
   bool substitute_entities_;
+  //TODO: In a future ABI-break, add these members.
+  //bool include_default_attributes_;
+  //int set_options_;
+  //int clear_options_;
 };
 
 } // namespace xmlpp


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