void writeValLabelMatches(struct jsonWrite *jw, struct slPair *matches, char *category) /* Append JSON objects containing alt/fix seqs with extra label info & optional category. */ { struct slPair *match; for (match = matches; match != NULL; match = match->next) { char *seqName = match->name; if (strchr(seqName, '_') && !endsWith(seqName, "_random") && !startsWith("chrUn", seqName)) { jsonWriteObjectStart(jw, NULL); jsonWriteString(jw, "value", seqName); char *extraInfo = match->val; if (isNotEmpty(extraInfo)) { int len = strlen(seqName) + strlen(extraInfo) + 32; char label[len]; safef(label, sizeof label, "%s (%s)", seqName, extraInfo); jsonWriteString(jw, "label", label); } if (isNotEmpty(category)) jsonWriteString(jw, "category", category); jsonWriteObjectEnd(jw); } } }
static void getAssemblyInfo(struct cartJson *cj, struct hash *paramHash) /* Return useful things from dbDb (or track hub) and assembly description html (possibly NULL). * If db param is NULL, use db from cart. */ { char *db = cartJsonOptionalParam(paramHash, "db"); if (db == NULL) db = cartString(cj->cart, "db"); jsonWriteString(cj->jw, "db", db); jsonWriteString(cj->jw, "commonName", hGenome(db)); jsonWriteString(cj->jw, "scientificName", hScientificName(db)); jsonWriteString(cj->jw, "dbLabel", hFreezeDate(db)); //#*** TODO: move jsonStringEscape inside jsonWriteString jsonWriteString(cj->jw, "assemblyDescription", jsonStringEscape(hAssemblyDescription(db))); }
static void getVar(struct cartJson *cj, struct hash *paramHash) /* Print out the requested cart var(s). varString may be a comma-separated list. * If a var is a list variable, prints out a list of values for that var. */ { char *varString = cartJsonRequiredParam(paramHash, "var", cj->jw, "get"); if (! varString) return; struct slName *varList = slNameListFromComma(varString), *var; for (var = varList; var != NULL; var = var->next) { if (cartListVarExists(cj->cart, var->name)) { // Use cartOptionalSlNameList and return a list: struct slName *valList = cartOptionalSlNameList(cj->cart, var->name); jsonWriteSlNameList(cj->jw, var->name, valList); slFreeList(&valList); } else { // Regular single-value variable (or not in the cart): char *val = cartOptionalString(cj->cart, var->name); //#*** TODO: move jsonStringEscape inside jsonWriteString char *encoded = jsonStringEscape(val); jsonWriteString(cj->jw, var->name, encoded); freeMem(encoded); } } slFreeList(&varList); }
void writeAltFixMatches(struct jsonWrite *jw, struct slName *matches, char *category) /* Append JSON objects containing alt or fix patch sequence names & optional category. */ { struct slName *match; for (match = matches; match != NULL; match = match->next) { if (strchr(match->name, '_')) { jsonWriteObjectStart(jw, NULL); jsonWriteString(jw, "value", match->name); if (isNotEmpty(category)) jsonWriteString(jw, "category", category); jsonWriteObjectEnd(jw); } } }
void cartJsonExecute(struct cartJson *cj) /* Get commands from cgi, print Content-type, execute commands, print results as JSON. */ { cartJsonPushErrHandlers(); puts("Content-Type:text/javascript\n"); // Initialize response JSON object: jsonWriteObjectStart(cj->jw, NULL); // Always send back hgsid: jsonWriteString(cj->jw, cartSessionVarName(), cartSessionId(cj->cart)); char *commandJson = cgiOptionalString(CARTJSON_COMMAND); if (commandJson) { struct jsonElement *commandObj = jsonParse(commandJson); struct hash *commandHash = jsonObjectVal(commandObj, "commandObj"); // change* commands need to go first! Really we need an ordered map type here... // for now, just make a list and sort to put change commands at the front. struct slPair *commandList = NULL, *cmd; struct hashCookie cookie = hashFirst(commandHash); struct hashEl *hel; while ((hel = hashNext(&cookie)) != NULL) slAddHead(&commandList, slPairNew(hel->name, hel->val)); slSort(&commandList, commandCmp); for (cmd = commandList; cmd != NULL; cmd = cmd->next) doOneCommand(cj, cmd->name, (struct jsonElement *)cmd->val); } cartJsonPrintWarnings(cj->jw); jsonWriteObjectEnd(cj->jw); puts(cj->jw->dy->string); cartJsonPopErrHandlers(); }
static void writeTdbSimple(struct jsonWrite *jw, struct trackDb *tdb, struct hash *fieldHash) /* Write JSON for the non-parent/child fields of tdb */ { if (fieldOk("track", fieldHash)) jsonWriteString(jw, "track", tdb->track); if (fieldOk("table", fieldHash)) jsonWriteString(jw, "table", tdb->table); if (fieldOk("shortLabel", fieldHash)) jsonWriteString(jw, "shortLabel", tdb->shortLabel); if (fieldOk("longLabel", fieldHash)) jsonWriteString(jw, "longLabel", tdb->longLabel); if (fieldOk("type", fieldHash)) jsonWriteString(jw, "type", tdb->type); if (fieldOk("priority", fieldHash)) jsonWriteDouble(jw, "priority", tdb->priority); if (fieldOk("grp", fieldHash)) jsonWriteString(jw, "grp", tdb->grp); // NOTE: if you add a new field here, then also add it to nameIsTdbField above. if (tdb->settingsHash) { struct hashEl *hel; struct hashCookie cookie = hashFirst(tdb->settingsHash); while ((hel = hashNext(&cookie)) != NULL) { if (! nameIsTdbField(hel->name) && fieldOk(hel->name, fieldHash)) { //#*** TODO: move jsonStringEscape inside jsonWriteString char *encoded = jsonStringEscape((char *)hel->val); jsonWriteString(jw, hel->name, encoded); } } } }
static void getCladeOrgDbPos(struct cartJson *cj, struct hash *paramHash) /* Get cart's current clade, org, db, position and geneSuggest track. */ { jsonWriteObjectStart(cj->jw, "cladeOrgDb"); printCladeOrgDbTree(cj->jw); char *db = cartString(cj->cart, "db"); jsonWriteString(cj->jw, "db", db); char *org = cartUsualString(cj->cart, "org", hGenome(db)); jsonWriteString(cj->jw, "org", org); char *clade = cartUsualString(cj->cart, "clade", hClade(org)); jsonWriteString(cj->jw, "clade", clade); jsonWriteObjectEnd(cj->jw); char *position = cartOptionalString(cj->cart, "position"); if (isEmpty(position)) position = hDefaultPos(db); jsonWriteString(cj->jw, "position", position); printGeneSuggestTrack(cj, db); }
struct jsonWrite *jsonForSoftware(struct eapSoftware *sw) /* Return JSON text for software. This is something that looks * like: { "name" : "macs2", "title" : "macs2", "url" : "https://github.com/taoliu/MACS/" } */ { struct jsonWrite *jw = jsonWriteNew(0); jsonWriteObjectStart(jw); jsonWriteString(jw, "name", sw->name); jsonWriteString(jw, "title", sw->name); jsonWriteString(jw, "url", sw->url); jsonWriteObjectEnd(jw); return jw; }
static void printCladeOrgDbTree(struct jsonWrite *jw) /* Print out the tree of clades, organisms and dbs as JSON. Each node has value and label * for menu options; clade nodes and org nodes also have children and default. */ { jsonWriteListStart(jw, "cladeOrgDb"); struct slPair *clade, *cladeOptions = hGetCladeOptions(); struct dbDb *centralDbDbList = hDbDbList(); for (clade = cladeOptions; clade != NULL; clade = clade->next) { jsonWriteObjectStart(jw, NULL); jsonWriteValueLabel(jw, clade->name, clade->val); jsonWriteListStart(jw, "children"); struct slPair *org, *orgOptions = hGetGenomeOptionsForClade(clade->name); for (org = orgOptions; org != NULL; org = org->next) { jsonWriteObjectStart(jw, NULL); jsonWriteValueLabel(jw, org->name, org->val); jsonWriteListStart(jw, "children"); struct dbDb *dbDb, *dbDbList; if (isHubTrack(org->name)) dbDbList = trackHubGetDbDbs(clade->name); else dbDbList = centralDbDbList; for (dbDb = dbDbList; dbDb != NULL; dbDb = dbDb->next) { if (sameString(org->name, dbDb->genome)) { jsonWriteObjectStart(jw, NULL); jsonWriteValueLabel(jw, dbDb->name, dbDb->description); jsonWriteString(jw, "defaultPos", dbDb->defaultPos); jsonWriteObjectEnd(jw); } } jsonWriteListEnd(jw); // children (dbs) jsonWriteString(jw, "default", trimSpaces(hDefaultDbForGenome(org->name))); jsonWriteObjectEnd(jw); // org } jsonWriteListEnd(jw); // children (orgs) jsonWriteString(jw, "default", trimSpaces(hDefaultGenomeForClade(clade->name))); jsonWriteObjectEnd(jw); // clade } jsonWriteListEnd(jw); }
static void printGeneSuggestTrack(struct cartJson *cj, char *db) /* Get the gene track used by hgSuggest for db (defaulting to cart db), or null if * there is none for this assembly. */ { if (isEmpty(db)) db = cartString(cj->cart, "db"); char *track = NULL; if (! trackHubDatabase(db)) track = assemblyGeneSuggestTrack(db); jsonWriteString(cj->jw, "geneSuggestTrack", track); }
static void cartJsonPrintWarnings(struct jsonWrite *jw) /* If there are warnings, write them out as JSON: */ { if (dyWarn && dyStringLen(dyWarn) > 0) { //#*** TODO: move jsonStringEscape inside jsonWriteString char *encoded = jsonStringEscape(dyWarn->string); jsonWriteString(jw, "warning", encoded); freeMem(encoded); } }
struct jsonWrite *jsonForSwVersion(struct sqlConnection *conn, struct eapSwVersion *ver) /* Construct JSON string describing ver. */ { char query[256]; sqlSafef(query, sizeof(query), "select * from eapSoftware where name='%s'", ver->software); struct eapSoftware *sw = eapSoftwareLoadByQuery(conn, query); if (sw == NULL || isEmpty(sw->metaUuid)) { verbose(2, "Skipping %s %s because %s has not been registered with metadatabase\n", ver->software, ver->version, ver->software); return NULL; } uglyf("sw id %u, softare %s, metaUuid %s\n", sw->id, sw->name, sw->metaUuid); struct jsonWrite *jw = jsonWriteNew(0); jsonWriteObjectStart(jw); jsonWriteString(jw, "software", sw->metaUuid); jsonWriteString(jw, "version", ver->version); jsonWriteString(jw, "dcc_md5", ver->md5); jsonWriteObjectEnd(jw); return jw; }
static void listAssemblyHubs(struct jsonWrite *jw) /* Write out JSON describing assembly hubs (not track-only hubs) connected in the cart. */ { jsonWriteListStart(jw, "hubs"); struct hubConnectStatus *status, *statusList = hubConnectStatusListFromCart(cart); for (status = statusList; status != NULL; status = status->next) { struct trackHub *hub = status->trackHub; if (hub == NULL) continue; int assemblyCount = trackHubCountAssemblies(hub); if (assemblyCount > 0) { jsonWriteObjectStart(jw, NULL); jsonWriteString(jw, "name", hub->name); jsonWriteString(jw, "shortLabel", hub->shortLabel); jsonWriteString(jw, "longLabel", hub->longLabel); jsonWriteString(jw, "defaultDb", trackHubDefaultAssembly(hub)); jsonWriteString(jw, "hubUrl", status->hubUrl); jsonWriteNumber(jw, "assemblyCount", assemblyCount); jsonWriteString(jw, "errorMessage", status->errorMessage); // We might be able to do better than this for taxId, for example if defaultDb is local // or if hub genomes ever specify taxId... jsonWriteNumber(jw, "taxId", 0); jsonWriteObjectEnd(jw); } } jsonWriteListEnd(jw); }
static void changePosition(struct cartJson *cj, char *newPosition) /* Update position in cart, after performing lookup if necessary. * Usually we don't report what we just changed, but since we might modify it, * print out the final value. */ { char *db = cartString(cj->cart, "db"); char *chrom = NULL; int start=0, end=0; struct hgPositions *hgp = genomePosCJ(cj->jw, db, newPosition, &chrom, &start, &end, cj->cart); // If it resolved to a single position, update the cart; otherwise the app can // present the error (or list of matches) to the user. if (hgp && hgp->singlePos) { char newPosBuf[128]; safef(newPosBuf, sizeof(newPosBuf), "%s:%d-%d", chrom, start+1, end); cartSetString(cj->cart, "position", newPosBuf); jsonWriteString(cj->jw, "position", newPosBuf); } else // Search failed; restore position from cart jsonWriteString(cj->jw, "position", cartUsualString(cj->cart, "position", hDefaultPos(db))); }
static void getStaticHtml(struct cartJson *cj, struct hash *paramHash) /* Read HTML text from a relative path under browser.documentRoot and * write it as an encoded JSON string */ { char *tag = cartJsonOptionalParam(paramHash, "tag"); if (isEmpty(tag)) tag = "html"; char *file = cartJsonRequiredParam(paramHash, "file", cj->jw, "getStaticHtml"); char *html = hFileContentsOrWarning(file); //#*** TODO: move jsonStringEscape inside jsonWriteString char *encoded = jsonStringEscape(html); jsonWriteString(cj->jw, tag, encoded); }
static boolean writeGroupedTrack(struct jsonWrite *jw, char *name, char *label, struct hash *fieldHash, struct hash *excludeTypesHash, int maxDepth, struct slRef *tdbRefList) /* If tdbRefList is empty after excluding tracks/views/subtracks whose types are * in excludeTypesHash, then return FALSE and write nothing. Otherwise write a group * and its tracks/views/subtracks and return TRUE. */ { // Make a new jsonWrite object in case this group turns out to have no children after filtering. struct jsonWrite *jwNew = jsonWriteNew(); jsonWriteObjectStart(jwNew, NULL); jsonWriteString(jwNew, "name", name); jsonWriteString(jwNew, "label", label); jsonWriteListStart(jwNew, "tracks"); boolean gotSomething = FALSE; struct slRef *tdbRef; for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next) { struct trackDb *tdb = tdbRef->val; // First see if there are any tracks to show for this group: struct jsonWrite *jwTrack = rTdbToJw(tdb, fieldHash, excludeTypesHash, 1, maxDepth); if (jwTrack) { gotSomething = TRUE; jsonWriteAppend(jwNew, NULL, jwTrack); jsonWriteFree(&jwTrack); } } if (gotSomething) { // Group has at least one track, so append it to jw. jsonWriteListEnd(jwNew); jsonWriteObjectEnd(jwNew); jsonWriteAppend(jw, NULL, jwNew); } jsonWriteFree(&jwNew); return gotSomething; }
static void writeDbDbMatch(struct jsonWrite *jw, struct dbDbMatch *match, char *term, char *category) /* Write out the JSON encoding of a match in dbDb. */ { struct dbDb *dbDb = match->dbDb; jsonWriteObjectStart(jw, NULL); jsonWriteString(jw, "genome", dbDb->genome); // label includes <b> tag to highlight the match for term. char label[PATH_LEN*4]; // value is placed in the input box when user selects the item. char value[PATH_LEN*4]; if (match->type == ddmtSciName) { safef(value, sizeof(value), "%s (%s)", dbDb->scientificName, dbDb->genome); char *bolded = boldTerm(dbDb->scientificName, term, match->offset, match->type); safef(label, sizeof(label), "%s (%s)", bolded, dbDb->genome); freeMem(bolded); } else if (match->type == ddmtGenome) { safecpy(value, sizeof(value), dbDb->genome); char *bolded = boldTerm(dbDb->genome, term, match->offset, match->type); safecpy(label, sizeof(label), bolded); freeMem(bolded); } else if (match->type == ddmtDb) { safecpy(value, sizeof(value), dbDb->name); char *bolded = boldTerm(dbDb->name, term, match->offset, match->type); safef(label, sizeof(label), "%s (%s %s)", bolded, dbDb->genome, dbDb->description); freeMem(bolded); jsonWriteString(jw, "db", dbDb->name); } else if (match->type == ddmtDescription) { safef(value, sizeof(value), "%s (%s %s)", dbDb->name, dbDb->genome, dbDb->description); char *bolded = boldTerm(dbDb->description, term, match->offset, match->type); safef(label, sizeof(label), "%s (%s %s)", dbDb->name, dbDb->genome, bolded); freeMem(bolded); jsonWriteString(jw, "db", dbDb->name); } else errAbort("writeDbDbMatch: unrecognized dbDbMatchType value %d (db %s, term %s)", match->type, dbDb->name, term); jsonWriteString(jw, "label", label); jsonWriteString(jw, "value", value); jsonWriteNumber(jw, "taxId", dbDb->taxId); if (isNotEmpty(category)) jsonWriteString(jw, "category", category); jsonWriteObjectEnd(jw); }
static void writeFindPositionInfo(struct jsonWrite *jw, char *db, int taxId, char *hubUrl, char *position) /* Write JSON for the info needed to populate the 'Find Position' section. */ { char *genome = hGenome(db); if (isEmpty(genome)) { jsonWriteStringf(jw, "error", "No genome for db '%s'", db); } else { jsonWriteString(jw, "db", db); jsonWriteNumber(jw, "taxId", taxId); jsonWriteString(jw, "genome", genome); struct slPair *dbOptions = NULL; char genomeLabel[PATH_LEN*4]; if (isNotEmpty(hubUrl)) { struct trackHub *hub = hubConnectGetHub(hubUrl); if (hub == NULL) { jsonWriteStringf(jw, "error", "Can't connect to hub at '%s'", hubUrl); return; } struct dbDb *dbDbList = trackHubGetDbDbs(hub->name); dbOptions = trackHubDbDbToValueLabel(dbDbList); safecpy(genomeLabel, sizeof(genomeLabel), hub->shortLabel); jsonWriteString(jw, "hubUrl", hubUrl); } else { dbOptions = hGetDbOptionsForGenome(genome); safecpy(genomeLabel, sizeof(genomeLabel), genome); } jsonWriteValueLabelList(jw, "dbOptions", dbOptions); jsonWriteString(jw, "genomeLabel", genomeLabel); jsonWriteString(jw, "position", position); char *suggestTrack = NULL; if (! trackHubDatabase(db)) suggestTrack = assemblyGeneSuggestTrack(db); jsonWriteString(jw, "suggestTrack", suggestTrack); char *description = maybeGetDescriptionText(db); //#*** TODO: move jsonStringEscape inside jsonWriteString char *encoded = jsonStringEscape(description); jsonWriteString(jw, "description", encoded); listAssemblyHubs(jw); } }
static void writeAssemblyHubMatches(struct jsonWrite *jw, struct aHubMatch *aHubMatchList) /* Write out JSON for each assembly in each assembly hub that matched the search term. */ { struct aHubMatch *aHubMatch; for (aHubMatch = aHubMatchList; aHubMatch != NULL; aHubMatch = aHubMatch->next) { jsonWriteObjectStart(jw, NULL); jsonWriteString(jw, "genome", aHubMatch->shortLabel); jsonWriteString(jw, "db", aHubMatch->aDb); jsonWriteString(jw, "hubUrl", aHubMatch->hubUrl); jsonWriteString(jw, "hubName", hubNameFromUrl(aHubMatch->hubUrl)); // Add a category label for customized autocomplete-with-categories. char category[PATH_LEN*4]; safef(category, sizeof(category), "Assembly Hub: %s", aHubMatch->shortLabel); jsonWriteString(jw, "category", category); jsonWriteString(jw, "value", aHubMatch->aDb); // Use just the db as label, since shortLabel is included in the category label. jsonWriteString(jw, "label", aHubMatch->aDb); jsonWriteObjectEnd(jw); } }
static void hgPositionsJson(struct jsonWrite *jw, char *db, struct hgPositions *hgp, struct cart *cart) /* Write out JSON description of multiple position matches. */ { struct hgPosTable *table; jsonWriteListStart(jw, "positionMatches"); struct trackDb *tdbList = NULL; for (table = hgp->tableList; table != NULL; table = table->next) { if (table->posList != NULL) { char *tableName = table->name; // clear the tdb cache if this track is a hub track if (isHubTrack(tableName)) tdbList = NULL; struct trackDb *tdb = tdbForTrack(db, tableName, &tdbList); if (!tdb && startsWith("all_", tableName)) tdb = tdbForTrack(db, tableName+strlen("all_"), &tdbList); if (!tdb) errAbort("no track for table \"%s\" found via a findSpec", tableName); char *trackName = tdb->track; jsonWriteObjectStart(jw, NULL); jsonWriteString(jw, "name", table->name); jsonWriteString(jw, "trackName", trackName); jsonWriteString(jw, "description", table->description); jsonWriteString(jw, "vis", hCarefulTrackOpenVis(db, trackName)); jsonWriteListStart(jw, "matches"); struct hgPos *pos; for (pos = table->posList; pos != NULL; pos = pos->next) { char *encMatches = cgiEncode(pos->browserName); jsonWriteObjectStart(jw, NULL); // begin one match if (pos->chrom != NULL) jsonWriteStringf(jw, "position", "%s:%d-%d", pos->chrom, pos->chromStart+1, pos->chromEnd); else // GenBank results set position to GB accession instead of chr:s-e position. jsonWriteString(jw, "position", pos->name); // this is magic to tell the browser to make the // composite and this subTrack visible if (tdb->parent) { if (tdbIsSuperTrackChild(tdb)) jsonWriteStringf(jw, "extraSel", "%s=show&", tdb->parent->track); else { // tdb is a subtrack of a composite or a view jsonWriteStringf(jw, "extraSel", "%s_sel=1&%s_sel=1&", trackName, tdb->parent->track); } } jsonWriteString(jw, "hgFindMatches", encMatches); jsonWriteString(jw, "posName", htmlEncodeText(pos->name, FALSE)); if (pos->description) { stripString(pos->description, "\n"); jsonWriteString(jw, "description", stripAnchor(pos->description)); } jsonWriteObjectEnd(jw); // end one match } jsonWriteListEnd(jw); // end matches jsonWriteObjectEnd(jw); // end one table } } jsonWriteListEnd(jw); // end positionMatches }
struct jsonWrite *jsonForStep(struct sqlConnection *conn, struct eapStep *step) /* Convert an eapStep to json. See step.json in same directory as the .c file. * for an example. */ { struct jsonWrite *jw = jsonWriteNew(); jsonWriteObjectStart(jw); /* Write name and description. */ jsonWriteString(jw, "name", step->name); jsonWriteString(jw, "description", step->description); /* Write version */ struct eapStepVersion *ver = eapStepVersionLatest(conn, step->name); jsonWriteNumber(jw, "version", ver->version); /* Write software */ jsonWriteListStart(jw, "software"); char query[512]; sqlSafef(query, sizeof(query), "select * from eapStepSoftware where step='%s'", step->name); struct eapStepSoftware *ss, *ssList = eapStepSoftwareLoadByQuery(conn, query); boolean isFirst = TRUE; struct dyString *dy = jw->dy; for (ss = ssList; ss != NULL; ss = ss->next) { struct eapSoftware *software = eapSoftwareLoadByName(conn, ss->software); assert(software != NULL); if (software->metaUuid) { if (!isFirst) { dyStringAppendC(dy, ','); dyStringAppendC(dy, '\n'); } isFirst = FALSE; dyStringAppendC(dy, '"'); dyStringPrintf(dy, "/software/%s/", software->metaUuid); dyStringAppendC(dy, '"'); } } if (!isFirst) dyStringAppendC(dy, '\n'); jsonWriteListEnd(jw); /* Done with writing software list */ /* Write input list */ jsonWriteListStart(jw, "inputs"); int i; for (i=0; i<step->inCount; ++i) { jsonWriteObjectStart(jw); jsonWriteString(jw, "format", step->inputFormats[i]); jsonWriteString(jw, "name", step->inputTypes[i]); jsonWriteString(jw, "description", step->inputDescriptions[i]); jsonWriteObjectEnd(jw); } jsonWriteListEnd(jw); /* Write output list */ jsonWriteListStart(jw, "outputs"); for (i=0; i<step->outCount; ++i) { jsonWriteObjectStart(jw); jsonWriteString(jw, "format", step->outputFormats[i]); jsonWriteString(jw, "name", step->outputTypes[i]); jsonWriteString(jw, "description", step->outputDescriptions[i]); jsonWriteObjectEnd(jw); } jsonWriteListEnd(jw); jsonWriteObjectEnd(jw); return jw; }
static struct jsonWrite *rTdbToJw(struct trackDb *tdb, struct hash *fieldHash, struct hash *excludeTypesHash, int depth, int maxDepth) /* Recursively build and return a new jsonWrite object with JSON for tdb and its children, * or NULL if tdb or all children have been filtered out by excludeTypesHash. * If excludeTypesHash is non-NULL, omit any tracks/views/subtracks with type in excludeTypesHash. * If fieldHash is non-NULL, include only the field names indexed in fieldHash. */ { if (maxDepth >= 0 && depth > maxDepth) return NULL; boolean doSubtracks = (tdb->subtracks && fieldOk("subtracks", fieldHash)); // If excludeTypesHash is given and tdb is a leaf track/subtrack, look up the first word // of tdb->type in excludeTypesHash; if found, return NULL. if (excludeTypesHash && !doSubtracks) { char typeCopy[PATH_LEN]; safecpy(typeCopy, sizeof(typeCopy), tdb->type); if (hashLookup(excludeTypesHash, firstWordInLine(typeCopy))) return NULL; } boolean gotSomething = !doSubtracks; struct jsonWrite *jwNew = jsonWriteNew(); jsonWriteObjectStart(jwNew, NULL); writeTdbSimple(jwNew, tdb, fieldHash); if (tdb->parent && fieldOk("parent", fieldHash)) { // We can't link to an object in JSON and better not recurse here or else infinite loop. if (tdbIsSuperTrackChild(tdb)) { // Supertracks have been omitted from fullTrackList, so add the supertrack object's // non-parent/child info here. jsonWriteObjectStart(jwNew, "parent"); writeTdbSimple(jwNew, tdb->parent, fieldHash); jsonWriteObjectEnd(jwNew); } else // Just the name so we don't have infinite loops. jsonWriteString(jwNew, "parent", tdb->parent->track); } if (doSubtracks) { jsonWriteListStart(jwNew, "subtracks"); slSort(&tdb->subtracks, trackDbViewCmp); struct trackDb *subTdb; for (subTdb = tdb->subtracks; subTdb != NULL; subTdb = subTdb->next) { struct jsonWrite *jwSub = rTdbToJw(subTdb, fieldHash, excludeTypesHash, depth+1, maxDepth); if (jwSub) { gotSomething = TRUE; jsonWriteAppend(jwNew, NULL, jwSub); jsonWriteFree(&jwSub); } } jsonWriteListEnd(jwNew); } jsonWriteObjectEnd(jwNew); if (! gotSomething) // All children were excluded; clean up and null out jwNew. jsonWriteFree(&jwNew); return jwNew; }
static void jsonWriteValueLabel(struct jsonWrite *jw, char *value, char *label) /* Assuming we're already in an object, write out value and label tags & strings. */ { jsonWriteString(jw, "value", value); jsonWriteString(jw, "label", label); }
void cartJsonGetGroupedTrackDb(struct cartJson *cj, struct hash *paramHash) /* Translate trackDb list (only a subset of the fields) into JSON array of track group objects; * each group contains an array of track objects that may have subtracks. Send it in a wrapper * object that includes the database from which it was taken; it's possible that by the time * this reaches the client, the user might have switched to a new db. */ { struct jsonWrite *jw = cj->jw; struct trackDb *fullTrackList = NULL; struct grp *fullGroupList = NULL; struct errCatch *errCatch = errCatchNew(); if (errCatchStart(errCatch)) { cartTrackDbInit(cj->cart, &fullTrackList, &fullGroupList, /* useAccessControl=*/TRUE); } errCatchEnd(errCatch); if (errCatch->gotError) { warn("%s", errCatch->message->string); jsonWriteObjectStart(jw, "groupedTrackDb"); jsonWriteString(jw, "db", cartString(cj->cart, "db")); jsonWriteListStart(jw, "groupedTrackDb"); jsonWriteListEnd(jw); jsonWriteObjectEnd(jw); return; } errCatchFree(&errCatch); struct hash *groupedTrackRefList = hashTracksByGroup(fullTrackList); // If the optional param 'fields' is given, hash the field names that should be returned. char *fields = cartJsonOptionalParam(paramHash, "fields"); struct hash *fieldHash = hashFromCommaString(fields); char *excludeTypes = cartJsonOptionalParam(paramHash, "excludeTypes"); struct hash *excludeTypesHash = hashFromCommaString(excludeTypes); // Also check for optional parameter 'maxDepth': int maxDepth = -1; char *maxDepthStr = cartJsonOptionalParam(paramHash, "maxDepth"); if (isNotEmpty(maxDepthStr)) maxDepth = atoi(maxDepthStr); jsonWriteObjectStart(jw, "groupedTrackDb"); jsonWriteString(jw, "db", cartString(cj->cart, "db")); jsonWriteListStart(jw, "groupedTrackDb"); int nonEmptyGroupCount = 0; struct grp *grp; for (grp = fullGroupList; grp != NULL; grp = grp->next) { struct slRef *tdbRefList = hashFindVal(groupedTrackRefList, grp->name); if (writeGroupedTrack(jw, grp->name, grp->label, fieldHash, excludeTypesHash, maxDepth, tdbRefList)) { nonEmptyGroupCount++; } } if (nonEmptyGroupCount == 0) { // Catch-all for assembly hubs that don't declare groups for their tracks: add All Tracks struct slRef *allTracks = sortedAllTracks(fullTrackList); (void)writeGroupedTrack(jw, "allTracks", "All Tracks", fieldHash, excludeTypesHash, maxDepth, allTracks); } jsonWriteListEnd(jw); jsonWriteObjectEnd(jw); }