COOPY » Guide  version 0.6.5
/home/paulfitz/cvs/coopy_scm/coopy/src/libcoopy_full/JsonBook.cpp
Go to the documentation of this file.
00001 #include <coopy/JsonBook.h>
00002 #include <coopy/FoldedSheet.h>
00003 #include <coopy/Dbg.h>
00004 #include <coopy/FormatSniffer.h>
00005 #include <coopy/FileIO.h>
00006 
00007 #include <fstream>
00008 
00009 #include <json/json.h>
00010 
00011 using namespace std;
00012 using namespace coopy::store;
00013 using namespace coopy::store::json;
00014 using namespace coopy::format;
00015 using namespace coopy::fold;
00016 
00017 static Json::Value cellToJson(const SheetCell& cell, const ColumnInfo& info) {
00018   const ColumnType& t = info.getColumnType();
00019   if (t.family == ColumnType::COLUMN_FAMILY_INTEGER) return Json::Value(cell.asInt());
00020   return Json::Value(cell.text);
00021 }
00022 
00023 static bool readPart(Json::Value& rows,
00024                      FoldedSheet *psheet,
00025                      SheetSchema *schema) {
00026   FoldedSheet& sheet = *psheet;
00027 
00028   int y = 0;
00029   Json::Value arr(Json::arrayValue);
00030   for (Json::Value::iterator it2=rows.begin(); it2!=rows.end(); it2++) {
00031     //for (int i=0; i<rows.size(); i++) {
00032     dbg_printf("JSON Row %d\n", y);
00033     if ((*it2).isArray() || (schema && (*it2).isObject())) {
00034       bool subst = false;
00035       if ((*it2).isObject()) {
00036         arr = Json::Value(Json::arrayValue);
00037         for (int x=0; x<schema->getColumnCount(); x++) {
00038           ColumnInfo info = schema->getColumnInfo(x);
00039           arr.append((*it2)[info.getName()]);
00040         }
00041         subst = true;
00042       }
00043       Json::Value& cols = subst?arr:*it2;
00044       if (y==0) {
00045         FoldedCell zero;
00046         sheet.resize((int)cols.size(),1,zero);
00047       } else {
00048         sheet.insertRow(RowRef(-1));
00049       }
00050       int x = 0;
00051       for (Json::Value::iterator it3=cols.begin(); it3!=cols.end(); it3++) {
00052         string s;
00053         bool escaped = false;
00054         bool nested = false;
00055         if ((*it3).isInt()) {
00056           //printf("At %d %d -> %d\n", x, y, (*it3).asInt());
00057           char buf[1000];
00058           snprintf(buf,sizeof(buf),"%d",(*it3).asInt());
00059           s = buf;
00060         } else if ((*it3).isNumeric()) {
00061           //printf("At %d %d -> %g\n", x, y, (*it3).asDouble());        
00062           char buf[1000];
00063           snprintf(buf,sizeof(buf),"%g",(*it3).asDouble());
00064           s = buf;
00065         } else if ((*it3).isNull()) {
00066           s = "NULL";
00067           escaped = true;
00068         } else if ((*it3).isArray()||(*it3).isObject()) {
00069           if (!readPart((*it3),sheet.cell(x,y).getOrCreateSheet(),NULL)) {
00070             return false;
00071           }
00072           nested = true;
00073         } else {
00074           //printf("At %d %d -> %s\n", x, y, (*it3).asString().c_str());
00075           s = (*it3).asString();
00076         }
00077         if (!nested) {
00078           sheet.cellString(x,y,s,escaped);
00079         }
00080         x++;
00081       }
00082     }
00083     y++;
00084   }
00085 
00086   return true;
00087 }
00088 
00089 bool JsonBook::read(const char *fname) {
00090   clear();
00091 
00092   FormatSniffer in;
00093   if (!in.open(fname,true)) {
00094     fprintf(stderr,"Failed to open %s\n", fname);
00095     return false;
00096   }
00097 
00098   Json::Value root;
00099   Json::Reader reader;
00100   if (!reader.parse(in.read(),root,false)) {
00101     fprintf(stderr,"Failed to parse %s\n", fname);
00102     return false;
00103   }
00104   SheetSchema *schema = NULL;
00105 
00106   for (Json::Value::iterator it=root.begin(); it!=root.end(); it++) {
00107     FoldedSheet *psheet = new FoldedSheet;
00108     COOPY_ASSERT(psheet);
00109     FoldedSheet& sheet = *psheet;
00110     PolySheet p(psheet,true);
00111 
00112     Json::Value *prows = &(*it);
00113     if (prows->isObject()) {
00114       Json::Value& crows = (*it);
00115       prows = &(crows["rows"]);
00116       if (prows->isNull()) {
00117         fprintf(stderr,"Cannot find rows for %s\n", it.memberName());
00118         return false;
00119       }
00120       const Json::Value& cols = (*it)["columns"];
00121       if (cols.isNull()) {
00122         fprintf(stderr,"Cannot find columns for %s\n", it.memberName());
00123         return false;
00124       }
00125       SimpleSheetSchema *ss = new SimpleSheetSchema();
00126       COOPY_ASSERT(ss);
00127       ss->setSheetName(it.memberName());
00128       for (Json::Value::iterator it=cols.begin(); it!=cols.end(); it++) {
00129         //printf("Got col %s\n", (*it).asString().c_str());
00130         ss->addColumn((*it).asString().c_str());
00131       }
00132       p.setSchema(ss,true);
00133       schema = ss;
00134       //printf("Configured sheet\n");
00135     }
00136     if (prows->isArray()) {
00137       dbg_printf("JSON Working on %s\n", it.memberName());
00138       Json::Value& rows = *prows;
00139       if (!readPart(rows,psheet,schema)) return false;
00140       name2index[it.memberName()] = (int)sheets.size();
00141       sheets.push_back(p);
00142       names.push_back(it.memberName());
00143     }
00144   }
00145 
00146   return true;
00147 }
00148 
00149 static bool writePart(Json::Value& root2,
00150                       DataSheet *psheet,
00151                       bool hasSchema,
00152                       bool nestSchema) {
00153   DataSheet& sheet = *psheet;
00154   Json::Value *rows = &root2;
00155   vector<string> names;
00156   vector<ColumnInfo> infos;
00157   bool hasNames = false;
00158   if (hasSchema) {
00159     root2["columns"] = Json::Value(Json::arrayValue);
00160     Json::Value& cols = root2["columns"];
00161     SheetSchema *schema = sheet.getSchema();
00162     if (schema->getColumnCount()!=sheet.width()) {
00163       fprintf(stderr,"warning: partial schema information, %d columns in sheet, %d column names\n", sheet.width(), schema->getColumnCount());
00164     }
00165     for (int x=0; x<schema->getColumnCount(); x++) {
00166       ColumnInfo info = schema->getColumnInfo(x);
00167       names.push_back(info.getName());
00168       infos.push_back(info);
00169       hasNames = nestSchema;
00170       cols.append(Json::Value(info.getName()));
00171     }    
00172     root2["rows"] = Json::Value(Json::arrayValue);
00173     rows = &root2["rows"];
00174   }
00175   for (int y=0; y<sheet.height(); y++) {
00176     Json::Value row(hasNames?Json::objectValue:Json::arrayValue);
00177     for (int x=0; x<sheet.width(); x++) {
00178       DataSheet *next = sheet.getNestedSheet(x,y);
00179       if (next==NULL) {
00180         SheetCell c = sheet.cellSummary(x,y);
00181         if (c.escaped) {
00182           if (hasNames) {
00183             row[names[x]] = Json::Value(Json::nullValue);
00184           } else {
00185             row.append(Json::Value(Json::nullValue));
00186           }
00187         } else {
00188           if (hasNames) {
00189             row[names[x]] = cellToJson(c,infos[x]);
00190               //Json::Value(sheet.cellString(x,y));
00191           } else {
00192             row.append(Json::Value(sheet.cellString(x,y)));
00193           }
00194         }
00195       } else {
00196         bool hasSchema2 = (next->getSchema()!=NULL);
00197         if (hasSchema2) {
00198           row.append(Json::Value(Json::objectValue));
00199         } else {
00200           row.append(Json::Value(Json::arrayValue));
00201         }
00202         if (!writePart(row[x],next,hasSchema2,nestSchema)) return false;
00203       }
00204     }
00205     rows->append(row);
00206   }
00207   return true;
00208 }
00209 
00210 static bool renderJsonBook(Json::Value& root, TextBook *book, 
00211                            const Property& options) {
00212   vector<string> names = book->getNames();
00213   for (int i=0; i<(int)names.size(); i++) {
00214     PolySheet sheet = book->readSheet(names[i]);
00215     bool hasSchema = false;
00216     bool nestSchema = true;
00217     if (options.check("hash")) {
00218       int h = options.get("hash").asInt();
00219       nestSchema = (h>0);
00220     }
00221     if (nestSchema) {
00222       sheet.mustHaveSchema();
00223     }
00224     if (sheet.getSchema()!=NULL) {
00225       hasSchema = true;
00226     }
00227     if (hasSchema) {
00228       root[names[i]] = Json::Value(Json::objectValue);
00229     } else {
00230       root[names[i]] = Json::Value(Json::arrayValue);
00231     }
00232     Json::Value& root2 = root[names[i]];
00233     if (!sheet.isValid()) return false;
00234     if (!writePart(root2,&sheet,hasSchema,nestSchema)) return false;
00235   }
00236   return true;
00237 }
00238 
00239 std::string JsonBook::render(TextBook *book, const Property& options) {
00240   Json::Value root(Json::objectValue);
00241   if (!renderJsonBook(root,book,options)) return "";
00242   return root.toStyledString();
00243 }
00244 
00245 bool JsonBook::write(const char *fname, TextBook *book, const Property& options) {
00246   if (book==NULL) return false;
00247   Json::Value root(Json::objectValue);
00248   ostream *fout = &cout;
00249   ofstream out;
00250   if (string(fname)!="-") {
00251     out.open(fname);
00252     fout = &out;
00253   }
00254   if (fout->bad()) {
00255     fprintf(stderr,"Failed to open %s for writing\n", fname);
00256     return false;
00257   }
00258   if (!renderJsonBook(root,book,options)) return false;
00259   (*fout) << root;
00260   return true;
00261 }
00262 
00263 bool JsonBook::open(const Property& config) {
00264   if (!config.check("file")) return false;
00265   return read(config.get("file").asString().c_str());
00266 }
00267 
00268 bool JsonBook::addSheet(const SheetSchema& schema) {
00269   dbg_printf("jsonbook::addsheet %s\n", schema.getSheetName().c_str());
00270   FoldedSheet *psheet = new FoldedSheet;
00271   COOPY_ASSERT(psheet);
00272   FoldedSheet& sheet = *psheet;
00273   PolySheet p(psheet,true);
00274   SimpleSheetSchema *sss = new SimpleSheetSchema();
00275   COOPY_ASSERT(sss);
00276   sss->copy(schema);
00277   p.setSchema(sss,true);
00278   name2index[schema.getSheetName()] = (int)sheets.size();
00279   sheet.resize(schema.getColumnCount(),0,FoldedCell());
00280   dbg_printf("CREATED %d %d (%d)\n", p.width(), p.height(), schema.getColumnCount());
00281   sheets.push_back(p);
00282   names.push_back(schema.getSheetName());
00283   return true;
00284 }
00285 
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines