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