Add missing virtual destructor.
[libdcp.git] / src / xml.cc
index 4ab6a2e7bcd5460009447ff83b5b31ed76b2422a..22e91ac0c872afffc4740d99708adcaebb9d10ec 100644 (file)
@@ -2,6 +2,7 @@
 #include <iostream>
 #include <boost/lexical_cast.hpp>
 #include <boost/filesystem.hpp>
+#include <boost/algorithm/string.hpp>
 #include <libxml++/libxml++.h>
 #include "xml.h"
 #include "exceptions.h"
@@ -24,20 +25,20 @@ XMLNode::XMLNode (xmlpp::Node const * node)
 }
 
 xmlpp::Node *
-XMLNode::xml_node (string name)
+XMLNode::node_child (string name)
 {
-       list<xmlpp::Node*> n = xml_nodes (name);
+       list<xmlpp::Node*> n = node_children (name);
        if (n.size() > 1) {
                throw XMLError ("duplicate XML tag " + name);
        } else if (n.empty ()) {
-               throw XMLError ("missing XML tag " + name);
+               throw XMLError ("missing XML tag " + name + " in " + _node->get_name());
        }
        
        return n.front ();
 }
 
 list<xmlpp::Node*>
-XMLNode::xml_nodes (string name)
+XMLNode::node_children (string name)
 {
        /* XXX: using find / get_path should work here, but I can't follow
           how get_path works.
@@ -57,27 +58,15 @@ XMLNode::xml_nodes (string name)
 }
 
 string
-XMLNode::string_node (string name)
+XMLNode::string_child (string name)
 {
-       xmlpp::Node* node = xml_node (name);
-       
-        xmlpp::Node::NodeList c = node->get_children ();
-       if (c.size() != 1) {
-               throw XMLError ("unexpected content in XML node");
-       }
-       
-        xmlpp::ContentNode const * v = dynamic_cast<xmlpp::ContentNode const *> (c.front());
-       if (!v) {
-               throw XMLError ("missing content in XML node");
-       }
-       
-       return v->get_content ();
+       return XMLNode (node_child (name)).content ();
 }
 
 string
-XMLNode::optional_string_node (string name)
+XMLNode::optional_string_child (string name)
 {
-       list<xmlpp::Node*> nodes = xml_nodes (name);
+       list<xmlpp::Node*> nodes = node_children (name);
        if (nodes.size() > 2) {
                throw XMLError ("duplicate XML tag " + name);
        }
@@ -86,33 +75,143 @@ XMLNode::optional_string_node (string name)
                return "";
        }
 
-       return string_node (name);
+       return string_child (name);
 }
 
 ContentKind
-XMLNode::kind_node (string name)
+XMLNode::kind_child (string name)
 {
-       return content_kind_from_string (string_node (name));
+       return content_kind_from_string (string_child (name));
 }
 
 Fraction
-XMLNode::fraction_node (string name)
+XMLNode::fraction_child (string name)
 {
-       return Fraction (string_node (name));
+       return Fraction (string_child (name));
 }
 
 int64_t
-XMLNode::int64_node (string name)
+XMLNode::int64_child (string name)
+{
+       string s = string_child (name);
+       erase_all (s, " ");
+       return lexical_cast<int64_t> (s);
+}
+
+int64_t
+XMLNode::optional_int64_child (string name)
+{
+       list<xmlpp::Node*> nodes = node_children (name);
+       if (nodes.size() > 2) {
+               throw XMLError ("duplicate XML tag " + name);
+       }
+
+       if (nodes.empty ()) {
+               return 0;
+       }
+
+       return int64_child (name);
+}
+
+float
+XMLNode::float_child (string name)
 {
-       return lexical_cast<int64_t> (string_node (name));
+       return lexical_cast<float> (string_child (name));
 }
 
 void
-XMLNode::ignore_node (string name)
+XMLNode::ignore_child (string name)
 {
        _taken.push_back (name);
 }
 
+Time
+XMLNode::time_attribute (string name)
+{
+       return Time (string_attribute (name));
+}
+
+string
+XMLNode::string_attribute (string name)
+{
+       xmlpp::Element const * e = dynamic_cast<const xmlpp::Element *> (_node);
+       if (!e) {
+               throw XMLError ("missing attribute");
+       }
+       
+       xmlpp::Attribute* a = e->get_attribute (name);
+       if (!a) {
+               throw XMLError ("missing attribute");
+       }
+
+       return a->get_value ();
+}
+
+string
+XMLNode::optional_string_attribute (string name)
+{
+       xmlpp::Element const * e = dynamic_cast<const xmlpp::Element *> (_node);
+       if (!e) {
+               return "";
+       }
+       
+       xmlpp::Attribute* a = e->get_attribute (name);
+       if (!a) {
+               return "";
+       }
+
+       return a->get_value ();
+}
+
+float
+XMLNode::float_attribute (string name)
+{
+       return lexical_cast<float> (string_attribute (name));
+}
+
+int64_t
+XMLNode::int64_attribute (string name)
+{
+       return lexical_cast<int64_t> (string_attribute (name));
+}
+
+int64_t
+XMLNode::optional_int64_attribute (string name)
+{
+       string const s = optional_string_attribute (name);
+       if (s.empty ()) {
+               return 0;
+       }
+       
+       return lexical_cast<int64_t> (s);
+}
+
+optional<bool>
+XMLNode::optional_bool_attribute (string name)
+{
+       string const s = optional_string_attribute (name);
+       if (s.empty ()) {
+               return optional<bool> ();
+       }
+
+       if (s == "1" || s == "yes") {
+               return optional<bool> (true);
+       }
+
+       return optional<bool> (false);
+}
+
+optional<Color>
+XMLNode::optional_color_attribute (string name)
+{
+       string const s = optional_string_attribute (name);
+       if (s.empty ()) {
+               return optional<Color> ();
+       }
+
+       return optional<Color> (Color (s));
+}
+
 void
 XMLNode::done ()
 {
@@ -124,6 +223,22 @@ XMLNode::done ()
        }
 }
 
+string
+XMLNode::content ()
+{
+       string content;
+       
+        xmlpp::Node::NodeList c = _node->get_children ();
+       for (xmlpp::Node::NodeList::const_iterator i = c.begin(); i != c.end(); ++i) {
+               xmlpp::ContentNode const * v = dynamic_cast<xmlpp::ContentNode const *> (*i);
+               if (v) {
+                       content += v->get_content ();
+               }
+       }
+
+       return content;
+}
+
 XMLFile::XMLFile (string file, string root_name)
 {
        if (!filesystem::exists (file)) {