blob: acec34d9dde8f7b15a7337b9681d48ba2e1075bd [file] [log] [blame]
// ----------------------------------------------------------------------------
// Copyright (C) 2007 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_READ_RAPIDXML_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_READ_RAPIDXML_HPP_INCLUDED
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/detail/xml_parser_error.hpp>
#include <boost/property_tree/detail/xml_parser_flags.hpp>
#include <boost/property_tree/detail/xml_parser_utils.hpp>
#include <boost/property_tree/detail/rapidxml.hpp>
#include <vector>
namespace boost { namespace property_tree { namespace xml_parser
{
template<class Ptree, class Ch>
void read_xml_node(detail::rapidxml::xml_node<Ch> *node,
Ptree &pt, int flags)
{
using namespace detail::rapidxml;
switch (node->type())
{
// Element nodes
case node_element:
{
// Create node
Ptree &pt_node = pt.push_back(std::make_pair(node->name(),
Ptree()))->second;
// Copy attributes
if (node->first_attribute())
{
Ptree &pt_attr_root = pt_node.push_back(
std::make_pair(xmlattr<Ch>(), Ptree()))->second;
for (xml_attribute<Ch> *attr = node->first_attribute();
attr; attr = attr->next_attribute())
{
Ptree &pt_attr = pt_attr_root.push_back(
std::make_pair(attr->name(), Ptree()))->second;
pt_attr.data() = attr->value();
}
}
// Copy children
for (xml_node<Ch> *child = node->first_node();
child; child = child->next_sibling())
read_xml_node(child, pt_node, flags);
}
break;
// Data nodes
case node_data:
case node_cdata:
{
if (flags & no_concat_text)
pt.push_back(std::make_pair(xmltext<Ch>(),
Ptree(node->value())));
else
pt.data() += node->value();
}
break;
// Comment nodes
case node_comment:
{
if (!(flags & no_comments))
pt.push_back(std::make_pair(xmlcomment<Ch>(),
Ptree(node->value())));
}
break;
default:
// Skip other node types
break;
}
}
template<class Ptree>
void read_xml_internal(std::basic_istream<
typename Ptree::key_type::value_type> &stream,
Ptree &pt,
int flags,
const std::string &filename)
{
typedef typename Ptree::key_type::value_type Ch;
using namespace detail::rapidxml;
// Load data into vector
stream.unsetf(std::ios::skipws);
std::vector<Ch> v(std::istreambuf_iterator<Ch>(stream.rdbuf()),
std::istreambuf_iterator<Ch>());
if (!stream.good())
BOOST_PROPERTY_TREE_THROW(
xml_parser_error("read error", filename, 0));
v.push_back(0); // zero-terminate
try {
// Parse using appropriate flags
const int f_tws = parse_normalize_whitespace
| parse_trim_whitespace;
const int f_c = parse_comment_nodes;
// Some compilers don't like the bitwise or in the template arg.
const int f_tws_c = parse_normalize_whitespace
| parse_trim_whitespace
| parse_comment_nodes;
xml_document<Ch> doc;
if (flags & no_comments) {
if (flags & trim_whitespace)
doc.BOOST_NESTED_TEMPLATE parse<f_tws>(&v.front());
else
doc.BOOST_NESTED_TEMPLATE parse<0>(&v.front());
} else {
if (flags & trim_whitespace)
doc.BOOST_NESTED_TEMPLATE parse<f_tws_c>(&v.front());
else
doc.BOOST_NESTED_TEMPLATE parse<f_c>(&v.front());
}
// Create ptree from nodes
Ptree local;
for (xml_node<Ch> *child = doc.first_node();
child; child = child->next_sibling())
read_xml_node(child, local, flags);
// Swap local and result ptrees
pt.swap(local);
} catch (parse_error &e) {
long line = static_cast<long>(
std::count(&v.front(), e.where<Ch>(), Ch('\n')) + 1);
BOOST_PROPERTY_TREE_THROW(
xml_parser_error(e.what(), filename, line));
}
}
} } }
#endif