COOPY » Guide
version 0.6.5
|
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