OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-atomspace-storage / opencog / persist / json / EncodeJson.cc

210 lines · cc ref:
/*
 * EncodeJson.cc
 * Encode Atoms and Values in a JSON format.
 *
 * Copyright (c) 2019, 2021 Linas Vepstas <linas@linas.org>
 * SPDX-License-Identifier: AGPL-3.0-or-later
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include <iomanip>

#include <opencog/atoms/base/Atom.h>
#include <opencog/atoms/value/FloatValue.h>
#include <opencog/atoms/value/LinkValue.h>
#include <opencog/atoms/value/StringValue.h>
#include <opencog/atoms/value/ValueFactory.h>
#include <opencog/atomspace/AtomSpace.h>

#include "Json.h"

using namespace opencog;

/* ================================================================== */
// Atom printers that do NOT print associated Values.

static std::string prt_node(const Handle& h, const std::string& indent)
{
	std::stringstream ss;
	ss << indent << "{\n" << indent << "  \"type\": \""
		<< nameserver().getTypeName(h->get_type())
		<< "\",\n" << indent << "  \"name\": ";
	ss << std::quoted(h->get_name());
	ss << "\n" << indent << "}";

	return ss.str();
}

static std::string prt_atom(const Handle&, const std::string& = "");

static std::string prt_link(const Handle& h, const std::string& indent)
{
	std::string idt = indent + "  ";
	std::string txt = indent + "{\n" + idt + "\"type\": \""
		+ nameserver().getTypeName(h->get_type()) + "\",\n"
		+ idt + "\"outgoing\": [\n";

	bool first = true;
	for (const Handle& ho : h->getOutgoingSet())
	{
		if (not first) { txt += ",\n"; } else { first = false; }
		txt += prt_atom(ho, idt + "  ");
	}
	txt += "]}";
	return txt;
}

static std::string prt_atom(const Handle& h, const std::string& indent)
{
	if (h->is_node()) return prt_node(h, indent);
	return prt_link(h, indent);
}

/// Convert the Atom into a string. It does NOT print any of the
/// associated values; use `dump_atom()` to get those.
std::string Json::encode_atom(const Handle& h, const std::string& indent)
{
	return prt_atom(h, indent);
}

/* ================================================================== */
// Same as above, for for printing values.

/// Convert value (or Atom) into a string.
std::string Json::encode_value(const ValuePtr& v, const std::string& indent)
{
	// Empty values are used to erase keys from atoms.
	if (nullptr == v) return "false";

	if (v->is_atom())
		return prt_atom(HandleCast(v));

	std::string idt = indent + "  ";
	std::string txt = indent + "{\n" + idt + "\"type\": \""
		+ nameserver().getTypeName(v->get_type()) + "\",\n"
		+ idt + "\"value\": [";

	Type typ = v->get_type();
	if (nameserver().isA(typ, FLOAT_VALUE))
	{
		// The FloatValue to_string() method prints out
		// plenty of digits, enough for high-precision.
		FloatValuePtr fv(FloatValueCast(v));
		const std::vector<double>& fl = fv->value();
		bool first = true;
		for (double d : fl)
		{
			if (not first) txt += ", ";
			txt += std::to_string(d);
			first = false;
		}
	}

	else
	if (nameserver().isA(typ, STRING_VALUE))
	{
		StringValuePtr sv(StringValueCast(v));
		const std::vector<std::string>& sl = sv->value();
		bool first = true;
		for (const std::string& s : sl)
		{
			if (not first) txt += ", ";

			// Escape quotes
			std::stringstream ss;
			ss << std::quoted(s);
			txt += ss.str();
			first = false;
		}
	}

	else
	if (nameserver().isA(typ, LINK_VALUE))
	{
		LinkValuePtr lv(LinkValueCast(v));
		const std::vector<ValuePtr>& ll = lv->value();
		bool first = true;
		for (const ValuePtr& vp : ll)
		{
			if (not first) txt += ", ";
			txt += encode_value(vp);
			first = false;
		}
	}

	else
	if (nameserver().isA(typ, BOOL_VALUE))
	{
		BoolValuePtr bv(BoolValueCast(v));
		txt += "\"";
		txt += bv->hex_string();
		txt += "\"";
	}

	else
	if (nameserver().isA(typ, VOID_VALUE))
	{
		txt += "\"\"";
	}

	else
	{
		txt += "\"Error: don't know how to print this\"";
	}

	txt += "]}";
	return txt;
}

/* ================================================================== */

/// Get all of the values on an Atom and print them as an
/// association list.
std::string Json::encode_atom_values(const Handle& h)
{
	if (nullptr == h) return "[]\n";
	std::stringstream rv;

	rv << "[\n";
	bool first = true;
	for (const Handle& key: h->getKeys())
	{
		if (not first) { rv << ",\n"; } else { first = false; }
		rv << "  {\n";
		rv << "    \"key\": " << encode_atom(key, "    ") << ",\n";
		rv << "    \"value\": ";
		ValuePtr p = h->getValue(key);
		rv << encode_value(p, "    ") << "}";
	}
	rv << "]\n";
	return rv.str();
}

std::string Json::encode_type_list(const std::vector<Type>& tlist)
{
	std::string rv = "[";
	bool first = true;
	for (const Type& t: tlist)
	{
		if (not first) { rv += ", "; } else { first = false; }
		rv += "\"" + nameserver().getTypeName(t) + "\"";
	}
	rv += "]\n";
	return rv;
}

/* ============================= END OF FILE ================= */