diff --git a/examples/traverse.cpp b/examples/traverse.cpp index 5f3052d..0fe2e18 100644 --- a/examples/traverse.cpp +++ b/examples/traverse.cpp @@ -14,7 +14,6 @@ // C-style libraries used here to keep it close to traverse.c #include #include -#include // ************************************************************************* // JSON-style @@ -121,6 +120,39 @@ void json_print_opt(const char* label, const std::vector& v, } } +// for optional map-data (extra props) +template +void json_print_opt(const char* label, const std::map& m, + int indent, bool last = false) { + if (!mmtf::isDefaultValue(m)) { + printf("%s: {", label); + typename std::map::const_iterator it; + for (it = m.begin(); it != m.end(); ++it) { + if (it != m.begin()) printf(","); + printf("\n%*s\"%s\": null", indent+1, " ", it->first.c_str()); + } + printf("\n%*s%s\n", indent+1, "}", (last) ? "" : ","); + } else { + printf("%s: null%s\n", label, (last) ? "" : ","); + } +} + +// define how to print vectors of chars (hard-coded) +// -> either list of numbers or converted to strings +void json_print_opt_chars(const char* label, + const std::vector& vec, bool last = false) { + // v1: use numbers + // printopt(label, "%d", vec, last); + // v2: convert to string first + std::vector tmp; + tmp.reserve(vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + if (vec[i] == 0x00) tmp.push_back(std::string()); + else tmp.push_back(std::string(1, vec[i])); + } + printopt(label, "\"%s\"", tmp, last); +} + // just aimed for ncsOperatorList template<> void json_print(const std::vector& list) { @@ -159,6 +191,7 @@ void json_print(const mmtf::GroupType& group) { printf(" {\n"); printreq(" \"formalChargeList\"", "%d", group.formalChargeList); printreq(" \"atomNameList\"", "\"%s\"", group.atomNameList); + printreq(" \"elementList\"", "\"%s\"", group.elementList); printopt(" \"bondAtomList\"", "%d", group.bondAtomList); printopt(" \"bondOrderList\"", "%d", group.bondOrderList); printopt(" \"bondResonanceList\"", "%d", group.bondResonanceList); @@ -184,7 +217,7 @@ void json_print(const mmtf::StructureData& example) { printopt(" \"depositionDate\"", example.depositionDate); printopt(" \"releaseDate\"", example.releaseDate); - // json_print_opt(" \"ncsOperatorList\"", example.ncsOperatorList, 1); + json_print_opt(" \"ncsOperatorList\"", example.ncsOperatorList, 1); json_print_opt(" \"bioAssemblyList\"", example.bioAssemblyList, 1); json_print_opt(" \"entityList\"", example.entityList, 1); printopt(" \"experimentalMethods\"", "\"%s\"", example.experimentalMethods); @@ -210,19 +243,26 @@ void json_print(const mmtf::StructureData& example) { printreq(" \"zCoordList\"", "%g", example.zCoordList); printopt(" \"bFactorList\"", "%g", example.bFactorList); printopt(" \"atomIdList\"", "%d", example.atomIdList); - printopt(" \"altLocList\"", "%d", example.altLocList); + json_print_opt_chars(" \"altLocList\"", example.altLocList); printopt(" \"occupancyList\"", "%g", example.occupancyList); printreq(" \"groupIdList\"", "%d", example.groupIdList); printreq(" \"groupTypeList\"", "%d", example.groupTypeList); printopt(" \"secStructList\"", "%d", example.secStructList); - printopt(" \"insCodeList\"", "%d", example.insCodeList); + json_print_opt_chars(" \"insCodeList\"", example.insCodeList); printopt(" \"sequenceIndexList\"", "%d", example.sequenceIndexList); printreq(" \"chainIdList\"", "\"%s\"", example.chainIdList); printopt(" \"chainNameList\"", "\"%s\"", example.chainNameList); printreq(" \"groupsPerChain\"", "%d", example.groupsPerChain); - printreq(" \"chainsPerModel\"", "%d", example.chainsPerModel, true); + printreq(" \"chainsPerModel\"", "%d", example.chainsPerModel); + + json_print_opt(" \"bondProperties\"", example.bondProperties, 1); + json_print_opt(" \"atomProperties\"", example.atomProperties, 1); + json_print_opt(" \"groupProperties\"", example.groupProperties, 1); + json_print_opt(" \"chainProperties\"", example.chainProperties, 1); + json_print_opt(" \"modelProperties\"", example.modelProperties, 1); + json_print_opt(" \"extraProperties\"", example.extraProperties, 1, true); printf("}\n"); } @@ -483,6 +523,8 @@ int main(int argc, char** argv) { if (argc > 2) { if (strcmp(argv[2], "json") == 0) { json_print(example); + } else if (strcmp(argv[2], "sd_json") == 0) { + std::cout << example.to_json() << std::endl; } else if (strcmp(argv[2], "print") == 0) { std::cout << example.print() << std::endl; } else { diff --git a/include/mmtf/structure_data.hpp b/include/mmtf/structure_data.hpp index 0d37e32..aa6bb0f 100644 --- a/include/mmtf/structure_data.hpp +++ b/include/mmtf/structure_data.hpp @@ -236,6 +236,11 @@ struct StructureData { */ std::string print(std::string delim="\t") const; + /** + * @brief Read out the contents of mmtf::StructureData to json (unencoded) + */ + std::string to_json() const; + /** * @brief Compare two StructureData classes for equality * @param c What to compare to @@ -1104,6 +1109,92 @@ inline std::string StructureData::print(std::string delim) const { return out.str(); } +inline std::string StructureData::to_json() const { + msgpack::zone zone; + std::map json_out; + + json_out["mmtfVersion"] = msgpack::object(mmtfVersion, zone); + json_out["mmtfProducer"] = msgpack::object(mmtfProducer, zone); + json_out["unitCell"] = msgpack::object(unitCell, zone); + json_out["spaceGroup"] = msgpack::object(spaceGroup, zone); + json_out["structureId"] = msgpack::object(structureId, zone); + json_out["title"] = msgpack::object(title, zone); + json_out["depositionDate"] = msgpack::object(depositionDate, zone); + json_out["releaseDate"] = msgpack::object(releaseDate, zone); + json_out["ncsOperatorList"] = msgpack::object(ncsOperatorList, zone); + json_out["bioAssemblyList"] = msgpack::object(bioAssemblyList, zone); + json_out["entityList"] = msgpack::object(entityList, zone); + json_out["experimentalMethods"] = msgpack::object(experimentalMethods, zone); + json_out["resolution"] = msgpack::object(resolution, zone); + json_out["rFree"] = msgpack::object(rFree, zone); + json_out["rWork"] = msgpack::object(rWork, zone); + json_out["numBonds"] = msgpack::object(numBonds, zone); + json_out["numAtoms"] = msgpack::object(numAtoms, zone); + json_out["numGroups"] = msgpack::object(numGroups, zone); + json_out["numChains"] = msgpack::object(numChains, zone); + json_out["numModels"] = msgpack::object(numModels, zone); + json_out["groupList"] = msgpack::object(groupList, zone); + json_out["bondAtomList"] = msgpack::object(bondAtomList, zone); + { + std::vector tmp_bol(bondOrderList.begin(), bondOrderList.end()); + json_out["bondOrderList"] = msgpack::object(tmp_bol, zone); + } + { + std::vector tmp_brl(bondResonanceList.begin(), bondResonanceList.end()); + json_out["bondResonanceList"] = msgpack::object(bondResonanceList, zone); + } + json_out["xCoordList"] = msgpack::object(xCoordList, zone); + json_out["yCoordList"] = msgpack::object(yCoordList, zone); + json_out["zCoordList"] = msgpack::object(zCoordList, zone); + json_out["bFactorList"] = msgpack::object(bFactorList, zone); + json_out["atomIdList"] = msgpack::object(atomIdList, zone); + { + std::vector tmp_all; + for (unsigned int i = 0; i < altLocList.size(); ++i) { + if (altLocList[i] == 0x00) { + tmp_all.push_back(std::string()); + } else { + tmp_all.push_back(std::string(1, altLocList[i])); + } + } + json_out["altLocList"] = msgpack::object(tmp_all, zone); + } + + json_out["occupancyList"] = msgpack::object(occupancyList, zone); + json_out["groupIdList"] = msgpack::object(groupIdList, zone); + json_out["groupTypeList"] = msgpack::object(groupTypeList, zone); + { + std::vector tmp_ssl(secStructList.begin(), secStructList.end()); + json_out["secStructList"] = msgpack::object(tmp_ssl, zone); + } + { + std::vector tmp_icl; + for (unsigned int i = 0; i < insCodeList.size(); ++i) { + if (insCodeList[i] == 0x00) { + tmp_icl.push_back(std::string()); + } else { + tmp_icl.push_back(std::string(1, insCodeList[i])); + } + } + json_out["insCodeList"] = msgpack::object(tmp_icl, zone); + } + json_out["sequenceIndexList"] = msgpack::object(sequenceIndexList, zone); + json_out["chainIdList"] = msgpack::object(chainIdList, zone); + json_out["chainNameList"] = msgpack::object(chainNameList, zone); + json_out["groupsPerChain"] = msgpack::object(groupsPerChain, zone); + json_out["chainsPerModel"] = msgpack::object(chainsPerModel, zone); + json_out["bondProperties"] = msgpack::object(bondProperties, zone); + json_out["atomProperties"] = msgpack::object(atomProperties, zone); + json_out["groupProperties"] = msgpack::object(groupProperties, zone); + json_out["chainProperties"] = msgpack::object(chainProperties, zone); + json_out["modelProperties"] = msgpack::object(modelProperties, zone); + json_out["extraProperties"] = msgpack::object(extraProperties, zone); + std::stringstream ss; + msgpack::object f(json_out, zone); + ss << f; + return ss.str(); +} + inline void StructureData::copyMapData_( std::map& target, const std::map& source) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 77fa418..7e9e79c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -22,6 +22,13 @@ else() target_link_libraries(multi_cpp_test MMTFcpp) endif() +add_executable(to_json to_json.cpp) +if(WIN32) + target_link_libraries(to_json MMTFcpp ws2_32) +else() + target_link_libraries(to_json MMTFcpp) +endif() + set(TEST_RUNNER "none" CACHE STRING "External runner for the tests") if (${TEST_RUNNER} STREQUAL "node") diff --git a/tests/mmtf_tests.cpp b/tests/mmtf_tests.cpp index 163e957..2654b1f 100644 --- a/tests/mmtf_tests.cpp +++ b/tests/mmtf_tests.cpp @@ -1052,6 +1052,61 @@ TEST_CASE("Test is_hetatm (chain_index version)") { } } +// We dont have a json library, but we can check for basic stuff since +// we're mostly relying on the msgpack library to do this for us. +TEST_CASE("Test json") { + std::string working_mmtf = "../temporary_test_data/3zqs.mmtf"; + mmtf::StructureData sd; + mmtf::decodeFromFile(sd, working_mmtf); + std::string const json_text(sd.to_json()); + REQUIRE(json_text.find("mmtfVersion\":") != std::string::npos); + REQUIRE(json_text.find("mmtfProducer\":") != std::string::npos); + REQUIRE(json_text.find("unitCell\":") != std::string::npos); + REQUIRE(json_text.find("spaceGroup\":") != std::string::npos); + REQUIRE(json_text.find("structureId\":") != std::string::npos); + REQUIRE(json_text.find("title\":") != std::string::npos); + REQUIRE(json_text.find("depositionDate\":") != std::string::npos); + REQUIRE(json_text.find("releaseDate\":") != std::string::npos); + REQUIRE(json_text.find("ncsOperatorList\":") != std::string::npos); + REQUIRE(json_text.find("bioAssemblyList\":") != std::string::npos); + REQUIRE(json_text.find("entityList\":") != std::string::npos); + REQUIRE(json_text.find("experimentalMethods\":") != std::string::npos); + REQUIRE(json_text.find("resolution\":") != std::string::npos); + REQUIRE(json_text.find("rFree\":") != std::string::npos); + REQUIRE(json_text.find("rWork\":") != std::string::npos); + REQUIRE(json_text.find("numBonds\":") != std::string::npos); + REQUIRE(json_text.find("numAtoms\":") != std::string::npos); + REQUIRE(json_text.find("numGroups\":") != std::string::npos); + REQUIRE(json_text.find("numChains\":") != std::string::npos); + REQUIRE(json_text.find("numModels\":") != std::string::npos); + REQUIRE(json_text.find("groupList\":") != std::string::npos); + REQUIRE(json_text.find("bondAtomList\":") != std::string::npos); + REQUIRE(json_text.find("bondOrderList\":") != std::string::npos); + REQUIRE(json_text.find("bondResonanceList\":") != std::string::npos); + REQUIRE(json_text.find("xCoordList\":") != std::string::npos); + REQUIRE(json_text.find("yCoordList\":") != std::string::npos); + REQUIRE(json_text.find("zCoordList\":") != std::string::npos); + REQUIRE(json_text.find("bFactorList\":") != std::string::npos); + REQUIRE(json_text.find("atomIdList\":") != std::string::npos); + REQUIRE(json_text.find("altLocList\":") != std::string::npos); + REQUIRE(json_text.find("occupancyList\":") != std::string::npos); + REQUIRE(json_text.find("groupIdList\":") != std::string::npos); + REQUIRE(json_text.find("groupTypeList\":") != std::string::npos); + REQUIRE(json_text.find("secStructList\":") != std::string::npos); + REQUIRE(json_text.find("insCodeList\":") != std::string::npos); + REQUIRE(json_text.find("sequenceIndexList\":") != std::string::npos); + REQUIRE(json_text.find("chainIdList\":") != std::string::npos); + REQUIRE(json_text.find("chainNameList\":") != std::string::npos); + REQUIRE(json_text.find("groupsPerChain\":") != std::string::npos); + REQUIRE(json_text.find("chainsPerModel\":") != std::string::npos); + REQUIRE(json_text.find("bondProperties\":") != std::string::npos); + REQUIRE(json_text.find("atomProperties\":") != std::string::npos); + REQUIRE(json_text.find("groupProperties\":") != std::string::npos); + REQUIRE(json_text.find("chainProperties\":") != std::string::npos); + REQUIRE(json_text.find("modelProperties\":") != std::string::npos); + REQUIRE(json_text.find("extraProperties\":") != std::string::npos); +} + #ifdef __EMSCRIPTEN__ #include diff --git a/tests/to_json.cpp b/tests/to_json.cpp new file mode 100644 index 0000000..d318aa2 --- /dev/null +++ b/tests/to_json.cpp @@ -0,0 +1,17 @@ +// ************************************************************************* +// +// Simple test for compilation issues. +// +// ************************************************************************* + +#include + +int main(int argc, char** argv) { + // decode MMTF file + std::string const filename(argv[1]); + mmtf::StructureData data; + mmtf::decodeFromFile(data, filename); + std::cout << data.to_json() << std::endl; + + return 0; +}