Opened 13 years ago

Closed 13 years ago

Last modified 6 years ago

#3828 closed Bugs (fixed)

No way to create smaller json output from property_tree::write_json

Reported by: Michael Anderson <drmikeando@…> Owned by: Sebastian Redl
Milestone: Boost 1.42.0 Component: property_tree
Version: Boost Development Trunk Severity: Problem
Keywords: Cc:

Description

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.

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.

Heres a sample program

#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 );

}

The output is:

    "foo":
    {
        "moo": "12345",
        "zoo": "12345"
    },
    "bar":
    {
        "mork": "hello"
    }
}
{"foo":{"moo":"12345","zoo":"12345"},"bar":{"mork":"hello"}}

And here are the patches required to make it work

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<class Ptree>
+    void write_json_helper_compact(std::basic_ostream<typename Ptree::key_type::value_type> &stream, 
+                           const Ptree &pt)
+    {
+
+        typedef typename Ptree::key_type::value_type Ch;
+        typedef typename std::basic_string<Ch> Str;
+        
+        // Value or object or array
+        if ( pt.empty())
+        {
+            
+            // Write value
+            Str data = create_escapes(pt.template get_value<Str>(), stream.getloc());
+            stream << Ch('"') << data << Ch('"');
+
+        }
+        else if ( pt.count(Str()) == pt.size())
+        {
+                
+            // Write array
+            stream << Ch('[');
+            typename Ptree::const_iterator it = pt.begin();
+            for (; it != pt.end(); ++it)
+            {
+                write_json_helper_compact(stream, it->second);
+                if (boost::next(it) != pt.end())
+                    stream << Ch(',');
+            }
+            stream << Ch(']');
+
+        }
+        else
+        {
+        
+            // Write object
+            stream << Ch('{');
+            typename Ptree::const_iterator it = pt.begin();
+            for (; it != pt.end(); ++it)
+            {
+                stream << Ch('"') << create_escapes(it->first, stream.getloc()) << Ch('"') << Ch(':');
+                write_json_helper_compact(stream, it->second );
+                if (boost::next(it) != pt.end())
+                    stream << Ch(',');
+            }
+            stream << Ch('}');
+        }
+
+    }
+
     // Verify if ptree does not contain information that cannot be written to json
     template<class Ptree>
     bool verify_json(const Ptree &pt, int depth)
@@ -159,6 +208,20 @@
             BOOST_PROPERTY_TREE_THROW(json_parser_error("write error", filename, 0));
     }
 
+    // Write ptree to json stream
+    template<class Ptree>
+    void write_json_compact_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream, 
+                             const Ptree &pt,
+                             const std::string &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 << 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<class Ptree>
+    void write_json_compact(std::basic_ostream<
+                        typename Ptree::key_type::value_type
+                    > &stream,
+                    const Ptree &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<class Ptree>
+    void write_json_compact(const std::string &filename,
+                    const Ptree &pt,
+                    const std::locale &loc = std::locale())
+    {
+        std::basic_ofstream<typename Ptree::key_type::value_type>
+            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;
 } }

Change History (5)

comment:1 by Michael Anderson <drmikeando@…>, 13 years ago

Oops there's an additional

        stream << std::endl;

that should be removed from the patch.

comment:2 by Sebastian Redl, 13 years ago

Resolution: fixed
Status: newclosed

(In [59739]) 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!

comment:3 by anonymous, 10 years ago

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.

Oops there's an additional

stream << std::endl;

that should be removed from the patch.

in reply to:  3 comment:4 by anonymous, 8 years ago

Replying to anonymous:

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.

Oops there's an additional

stream << std::endl;

that should be removed from the patch.

Issue is still present in boost 1.57.

comment:5 by anonymous, 6 years ago

created #12149 about that trailing endl

Note: See TracTickets for help on using tickets.