fix doc example typo
[boost.git] / boost / property_tree / detail / json_parser_write.hpp
blobc5609eee1c1ae85574039bd80427e545a1928421
1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2002-2006 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_JSON_PARSER_WRITE_HPP_INCLUDED
11 #define BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_WRITE_HPP_INCLUDED
13 #include <boost/property_tree/ptree.hpp>
14 #include <boost/next_prior.hpp>
15 #include <string>
16 #include <ostream>
17 #include <iomanip>
19 namespace boost { namespace property_tree { namespace json_parser
22 // Create necessary escape sequences from illegal characters
23 template<class Ch>
24 std::basic_string<Ch> create_escapes(const std::basic_string<Ch> &s,
25 const std::locale &loc)
27 std::basic_string<Ch> result;
28 typename std::basic_string<Ch>::const_iterator b = s.begin();
29 typename std::basic_string<Ch>::const_iterator e = s.end();
30 while (b != e)
32 if (*b == Ch('\0')) result += Ch('\\'), result += Ch('0');
33 else if (*b == Ch('\b')) result += Ch('\\'), result += Ch('b');
34 else if (*b == Ch('\f')) result += Ch('\\'), result += Ch('f');
35 else if (*b == Ch('\n')) result += Ch('\\'), result += Ch('n');
36 else if (*b == Ch('\r')) result += Ch('\\'), result += Ch('r');
37 else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"');
38 else if (*b == Ch('\\')) result += Ch('\\'), result += Ch('\\');
39 else
41 if (std::isprint(*b, loc))
42 result += *b;
43 else
45 const char *hexdigits = "0123456789ABCDEF";
46 unsigned long u = (std::min)(static_cast<unsigned long>(*b), 0xFFFFul);
47 int d1 = u / 4096; u -= d1 * 4096;
48 int d2 = u / 256; u -= d2 * 256;
49 int d3 = u / 16; u -= d3 * 16;
50 int d4 = u;
51 result += Ch('\\'); result += Ch('u');
52 result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]);
53 result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]);
56 ++b;
58 return result;
61 template<class Ptree>
62 void write_json_helper(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
63 const Ptree &pt,
64 int indent)
67 typedef typename Ptree::key_type::value_type Ch;
68 typedef typename std::basic_string<Ch> Str;
70 // Value or object or array
71 if (indent > 0 && pt.empty())
74 // Write value
75 Str data = create_escapes(pt.template get_value<Str>(), stream.getloc());
76 stream << Ch('"') << data << Ch('"');
79 else if (indent > 0 && pt.count(Str()) == pt.size())
82 // Write array
83 stream << Ch('[') << Ch('\n');
84 typename Ptree::const_iterator it = pt.begin();
85 for (; it != pt.end(); ++it)
87 stream << Str(4 * (indent + 1), Ch(' '));
88 write_json_helper(stream, it->second, indent + 1);
89 if (boost::next(it) != pt.end())
90 stream << Ch(',');
91 stream << Ch('\n');
93 stream << Str(4 * indent, Ch(' ')) << Ch(']');
96 else
99 // Write object
100 stream << Ch('{') << Ch('\n');
101 typename Ptree::const_iterator it = pt.begin();
102 for (; it != pt.end(); ++it)
104 stream << Str(4 * (indent + 1), Ch(' '));
105 stream << Ch('"') << create_escapes(it->first, stream.getloc()) << Ch('"') << Ch(':');
106 if (it->second.empty())
107 stream << Ch(' ');
108 else
109 stream << Ch('\n') << Str(4 * (indent + 1), Ch(' '));
110 write_json_helper(stream, it->second, indent + 1);
111 if (boost::next(it) != pt.end())
112 stream << Ch(',');
113 stream << Ch('\n');
115 stream << Str(4 * indent, Ch(' ')) << Ch('}');
121 // Verify if ptree does not contain information that cannot be written to json
122 template<class Ptree>
123 bool verify_json(const Ptree &pt, int depth)
126 typedef typename Ptree::key_type::value_type Ch;
127 typedef typename std::basic_string<Ch> Str;
129 // Root ptree cannot have data
130 if (depth == 0 && !pt.template get_value<Str>().empty())
131 return false;
133 // Ptree cannot have both children and data
134 if (!pt.template get_value<Str>().empty() && !pt.empty())
135 return false;
137 // Check children
138 typename Ptree::const_iterator it = pt.begin();
139 for (; it != pt.end(); ++it)
140 if (!verify_json(it->second, depth + 1))
141 return false;
143 // Success
144 return true;
148 // Write ptree to json stream
149 template<class Ptree>
150 void write_json_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
151 const Ptree &pt,
152 const std::string &filename)
154 if (!verify_json(pt, 0))
155 BOOST_PROPERTY_TREE_THROW(json_parser_error("ptree contains data that cannot be represented in JSON format", filename, 0));
156 write_json_helper(stream, pt, 0);
157 stream << std::endl;
158 if (!stream.good())
159 BOOST_PROPERTY_TREE_THROW(json_parser_error("write error", filename, 0));
162 } } }
164 #endif