bin/rmf_xml.cpp

Summary

Maintainability
Test Coverage
/**
 * Copyright 2007-2022 IMP Inventors. All rights reserved.
 */

#include <algorithm>
#include <exception>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

#include "RMF/FileConstHandle.h"
#include "RMF/ID.h"
#include "RMF/NodeConstHandle.h"
#include "RMF/Nullable.h"
#include "RMF/enums.h"
#include "RMF/infrastructure_macros.h"
#include "common.h"

namespace {
std::string description =
    "Convert an rmf file into an xml file suitable for "
    "opening in a web browser.";

std::string get_as_attribute_name(std::string name) {
  std::vector<char> data(name.begin(), name.end());
  std::vector<char>::iterator cur = data.begin();
  do {
    cur = std::find(cur, data.end(), ' ');
    if (cur == data.end()) {
      break;
    } else {
      *cur = '_';
    }
  } while (true);
  return std::string(data.begin(), data.end());
}

template <class TypeT, class Handle>
bool show_type_data_xml(Handle nh, RMF::Category kc, bool opened,
                        std::ostream& out) {
  using RMF::operator<<;
  RMF::FileConstHandle rh = nh.get_file();
  std::vector<RMF::ID<TypeT> > keys = rh.get_keys<TypeT>(kc);
  for (unsigned int i = 0; i < keys.size(); ++i) {
    // std::cout << "key " << rh.get_name(keys[i]) << std::endl;
    if (nh.get_has_value(keys[i])) {
      if (!opened) {
        out << "<" << nh.get_file().get_name(kc) << "\n";
        opened = true;
      }
      out << get_as_attribute_name(rh.get_name(keys[i])) << "=\"";
      out << RMF::Showable(nh.get_value(keys[i])) << "\"\n";
    }
  }
  return opened;
}
#define RMF_SHOW_TYPE_DATA_XML(Traits, UCName) \
  opened = show_type_data_xml<Traits>(nh, kc, opened, out);

template <class Handle>
void show_data_xml(Handle nh, RMF::Category kc, std::ostream& out) {
  bool opened = false;
  RMF_FOREACH_TYPE(RMF_SHOW_TYPE_DATA_XML);
  if (opened) {
    out << "/>\n";
  }
}

void show_hierarchy(RMF::NodeConstHandle nh, const RMF::Categories& cs,
                    std::set<RMF::NodeConstHandle>& seen, std::ostream& out) {
  out << "<node name=\"" << nh.get_name() << "\" id=\"" << nh.get_id() << "\" "
      << "type=\"" << nh.get_type() << "\">\n";
  if (seen.find(nh) == seen.end()) {
    if (variables_map.count("verbose")) {
      for (const auto &c : cs) {
        show_data_xml(nh, c, out);
      }
    }
    RMF::NodeConstHandles children = nh.get_children();
    for (const auto &child : children) {
      out << "<child>\n";
      show_hierarchy(child, cs, seen, out);
      out << "</child>\n";
    }
    seen.insert(nh);
  }
  out << "</node>" << std::endl;
}
}

int main(int argc, char** argv) {
  try {
    RMF_ADD_INPUT_FILE("rmf");
    RMF_ADD_OUTPUT_FILE("xml");
    int frame = 0;
    options.add_options()("frame,f", boost::program_options::value<int>(&frame),
                          "Frame to use, if -1 just show static data")(
        "verbose,v", "Show the attribute values for each node.");

    process_options(argc, argv);

    RMF::FileConstHandle rh = RMF::open_rmf_file_read_only(input);
    std::ostream* out;
    std::ofstream fout;
    if (!output.empty()) {
      fout.open(output.c_str());
      if (!fout) {
        std::cerr << "Error opening file " << output << std::endl;
        return 1;
      }
      out = &fout;
    } else {
      out = &std::cout;
    }
    RMF::Categories cs = rh.get_categories();
    *out << "<?xml version=\"1.0\"?>\n";
    *out << "<rmf>\n";
    *out << "<description>\n";
    *out << rh.get_description() << std::endl;
    *out << "</description>\n";
    *out << "<path>\n";
    *out << input << std::endl;
    *out << "</path>\n";
    std::set<RMF::NodeConstHandle> seen;
    rh.set_current_frame(RMF::FrameID(frame));
    show_hierarchy(rh.get_root_node(), cs, seen, *out);
    *out << "</rmf>\n";
    return 0;
  }
  catch (const std::exception& e) {
    std::cerr << "Error: " << e.what() << std::endl;
  }
}