Boost C++ Libraries: Ticket #3828: No way to create smaller json output from property_tree::write_json https://svn.boost.org/trac10/ticket/3828 <p> The current implementation of write_json is filled with whitespace and newlines. This makes it very nice for human readability, but not so nice for sending over the network. </p> <p> It would be nice to have a way to write compact JSON. I've implemented stripped down versions of the JSON writer that does this, however there is a heap of common code between this version and the non-compact version that could/should be factored out. </p> <p> Heres a sample program </p> <pre class="wiki">#include "boost/property_tree/json_parser.hpp" #include "boost/array.hpp" boost::property_tree::ptree foo() { boost::property_tree::ptree retval; retval.put("moo","12345"); retval.put("zoo",12345); return retval; } boost::property_tree::ptree bar() { boost::property_tree::ptree retval; retval.put("mork","hello"); return retval; } int main() { // std::stringstream ss; boost::property_tree::ptree pt; pt.put_child("foo", foo() ); pt.put_child("bar", bar() ); boost::property_tree::write_json(std::cout, pt ); boost::property_tree::write_json_compact(std::cout, pt ); } </pre><p> The output is: </p> <pre class="wiki"> "foo": { "moo": "12345", "zoo": "12345" }, "bar": { "mork": "hello" } } {"foo":{"moo":"12345","zoo":"12345"},"bar":{"mork":"hello"}} </pre><p> And here are the patches required to make it work </p> <pre class="wiki">Index: boost/property_tree/detail/json_parser_write.hpp =================================================================== --- boost/property_tree/detail/json_parser_write.hpp (revision 58794) +++ boost/property_tree/detail/json_parser_write.hpp (working copy) @@ -118,6 +117,56 @@ } + template&lt;class Ptree&gt; + void write_json_helper_compact(std::basic_ostream&lt;typename Ptree::key_type::value_type&gt; &amp;stream, + const Ptree &amp;pt) + { + + typedef typename Ptree::key_type::value_type Ch; + typedef typename std::basic_string&lt;Ch&gt; Str; + + // Value or object or array + if ( pt.empty()) + { + + // Write value + Str data = create_escapes(pt.template get_value&lt;Str&gt;(), stream.getloc()); + stream &lt;&lt; Ch('"') &lt;&lt; data &lt;&lt; Ch('"'); + + } + else if ( pt.count(Str()) == pt.size()) + { + + // Write array + stream &lt;&lt; Ch('['); + typename Ptree::const_iterator it = pt.begin(); + for (; it != pt.end(); ++it) + { + write_json_helper_compact(stream, it-&gt;second); + if (boost::next(it) != pt.end()) + stream &lt;&lt; Ch(','); + } + stream &lt;&lt; Ch(']'); + + } + else + { + + // Write object + stream &lt;&lt; Ch('{'); + typename Ptree::const_iterator it = pt.begin(); + for (; it != pt.end(); ++it) + { + stream &lt;&lt; Ch('"') &lt;&lt; create_escapes(it-&gt;first, stream.getloc()) &lt;&lt; Ch('"') &lt;&lt; Ch(':'); + write_json_helper_compact(stream, it-&gt;second ); + if (boost::next(it) != pt.end()) + stream &lt;&lt; Ch(','); + } + stream &lt;&lt; Ch('}'); + } + + } + // Verify if ptree does not contain information that cannot be written to json template&lt;class Ptree&gt; bool verify_json(const Ptree &amp;pt, int depth) @@ -159,6 +208,20 @@ BOOST_PROPERTY_TREE_THROW(json_parser_error("write error", filename, 0)); } + // Write ptree to json stream + template&lt;class Ptree&gt; + void write_json_compact_internal(std::basic_ostream&lt;typename Ptree::key_type::value_type&gt; &amp;stream, + const Ptree &amp;pt, + const std::string &amp;filename) + { + if (!verify_json(pt, 0)) + BOOST_PROPERTY_TREE_THROW(json_parser_error("ptree contains data that cannot be represented in JSON format", filename, 0)); + write_json_helper_compact(stream, pt); + stream &lt;&lt; std::endl; + if (!stream.good()) + BOOST_PROPERTY_TREE_THROW(json_parser_error("write error", filename, 0)); + } + } } } #endif Index: boost/property_tree/json_parser.hpp =================================================================== --- boost/property_tree/json_parser.hpp (revision 58794) +++ boost/property_tree/json_parser.hpp (working copy) @@ -121,12 +121,61 @@ write_json_internal(stream, pt, filename); } + /** + * Translates the property tree to JSON and writes it in a compact form to + * the given output stream. + * @note Any property tree key containing only unnamed subkeys will be + * rendered as JSON arrays. + * @pre @e pt cannot contain keys that have both subkeys and non-empty data. + * @throw json_parser_error In case of error translating the property tree + * to JSON or writing to the output stream. + * @param stream The stream to which to write the JSON representation of the + * property tree. + * @param pt The property tree to tranlsate to JSON and output. + */ + template&lt;class Ptree&gt; + void write_json_compact(std::basic_ostream&lt; + typename Ptree::key_type::value_type + &gt; &amp;stream, + const Ptree &amp;pt) + { + write_json_compact_internal(stream, pt, std::string()); + } + + /** + * Translates the property tree to JSON and writes it in a compact style to + * the given file. + * @note Any property tree key containing only unnamed subkeys will be + * rendered as JSON arrays. + * @pre @e pt cannot contain keys that have both subkeys and non-empty data. + * @throw json_parser_error In case of error translating the property tree + * to JSON or writing to the file. + * @param filename The name of the file to which to write the JSON + * representation of the property tree. + * @param pt The property tree to translate to JSON and output. + * @param loc The locale to use when writing out to the output file. + */ + template&lt;class Ptree&gt; + void write_json_compact(const std::string &amp;filename, + const Ptree &amp;pt, + const std::locale &amp;loc = std::locale()) + { + std::basic_ofstream&lt;typename Ptree::key_type::value_type&gt; + stream(filename.c_str()); + if (!stream) + BOOST_PROPERTY_TREE_THROW(json_parser_error( + "cannot open file", filename, 0)); + stream.imbue(loc); + write_json_compact_internal(stream, pt, filename); + } + } } } namespace boost { namespace property_tree { using json_parser::read_json; using json_parser::write_json; + using json_parser::write_json_compact; using json_parser::json_parser_error; } } </pre><p> </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/3828 Trac 1.4.3 Michael Anderson <drmikeando@…> Sat, 09 Jan 2010 11:35:48 GMT <link>https://svn.boost.org/trac10/ticket/3828#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3828#comment:1</guid> <description> <p> Oops there's an additional </p> <pre class="wiki"> stream &lt;&lt; std::endl; </pre><p> that should be removed from the patch. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Sebastian Redl</dc:creator> <pubDate>Wed, 17 Feb 2010 18:55:13 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/3828#comment:2 https://svn.boost.org/trac10/ticket/3828#comment:2 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> (In <a class="changeset" href="https://svn.boost.org/trac10/changeset/59739" title="Give the JSON writer the ability to NOT pretty-print, but instead ...">[59739]</a>) Give the JSON writer the ability to NOT pretty-print, but instead produce compact code. Fixes bug 3828. But I still have to write test cases for the JSON writer; there aren't ANY! </p> Ticket anonymous Thu, 26 Jul 2012 07:38:43 GMT <link>https://svn.boost.org/trac10/ticket/3828#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3828#comment:3</guid> <description> <p> dear boost, in 1.50 release, compact JSON *almost* works correctly, there's still an additional newline that's harmful, just like the previous comment says. </p> <blockquote> <p> Oops there's an additional </p> </blockquote> <p> </p> <blockquote> <blockquote> <p> <code> stream &lt;&lt; std::endl; </code> </p> </blockquote> <p> that should be removed from the patch. </p> </blockquote> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Thu, 12 Mar 2015 19:48:18 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3828#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3828#comment:4</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/3828#comment:3" title="Comment 3">anonymous</a>: </p> <blockquote class="citation"> <p> dear boost, in 1.50 release, compact JSON *almost* works correctly, there's still an additional newline that's harmful, just like the previous comment says. </p> <blockquote> <p> Oops there's an additional </p> </blockquote> <p> </p> <blockquote> <blockquote> <p> <code> stream &lt;&lt; std::endl; </code> </p> </blockquote> <p> that should be removed from the patch. </p> </blockquote> </blockquote> <p> Issue is still present in boost 1.57. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Fri, 22 Apr 2016 16:28:12 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3828#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3828#comment:5</guid> <description> <p> created <a class="new ticket" href="https://svn.boost.org/trac10/ticket/12149" title="#12149: Bugs: boost::property_tree::write_json(stream, root, /*pretty=*/false) ... (new)">#12149</a> about that trailing endl </p> </description> <category>Ticket</category> </item> </channel> </rss>