1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2007 Marcin Kalicinski
3 //
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // For more information, see www.boost.org
9 // ----------------------------------------------------------------------------
10 #ifndef BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_READ_RAPIDXML_HPP_INCLUDED
11 #define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_READ_RAPIDXML_HPP_INCLUDED
12 
13 #include <boost/property_tree/ptree.hpp>
14 #include <boost/property_tree/detail/xml_parser_error.hpp>
15 #include <boost/property_tree/detail/xml_parser_flags.hpp>
16 #include <boost/property_tree/detail/xml_parser_utils.hpp>
17 #include <boost/property_tree/detail/rapidxml.hpp>
18 #include <vector>
19 
20 namespace boost { namespace property_tree { namespace xml_parser
21 {
22 
23     template<class Ptree, class Ch>
read_xml_node(detail::rapidxml::xml_node<Ch> * node,Ptree & pt,int flags)24     void read_xml_node(detail::rapidxml::xml_node<Ch> *node,
25                        Ptree &pt, int flags)
26     {
27         using namespace detail::rapidxml;
28         switch (node->type())
29         {
30             // Element nodes
31             case node_element:
32             {
33                 // Create node
34                 Ptree &pt_node = pt.push_back(std::make_pair(node->name(),
35                                                              Ptree()))->second;
36 
37                 // Copy attributes
38                 if (node->first_attribute())
39                 {
40                     Ptree &pt_attr_root = pt_node.push_back(
41                         std::make_pair(xmlattr<typename Ptree::key_type>(), Ptree()))->second;
42                     for (xml_attribute<Ch> *attr = node->first_attribute();
43                          attr; attr = attr->next_attribute())
44                     {
45                         Ptree &pt_attr = pt_attr_root.push_back(
46                             std::make_pair(attr->name(), Ptree()))->second;
47                         pt_attr.data() = typename Ptree::key_type(attr->value(), attr->value_size());
48                     }
49                 }
50 
51                 // Copy children
52                 for (xml_node<Ch> *child = node->first_node();
53                      child; child = child->next_sibling())
54                     read_xml_node(child, pt_node, flags);
55             }
56             break;
57 
58             // Data nodes
59             case node_data:
60             case node_cdata:
61             {
62                 if (flags & no_concat_text)
63                     pt.push_back(std::make_pair(xmltext<typename Ptree::key_type>(),
64                                                 Ptree(node->value())));
65                 else
66                     pt.data() += typename Ptree::key_type(node->value(), node->value_size());
67             }
68             break;
69 
70             // Comment nodes
71             case node_comment:
72             {
73                 if (!(flags & no_comments))
74                     pt.push_back(std::make_pair(xmlcomment<typename Ptree::key_type>(),
75                                     Ptree(typename Ptree::key_type(node->value(), node->value_size()))));
76             }
77             break;
78 
79             default:
80                 // Skip other node types
81                 break;
82         }
83     }
84 
85     template<class Ptree>
read_xml_internal(std::basic_istream<typename Ptree::key_type::value_type> & stream,Ptree & pt,int flags,const std::string & filename)86     void read_xml_internal(std::basic_istream<
87                                typename Ptree::key_type::value_type> &stream,
88                            Ptree &pt,
89                            int flags,
90                            const std::string &filename)
91     {
92         typedef typename Ptree::key_type::value_type Ch;
93         using namespace detail::rapidxml;
94 
95         // Load data into vector
96         stream.unsetf(std::ios::skipws);
97         std::vector<Ch> v(std::istreambuf_iterator<Ch>(stream.rdbuf()),
98                           std::istreambuf_iterator<Ch>());
99         if (!stream.good())
100             BOOST_PROPERTY_TREE_THROW(
101                 xml_parser_error("read error", filename, 0));
102         v.push_back(0); // zero-terminate
103 
104         try {
105             // Parse using appropriate flags
106             const int f_tws = parse_normalize_whitespace
107                             | parse_trim_whitespace;
108             const int f_c = parse_comment_nodes;
109             // Some compilers don't like the bitwise or in the template arg.
110             const int f_tws_c = parse_normalize_whitespace
111                               | parse_trim_whitespace
112                               | parse_comment_nodes;
113             xml_document<Ch> doc;
114             if (flags & no_comments) {
115                 if (flags & trim_whitespace)
116                     doc.BOOST_NESTED_TEMPLATE parse<f_tws>(&v.front());
117                 else
118                     doc.BOOST_NESTED_TEMPLATE parse<0>(&v.front());
119             } else {
120                 if (flags & trim_whitespace)
121                     doc.BOOST_NESTED_TEMPLATE parse<f_tws_c>(&v.front());
122                 else
123                     doc.BOOST_NESTED_TEMPLATE parse<f_c>(&v.front());
124             }
125 
126             // Create ptree from nodes
127             Ptree local;
128             for (xml_node<Ch> *child = doc.first_node();
129                  child; child = child->next_sibling())
130                 read_xml_node(child, local, flags);
131 
132             // Swap local and result ptrees
133             pt.swap(local);
134         } catch (parse_error &e) {
135             long line = static_cast<long>(
136                 std::count(&v.front(), e.where<Ch>(), Ch('\n')) + 1);
137             BOOST_PROPERTY_TREE_THROW(
138                 xml_parser_error(e.what(), filename, line));
139         }
140     }
141 
142 } } }
143 
144 #endif
145