3f06ffc10df40e72dfa18a150eeca23fda6b41df angie Thu Feb 8 13:42:04 2018 -0800 annoStreamDbPslPlus internally used a json config to join in CDS and sequence with the underlying PSL -- so annoStreamDbPslPlusNew did not accept an incoming config, so hgVai's RefSeq Status option was ignored. Add jsonObjectMerge so that the config from hgVai can be merged with the internal config, and make sure that the extra columns from the internal annoStreamDb are added to annoStreamDbPslPlusNew's asObj. We can't just use the internal annoStreamDb's asObj because the field names for CDS etc. fields would differ for refSeqAli vs ncbiRefSeq and column-matching to recognize annoStreamDbPslPlus would fail. refs #20948 diff --git src/lib/jsonParse.c src/lib/jsonParse.c index e1d4399..29216c2 100644 --- src/lib/jsonParse.c +++ src/lib/jsonParse.c @@ -64,30 +64,75 @@ struct jsonElement *newJsonNull() { struct jsonElement *ele = newJsonElement(jsonNull); ele->val.jeNull = NULL; return ele; } void jsonObjectAdd(struct jsonElement *h, char *name, struct jsonElement *ele) // Add a new element to a jsonObject; existing values are replaced. { if(h->type != jsonObject) errAbort("jsonObjectAdd called on element with incorrect type (%d)", h->type); hashReplace(h->val.jeHash, name, ele); } +void jsonListCat(struct jsonElement *listA, struct jsonElement *listB) +/* Add all values of listB to the end of listA. Neither listA nor listB can be NULL. */ +{ +if (!listA || !listB || listA->type != jsonList || listB->type != jsonList) + errAbort("jsonListMerge: both arguments must be non-NULL and have type jsonList"); +struct slRef *listAVals = jsonListVal(listA, "jsonListCat:listA"); +struct slRef *listBVals = jsonListVal(listB, "jsonListCat:listB"); +if (listAVals == NULL) + listA->val.jeList = listBVals; +else + { + struct slRef *ref = listAVals; + while (ref && ref->next) + ref = ref->next; + ref->next = listBVals; + } +} + +void jsonObjectMerge(struct jsonElement *objA, struct jsonElement *objB) +/* Recursively merge fields of objB into objA. Neither objA nor objB can be NULL. + * If objA and objB each have a list child with the same key then concatenate the lists. + * If objA and objB each have an object child with the same key then merge the object children. + * If objA and objB each have a child of some other type then objB's child replaces objA's child. */ +{ +if (!objA || !objB || objA->type != jsonObject || objB->type != jsonObject) + errAbort("jsonObjectMerge: both arguments must be non-NULL and have type jsonObject"); +struct hash *objAHash = jsonObjectVal(objA, "jsonObjectMerge:objA"); +struct hash *objBHash = jsonObjectVal(objB, "jsonObjectMerge:objB"); +struct hashCookie cookie = hashFirst(objBHash); +struct hashEl *hel; +while ((hel = hashNext(&cookie)) != NULL) + { + struct jsonElement *elA = hashFindVal(objAHash, hel->name); + struct jsonElement *elB = hel->val; + if (elA == NULL || elA->type != elB->type) + jsonObjectAdd(objA, hel->name, elB); + else if (elA->type == jsonObject) + jsonObjectMerge(elA, elB); + else if (elA->type == jsonList) + jsonListCat(elA, elB); + else + elA->val = elB->val; + } +} + void jsonListAdd(struct jsonElement *list, struct jsonElement *ele) { if(list->type != jsonList) errAbort("jsonListAdd called on element with incorrect type (%d)", list->type); struct slRef *el; AllocVar(el); el->val = ele; slAddHead(&list->val.jeList, el); } static void skipLeadingSpacesWithPos(char *s, int *posPtr) /* skip leading white space. */ { for (;;) {