*! version 0.4.3 program educationdata version 11.0 mata: if (findfile("libjson.mlib") != "") {} else stata("ssc install libjson"); mata: if (libjson::checkVersion((1,0,2))) {} else printf("{err: The JSON library version is not compatible with this command and so will likely fail. Please update libjson by running the following: ado uninstall libjson, then run: ssc install libjson}\n"); syntax using/ , [SUBset(string)] [COLumns(string)] [SUMMARIES(string)] [CLEAR] [METAdata] [STAGING] [CSV] [CACHE] [DEBUG] mata: dummy=getalldata("`using'", "`columns'", "`subset'", "`summaries'", strlen("`clear'"),strlen("`metadata'"),strlen("`staging'"),strlen("`csv'"),strlen("`cache'"),strlen("`debug'")); end mata // Beginning section above and some structure borrowed from insheetjson - thanks!; // Helper function that returns results node pointer (class libjson scalar) scalar getresults(string scalar url){ pointer (class libjson scalar) scalar root pointer (class libjson scalar) scalar result if (st_global("debug_ind") == "1") printf(urlmode(url) + "\n") root = libjson::webcall(urlmode(url) ,""); result = root->getNode("results") return(result) } // Helper function that returns matrix of variable information from API string matrix getvarinfo(string scalar url){ pointer (class libjson scalar) scalar res pointer (class libjson scalar) scalar trow pointer (class libjson scalar) scalar result string scalar tempvar string scalar tempind real scalar numrows real scalar numrowscheck res = getresults(url) numrows = res->arrayLength() if (numrows == 0){ temp = raise_error() return("") } varinfo = J(6,numrows,"") for (r=1; r<=numrows; r++) { trow = res->getArrayValue(r) varinfo[1,r] = trow->getString("variable", "") varinfo[2,r] = trow->getString("label", "") tempvar = trow->getString("data_type", "") if (tempvar == "integer" || tempvar == "float") varinfo[3,r] = "double" else if (tempvar == "string"){ varinfo[3,r] = "str" + trow->getString("string_length", "") } varinfo[5,r] = trow->getString("format", "") if (varinfo[5,r] != varinfo[1,r] && varinfo[5,r] != "string" && varinfo[5,r] != "numeric"){ result = getresults(st_global("base_url") + "/api/v1/api-values/?format_name=" + varinfo[5,r]) } else result = getresults(st_global("base_url") + "/api/v1/api-values/?format_name=" + varinfo[1,r]) numrowscheck = result->arrayLength() if (numrowscheck == 0) varinfo[4,r] = "0" else varinfo[4,r] = "1" varinfo[6,r] = trow->getString("is_filter", "") } return(varinfo) } // Parse metadata to get api endpoint strings, years, and required selectors from enpoint URL string matrix endpointstrings(){ pointer (class libjson scalar) scalar res1 pointer (class libjson scalar) scalar trow string matrix endpointdata res1 = getresults(st_global("base_url") + "/api/v1/api-endpoints/") numrows = res1->arrayLength() endpointdata = J(3,numrows,"") for (r=1; r<=numrows; r++){ trow = res1->getArrayValue(r) endpointdata[1,r] = trow->getString("endpoint_id", "") endpointdata[2,r] = trow->getString("endpoint_url", "") endpointdata[3,r] = trow->getString("years_available", "") } return(endpointdata) } // Helper function to parse url endpoint strings into required variables string rowvector parseurls(string scalar url, string scalar typevar){ string rowvector splits string scalar splitr string scalar keepvars real scalar stopme url = subinstr(url, "/api/v1/", "") t = tokeninit("/") s = tokenset(t, url) splits = tokengetall(t) keepvars = "" if (typevar == "optional"){ for (r=1; r<=length(splits); r++){ splitr = subinstr(subinstr(splits[r], "{", ""), "}", "") if (splitr != splits[r]){ if (keepvars == "") keepvars = keepvars + splitr else keepvars = keepvars + "," + splitr } } } else{ for (r=1; r<=length(splits); r++){ splitr = subinstr(subinstr(splits[r], "{", ""), "}", "") if (splitr == splits[r]){ if (keepvars == "") keepvars = keepvars + splits[r] else keepvars = keepvars + "," + splits[r] } } } t = tokeninit(",") s = tokenset(t, keepvars) return(tokengetall(t)) } // Helper function to parse required data as inputs, check validity, and return endpoint chosen real scalar validendpoints(string scalar eps){ string matrix endpoints string rowvector epsind string rowvector parsedurls real scalar check real scalar permcheck endpoints = endpointstrings() epsind = tokens(eps) permcheck = 0 for (c=1; c<=length(endpoints[2,.]); c++){ parsedurls = parseurls(endpoints[2,c], "required") if (length(parsedurls) == length(epsind)){ check = 1 for (r=1; r<=length(epsind); r++){ if (epsind[r] == parsedurls[r]) check = check * 1 else check = check * 0 } if (check == 1) permcheck = c } } return(permcheck) } // Helper function to parse years available for endpoint string rowvector parseyears(real scalar matid){ string matrix endpoints string rowvector getit string rowvector getit2 string rowvector returnyears string scalar yrs string scalar yrstring string scalar yrstring2 endpoints = endpointstrings() yrs = endpoints[3,matid] if (subinstr(subinstr(yrs, ",", ""), "–", "") == yrs){ returnyears = (yrs) } else if (subinstr(yrs, "and", "") != yrs){ yrs = subinstr(subinstr(yrs, " ", ""), "and", "") t = tokeninit(",") s = tokenset(t, yrs) getit = tokengetall(t) yrstring = subinstr(yrs, "," + getit[length(getit)], "") t = tokeninit("–") s = tokenset(t, getit[length(getit)]) getit = tokengetall(t) for (y=strtoreal(getit[1]); y<=strtoreal(getit[2]); y++){ yrstring = yrstring + "," + strofreal(y) } t = tokeninit(",") s = tokenset(t, yrstring) returnyears = tokengetall(t) } else if (subinstr(yrs, ",", "") != yrs){ t = tokeninit(", ") s = tokenset(t, yrs) getit = tokengetall(t) yrstring = "" for (c=1; c<=length(getit); c++){ if (subinstr(getit[c], "–", "") != getit[c]){ t = tokeninit("–") s = tokenset(t, getit[c]) getit2 = tokengetall(t) if (c == 1) yrstring = getit2[c] else yrstring = yrstring + "," + getit2[1] for (y=strtoreal(getit2[1])+1; y<=strtoreal(getit2[2]); y++){ yrstring = yrstring + "," + strofreal(y) } } else{ if (c == 1) yrstring = getit[c] else yrstring = yrstring + "," + getit[c] } } t = tokeninit(",") s = tokenset(t, yrstring) returnyears = tokengetall(t) } else { t = tokeninit("–") s = tokenset(t, yrs) getit = tokengetall(t) yrstring = getit[1] for (y=strtoreal(getit[1])+1; y<=strtoreal(getit[2]); y++){ yrstring = yrstring + "," + strofreal(y) } t = tokeninit(",") s = tokenset(t, yrstring) returnyears = tokengetall(t) } return(returnyears) } // Helper function to validate a single option against the list of valid options real scalar isvalid(string scalar test, string rowvector vopts){ real scalar isopt isopt = 0 for (c = 1; c<=length(vopts); c++){ if (vopts[c] == test) return(1) } return(0) } // Helper function to get the position of a string in a list real scalar stringpos(string scalar test, string rowvector tlist){ for (r = 1; r<=length(tlist); r++){ if (test == tlist[r]) return(r) } return(0) } // Helper function to check if item is in a list real scalar iteminlist(string scalar i, string rowvector tlist){ real scalar isinlist isinlist = 0 for (r=1; r<=length(tlist); r++){ if (i == tlist[r]) isinlist = 1 } return(isinlist) } // Helper function to check number of item in list real scalar iteminlistnum(string scalar i, string rowvector tlist){ real scalar isinlist isinlist = 0 for (r=1; r<=length(tlist); r++){ if (i == tlist[r]) isinlist = r } return(isinlist) } // Helper function to add mode logging to URLs for API tracking string scalar urlmode(string scalar url3){ string scalar strnum if (strpos(url3, "mode=stata") == 0){ if (subinstr(url3, "?", "") == url3) url3 = url3 + "?mode=stata" else url3 = url3 + "&mode=stata" } strnum = strofreal(round(runiform(1,1)*100000)) if (st_global("cc") == "1") url3 = url3 + "&a=" + strnum return(url3) } // Helper function to validate against list string rowvector checkinglist(string rowvector alist, string scalar tocheck, string rowvector yearlist){ string rowvector tochecklist string rowvector toaddlist string rowvector validlist string scalar returnlist if (tocheck == "grade") { tochecklist = ("grade-pk","grade-k","grade-1","grade-2","grade-3","grade-4","grade-5","grade-6","grade-7","grade-8","grade-9","grade-10","grade-11","grade-12","grade-13","grade-14","grade-15","grade-99","grade-999") toaddlist = ("pk","k","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","99","999") } else if (tocheck == "grade_edfacts") { tochecklist = ("grade-3","grade-4","grade-5","grade-6","grade-7","grade-8","grade-9","grade-99") toaddlist = ("3","4","5","6","7","8","9","99") } else if (tocheck == "level_of_study") tochecklist = ("undergraduate","graduate","first-professional","post-baccalaureate","1","2","3","4") else if (tocheck == "fed_aid_type") tochecklist = ("fed","sub-stafford","no-pell-stafford","1","2","3") else if (tocheck == "year") tochecklist = yearlist else return(alist) for (c=1; c<=length(alist); c++){ if (iteminlist(alist[c],tochecklist) == 0) { if ((tocheck == "grade" || tocheck == "grade_edfacts") && (alist[c] == "-1" || alist[c] == "0")){ if (alist[c] == "-1") alist[c] = "grade-pk" else alist[c] = "grade-k" } else if ((tocheck != "grade" && tocheck != "grade_edfacts") || iteminlist(alist[c],toaddlist) == 0){ if (tocheck == "grade" || tocheck == "grade_edfacts") validlist = toaddlist else validlist = tochecklist for (r=1; r<=length(validlist); r++){ if (r == 1) returnlist = validlist[r] else returnlist = returnlist + ", " + validlist[r] } return(("Error",alist[c],returnlist)) } else alist[c] = "grade-" + alist[c] } } return(alist) } // Helper function to parse optional data as inputs, taking a single optional data argument, check validity, and return all chosen options string rowvector validoptions(string scalar subset1, real scalar epid){ string matrix endpoints string rowvector grades string rowvector levels string rowvector fedaids string rowvector vopts string rowvector getit string rowvector tlev string rowvector years string rowvector checklist string scalar getstring string scalar tempadd string scalar keepg1 real scalar isopt1 real scalar spos1 real scalar spos2 real scalar isgrade endpoints = endpointstrings() t = tokeninit("=") s = tokenset(t, subset1) getit = tokengetall(t) vopts = parseurls(endpoints[2,epid], "optional") isopt1 = isvalid(getit[1], vopts) if (isopt1 == 1){ grades = ("pk","k","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","99","999") grades_alt = ("-1","0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","99","999") gradesed = ("3","4","5","6","7","8","9","99") gradesed_alt = ("3","4","5","6","7","8","9","99") levels = ("undergraduate","graduate","first-professional","post-baccalaureate") fedaids = ("fed","sub-stafford","no-pell-stafford") if (getit[1] == "year") years = parseyears(epid) else years = ("fake","data") if (getit[2] != "alldata"){ if (subinstr(subinstr(getit[2], ",", ""), ":", "") == getit[2]){ checklist = checkinglist((getit[2]), getit[1], years) if (checklist[1] == "Error") return(("Invalid Option: " + checklist[2] + " in " + getit[1] + "\nValid options are: " + checklist[3], "")) else return(checklist) } else if (subinstr(getit[2], ",", "") != getit[2]){ t = tokeninit(",") s = tokenset(t, getit[2]) checklist = checkinglist(tokengetall(t), getit[1], years) if (checklist[1] == "Error") return(("Invalid Option: " + checklist[2] + " in " + getit[1] + "\nValid options are: " + checklist[3], "")) else return(checklist) } else{ tempadd = "" isgrade = 0 if (getit[1] == "year") tlev = years else if (getit[1] == "grade"){ tlev = grades tempadd = "grade-" isgrade = 1 } else if (getit[1] == "grade_edfacts"){ tlev = gradesed tempadd = "grade-" isgrade = 2 } else if (getit[1] == "level_of_study") tlev = levels else if (getit[1] == "fed_aid_type") tlev = fedaids keepg1 = getit[1] t = tokeninit(":") s = tokenset(t, getit[2]) getit = tokengetall(t) if (isvalid(getit[1], tlev) == 1 && isvalid(getit[2], tlev) == 1){ spos1 = stringpos(getit[1], tlev) spos2 = stringpos(getit[2], tlev) getstring = tempadd + tlev[spos1] for (c=spos1 + 1; c<=spos2; c++){ getstring = getstring + "," + tempadd + tlev[c] } t = tokeninit(",") s = tokenset(t, getstring) checklist = checkinglist(tokengetall(t), getit[1], years) if (checklist[1] == "Error") return(("Invalid Option: " + checklist[2] + " in " + getit[1] + "\nValid options are: " + checklist[3], "")) else return(checklist) } else if (isgrade == 1 && (isvalid(getit[1], grades_alt) == 1 && isvalid(getit[2], grades_alt) == 1)){ spos1 = stringpos(getit[1], grades_alt) spos2 = stringpos(getit[2], grades_alt) getstring = tempadd + tlev[spos1] for (c=spos1 + 1; c<=spos2; c++){ getstring = getstring + "," + tempadd + tlev[c] } t = tokeninit(",") s = tokenset(t, getstring) checklist = checkinglist(tokengetall(t), getit[1], years) if (checklist[1] == "Error") return(("Invalid Option: " + checklist[2] + " in " + getit[1] + "\nValid options are: " + checklist[3], "")) else return(checklist) } else if (isgrade == 2 && (isvalid(getit[1], gradesed_alt) == 1 && isvalid(getit[2], gradesed_alt) == 1)){ spos1 = stringpos(getit[1], gradesed_alt) spos2 = stringpos(getit[2], gradesed_alt) getstring = tempadd + tlev[spos1] for (c=spos1 + 1; c<=spos2; c++){ getstring = getstring + "," + tempadd + tlev[c] } t = tokeninit(",") s = tokenset(t, getstring) checklist = checkinglist(tokengetall(t), getit[1], years) if (checklist[1] == "Error") return(("Invalid Option: " + checklist[2] + " in " + getit[1] + "\nValid options are: " + checklist[3], "")) else return(checklist) } else { if (isvalid(getit[1], tlev) == 0){ checklist = checkinglist((getit[1]),keepg1, years) return(("Invalid Option selection: " + getit[1] + " in " + keepg1 + "\nValid options are: " + checklist[3], "")) } else{ checklist = checkinglist((getit[2]),keepg1, years) return(("Invalid Option selection: " + getit[2] + " in " + keepg1 + "\nValid options are: " + checklist[3], "")) } } } } else{ tempadd = "" if (getit[1] == "year") tlev = years else if (getit[1] == "grade"){ tlev = grades tempadd = "grade-" } else if (getit[1] == "grade_edfacts"){ tlev = gradesed tempadd = "grade-" } else if (getit[1] == "level_of_study") tlev = levels else if (getit[1] == "fed_aid_type") tlev = fedaids getstring = tempadd + tlev[1] for (c=2; c<=length(tlev); c++){ getstring = getstring + "," + tempadd + tlev[c] } t = tokeninit(",") s = tokenset(t, getstring) return(tokengetall(t)) } } else return(("Invalid Option: " + getit[1])) } // Helper function that returns string and real/integer variable names string rowvector getvartypes(string scalar typ, string matrix varinfo){ real scalar counting real scalar counter1 string scalar varnametypes real scalar numvars numvars = length(varinfo[1,.]) counting = 0 for (c=1; c<=numvars; c++){ if (subinstr(varinfo[3,c], "str", "") != varinfo[3,c]){ if (typ == "string") counting = counting + 1 } else { if (typ != "string") counting = counting + 1 } } varnametypes = J(1,counting,"") counter1 = 1 for (c=1; c<=numvars; c++){ if (subinstr(varinfo[3,c], "str", "") != varinfo[3,c]){ if (typ == "string") { varnametypes[1,counter1] = varinfo[1,c] counter1 = counter1 + 1 } } else { if (typ != "string") { varnametypes[1,counter1] = varinfo[1,c] counter1 = counter1 + 1 } } } return(varnametypes) } // Helper function to get variable value definitions string matrix getvardefs(string scalar var1, string scalar format1){ pointer (class libjson scalar) scalar result pointer (class libjson scalar) scalar trow string matrix vardefs string rowvector tokenstemp string scalar tempvar string scalar tempstring real scalar numrows real scalar startvar if (format1 != var1 && format1 != "string" && format1 != "numeric"){ result = getresults(st_global("base_url") + "/api/v1/api-values/?format_name=" + format1) } else result = getresults(st_global("base_url") + "/api/v1/api-values/?format_name=" + var1) numrows = result->arrayLength() vardefs = J(2,numrows,"") for (r=1; r<=numrows; r++){ trow = result->getArrayValue(r) vardefs[1,r] = trow->getString("code", "") tempvar = trow->getString("code_label", "") tokenstemp = tokens(tempvar, "-") if (tokenstemp[1] == "-") startvar = 4 else startvar = 3 tempstring = "" for (i=startvar; i<=length(tokenstemp); i++){ tempstring = tempstring + tokenstemp[i] if (i != length(tokenstemp)) tempstring = tempstring + " " } vardefs[2,r] = subinstr(tempstring, "–", "–") vardefs[2,r] = subinstr(vardefs[2,r], "—", "—") vardefs[2,r] = subinstr(vardefs[2,r], " - ", "-") vardefs[2,r] = subinstr(vardefs[2,r], " – ", "–") vardefs[2,r] = subinstr(vardefs[2,r], " — ", "—") } return(vardefs) } // Get table just gets data we need for one table, this appends results to the stata dataset string scalar gettable(string scalar url, real scalar startpos, string matrix varinfo){ pointer (class libjson scalar) scalar root pointer (class libjson scalar) scalar result pointer (class libjson scalar) scalar trow string matrix sdata string rowvector varnames string scalar nextpage string scalar tval real matrix rdata real scalar numrows real scalar endpos if (st_global("debug_ind") == "1") printf(urlmode(url) + "\n") root = libjson::webcall(urlmode(url) ,""); result = root->getNode("results") numrows = result->arrayLength() varinfotemp = J(6,length(varinfo[1,.]),"") for (c=1; c<=length(varinfo[1,.]); c++){ varinfotemp[1,c] = strlower(varinfo[1,c]) varinfotemp[3,c] = varinfo[3,c] } if (numrows > 0){ st_addobs(numrows) endpos = startpos + numrows - 1 svarnames = getvartypes("string", varinfo) rvarnames = getvartypes("other", varinfo) svarnamestemp = getvartypes("string", varinfotemp) rvarnamestemp = getvartypes("other", varinfotemp) sdata = J(numrows,length(svarnames),"") rdata = J(numrows,length(rvarnames),.) for (r=1; r<=numrows; r++) { trow = result->getArrayValue(r); for(c=1; c<=length(svarnames); c++) { tval = trow->getString(svarnames[c],""); if (tval == "null") tval = "" if (tval == `"""' + `"""') tval = "" sdata[r,c] = tval } for(c=1; c<=length(rvarnames); c++) { tval = trow->getString(rvarnames[c],""); if (tval == "null") rdata[r,c] = . else rdata[r,c] = strtoreal(tval) } } if (length(svarnames) > 0){ st_sview(SV,(startpos..endpos)',svarnamestemp) SV[.,.] = sdata[.,.] } if (length(rvarnames) > 0){ st_view(V,(startpos..endpos)',rvarnamestemp) V[.,.] = rdata[.,.] } nextpage = root->getString("next", "") return(nextpage) } else return("null") } string scalar gettable_summaries(string scalar url, real scalar startpos, string matrix varinfo){ pointer (class libjson scalar) scalar root pointer (class libjson scalar) scalar result pointer (class libjson scalar) scalar trow string matrix sdata string rowvector varnames string scalar nextpage string scalar tval real matrix rdata real scalar numrows real scalar endpos if (st_global("debug_ind") == "1") printf(urlmode(url) + "\n") root = libjson::webcall(url ,""); result = root->getNode("results") numrows = result->arrayLength() varinfotemp = J(6,length(varinfo[1,.]),"") for (c=1; c<=length(varinfo[1,.]); c++){ varinfotemp[1,c] = strlower(varinfo[1,c]) varinfotemp[3,c] = varinfo[3,c] } if (numrows > 0){ st_addobs(numrows) endpos = startpos + numrows - 1 svarnames = getvartypes("string", varinfo) rvarnames = getvartypes("other", varinfo) svarnamestemp = getvartypes("string", varinfotemp) rvarnamestemp = getvartypes("other", varinfotemp) sdata = J(numrows,length(svarnames),"") rdata = J(numrows,length(rvarnames),.) for (r=1; r<=numrows; r++) { trow = result->getArrayValue(r); for(c=1; c<=length(svarnames); c++) { tval = trow->getString(svarnames[c],""); if (tval == "null") tval = "" if (tval == `"""' + `"""') tval = "" sdata[r,c] = tval } for(c=1; c<=length(rvarnames); c++) { tval = trow->getString(rvarnames[c],""); if (tval == "null") rdata[r,c] = . else rdata[r,c] = strtoreal(tval) } } if (length(svarnames) > 0){ st_sview(SV,(startpos..endpos)',svarnamestemp) SV[.,.] = sdata[.,.] } if (length(rvarnames) > 0){ st_view(V,(startpos..endpos)',rvarnamestemp) V[.,.] = rdata[.,.] } nextpage = root->getString("next", "") return(nextpage) } else return("null") } // Helper function to create query strings ?var=x for all potential subset combinations string scalar getquerystrings(string scalar additions){ string rowvector result1 string rowvector result2 string rowvector result3 string scalar staticstring string scalar dynamicstring real scalar countstatic if (additions == "") return("") t = tokeninit(";") s = tokenset(t, additions) result1 = tokengetall(t) countstatic = 1 staticstring = "" for (c=1; c<=length(result1); c++){ t = tokeninit("=") s = tokenset(t, result1[c]) result2 = tokengetall(t) if (subinstr(result2[2], ":", "") == result2[2]){ if (countstatic == 1) staticstring = staticstring + result1[c] else staticstring = staticstring + "&" + result1[c] countstatic = countstatic + 1 } else{ t = tokeninit(":") s = tokenset(t, result2[2]) result3 = tokengetall(t) dynamicstring = "" for (r=strtoreal(result3[1]); r<=strtoreal(result3[2]); r++){ if (r == strtoreal(result3[1])) dynamicstring = dynamicstring + result2[1] + "=" + strofreal(r) else dynamicstring = dynamicstring + "," + strofreal(r) } if (countstatic == 1) staticstring = staticstring + dynamicstring else staticstring = staticstring + "&" + result1[c] countstatic = countstatic + 1 } } return("?" + staticstring) } // Helper function to create dataset real scalar createdataset(string scalar eid){ string matrix varinfo string matrix vardef string scalar labeldef string scalar labelshort varinfo = getvarinfo(st_global("base_url") + "/api/v1/api-endpoint-varlist/?endpoint_id=" + eid) for (c=1; c<=length(varinfo[1,.]); c++){ varinfo[1,c] = strlower(varinfo[1,c]) } temp1 = st_addvar(varinfo[3,.],varinfo[1,.]) for (c=1; c<=length(varinfo[1,.]); c++){ varinfo[2,c] = subinstr(varinfo[2,c], "—", "—") varinfo[2,c] = subinstr(varinfo[2,c], "–", "–") stata("qui label var " + varinfo[1,c] + " " + `"""' + varinfo[2,c] + `"""') if (strlen(varinfo[1,c]) > 30) labelshort = substr(varinfo[1,c], 1, 30) + "df" else labelshort = varinfo[1,c] + "df" if (varinfo[4,c] == "1"){ vardef = getvardefs(varinfo[1,c], varinfo[5,c]) labeldef = "qui label define " + labelshort + " " for (r=1; r<=length(vardef[1,.]); r++){ labeldef = labeldef + vardef[1,r] + " " + `"""' + vardef[2,r] + `"""' if (r != length(vardef[1,.])) labeldef = labeldef + " " } labeldef = labeldef + ", replace" stata(labeldef) stata("qui label values " + varinfo[1,c] + " " + labelshort) } else if (varinfo[3,c] == "float"){ labeldef = "qui label define " + labelshort + " -1 " + `"""' + "Missing/Not reported" + `"""' + " -2 " + `"""' + "Not applicable" + `"""' + " -3 " + `"""' + "Suppressed data" + `"""' + ", replace" stata(labeldef) stata("qui label values " + varinfo[1,c] + " " + labelshort) } else if (varinfo[3,c] == "double"){ labeldef = "qui label define " + labelshort + " -1 " + `"""' + "Missing/Not reported" + `"""' + " -2 " + `"""' + "Not applicable" + `"""' + " -3 " + `"""' + "Suppressed data" + `"""' + ", replace" stata(labeldef) stata("qui label values " + varinfo[1,c] + " " + labelshort + ", nofix") } } return(1) } // Helper function to create dataset real scalar createdataset_summaries_ep(string matrix varinfo){ string matrix vardef string scalar labeldef string scalar labelshort for (c=1; c<=length(varinfo[1,.]); c++){ varinfo[1,c] = strlower(varinfo[1,c]) } temp1 = st_addvar(varinfo[3,.],varinfo[1,.]) for (c=1; c<=length(varinfo[1,.]); c++){ varinfo[2,c] = subinstr(varinfo[2,c], "—", "—") varinfo[2,c] = subinstr(varinfo[2,c], "–", "–") stata("qui label var " + varinfo[1,c] + " " + `"""' + varinfo[2,c] + `"""') if (strlen(varinfo[1,c]) > 30) labelshort = substr(varinfo[1,c], 1, 30) + "df" else labelshort = varinfo[1,c] + "df" if (varinfo[4,c] == "1"){ vardef = getvardefs(varinfo[1,c], varinfo[5,c]) labeldef = "qui label define " + labelshort + " " for (r=1; r<=length(vardef[1,.]); r++){ labeldef = labeldef + vardef[1,r] + " " + `"""' + vardef[2,r] + `"""' if (r != length(vardef[1,.])) labeldef = labeldef + " " } labeldef = labeldef + ", replace" stata(labeldef) stata("qui label values " + varinfo[1,c] + " " + labelshort) } else if (varinfo[3,c] == "float"){ labeldef = "qui label define " + labelshort + " -1 " + `"""' + "Missing/Not reported" + `"""' + " -2 " + `"""' + "Not applicable" + `"""' + " -3 " + `"""' + "Suppressed data" + `"""' + ", replace" stata(labeldef) stata("qui label values " + varinfo[1,c] + " " + labelshort) } else if (varinfo[3,c] == "double"){ labeldef = "qui label define " + labelshort + " -1 " + `"""' + "Missing/Not reported" + `"""' + " -2 " + `"""' + "Not applicable" + `"""' + " -3 " + `"""' + "Suppressed data" + `"""' + ", replace" stata(labeldef) stata("qui label values " + varinfo[1,c] + " " + labelshort + ", nofix") } } return(1) } // Helper function to translate short dataset name to full name string scalar shorttolongname(string scalar shortname, string matrix eps){ string rowvector voptions string rowvector result1 string scalar toreturn result1 = tokens(shortname) if (length(result1) < 2) return("Error1") if (result1[1] == "school") st1 = "schools" else if (result1[1] == "district") st1 = "school-districts" else if (result1[1] == "college") st1 = "college-university" else return("Error2") result1[1] = st1 toreturn = "" for (r=1; r<=length(result1); r++){ if (r == 1) toreturn = toreturn + result1[r] else toreturn = toreturn + " " + result1[r] } return(toreturn) } // Helper function to reformat summaries subcommand to endpoint URLs string scalar getsummariesurl(string scalar dataoptions, string scalar summaries_cmd){ string scalar ep_url string scalar agg_method string scalar var_to_agg string scalar agg_by string rowvector token_cmd ep_url = "/api/v1/" for (c=1; c<=length(tokens(dataoptions)); c++){ ep_url = ep_url + tokens(dataoptions)[c] + "/" } ep_url = ep_url + "summaries/" token_cmd = tokens(summaries_cmd) agg_method = token_cmd[1] var_to_agg = token_cmd[2] agg_by = "" for (c=4; c<=length(token_cmd); c++){ if (c != length(token_cmd)){ agg_by = agg_by + token_cmd[c] + "," } else { agg_by = agg_by + token_cmd[c] } } ep_url = ep_url + "?stat=" + agg_method + "&by=" + agg_by + "&var=" + var_to_agg return(ep_url) } // Helper function for time taken string scalar timeit(real scalar timeper){ string scalar timetaken if (hhC(timeper) == 0 && mmC(timeper) == 0) timetaken = "less than one minute" else if (hhC(timeper) == 0) timetaken = strofreal(mmC(timeper)) + " minute(s)" else timetaken = strofreal(hhC(timeper)) + " hour(s) and " + strofreal(mmC(timeper)) + " minute(s)" return(timetaken) } // Provide CSV download with numbered list of columns that should be strings string scalar numliststr(string matrix varinfo2){ string rowvector varnames string scalar nliststr real scalar listnum varnames = st_varname((1..st_nvar())) nliststr = "" for (c=1; c<=length(varinfo2[1,.]); c++){ if (varinfo2[5,c] == "string"){ listnum = iteminlistnum(varinfo2[1,c], varnames) if (nliststr == "") nliststr = strofreal(listnum) else nliststr = nliststr + " " + strofreal(listnum) } } return(nliststr) } // Label CSV dataset appropriately when it is loaded in real scalar labelcsv(string matrix varinfo2, real scalar init1){ string matrix vardef string scalar labeldef string scalar labelshort for (c=1; c<=length(varinfo2[1,.]); c++){ stata("qui label var " + varinfo2[1,c] + " " + `"""' + varinfo2[2,c] + `"""') if (strlen(varinfo2[1,c]) > 30) labelshort = substr(varinfo2[1,c], 1, 30) + "df" else labelshort = varinfo2[1,c] + "df" if (varinfo2[4,c] == "1"){ if (init1 == 1){ vardef = getvardefs(varinfo2[1,c], varinfo2[5,c]) labeldef = "qui label define " + labelshort + " " for (r=1; r<=length(vardef[1,.]); r++){ labeldef = labeldef + vardef[1,r] + " " + `"""' + vardef[2,r] + `"""' if (r != length(vardef[1,.])) labeldef = labeldef + " " } labeldef = labeldef + ", replace" stata(labeldef) } stata("qui label values " + varinfo2[1,c] + " " + labelshort) } else if (varinfo2[3,c] == "float"){ if (init1 == 1){ labeldef = "qui label define " + labelshort + " -1 " + `"""' + "Missing/Not reported" + `"""' + " -2 " + `"""' + "Not applicable" + `"""' + " -3 " + `"""' + "Suppressed data" + `"""' + ", replace" stata(labeldef) } stata("qui label values " + varinfo2[1,c] + " " + labelshort) } else if (varinfo2[3,c] == "double"){ if (init1 == 1){ labeldef = "qui label define " + labelshort + " -1 " + `"""' + "Missing/Not reported" + `"""' + " -2 " + `"""' + "Not applicable" + `"""' + " -3 " + `"""' + "Suppressed data" + `"""' + ", replace" stata(labeldef) } stata("qui label values " + varinfo2[1,c] + " " + labelshort + ", nofix") } } return(1) } // Correct grade list for subsetting CSV files string scalar correctgrade(string scalar vopt1){ if (vopt1 == "grade-pk" || vopt1 == "pk") return("-1") else if (vopt1 == "grade-k" || vopt1 == "k") return("0") else return(subinstr(vopt1, "grade-", "")) } // Subset and keep relevant variables - keep if inlist(varname,val1,val2,etc.) real scalar subsetkeep(string matrix spops2, string scalar querystring2, real scalar epid2, string scalar vlist2){ string rowvector spopsres string rowvector voptions string rowvector queryparams string rowvector queryparamvals string rowvector queryparamlist string scalar keepstate string scalar keepbase keepbase = "qui keep if inlist(" for (r=1; r<=length(spops2[1,.]); r++){ t = tokeninit("=") s = tokenset(t, spops2[2,r]) spopsres = tokengetall(t) keepstate = keepbase + spops2[1,r] if (spopsres[2] != "alldata"){ voptions = validoptions(spops2[2,r], epid2) for (c=1; c<=length(voptions); c++){ keepstate = keepstate + "," + correctgrade(voptions[c]) } keepstate = keepstate + ")" stata(keepstate) } } querystring2 = subinstr(querystring2, "?", "") t = tokeninit("&") s = tokenset(t, querystring2) queryparams = tokengetall(t) for (r=1; r<=length(queryparams); r++){ t = tokeninit("=") s = tokenset(t, queryparams[r]) queryparamvals = tokengetall(t) keepstate = keepbase + queryparamvals[1] + "," + queryparamvals[2] + ")" stata(keepstate) } if (vlist2 != "") stata("keep " + vlist2) return(1) } // Download Local CSV to parse column order, keep it real scalar copycsv(string scalar tval1, string scalar tbaseurl1){ stata("qui copy " + tbaseurl1 + subinstr(tval1, " ", "") + " temp_eddata_file_gen_012345.csv, replace") stata("qui import delimited temp_eddata_file_gen_012345.csv, clear rowrange(1:1)") return(1) } // Download from CSV instead real scalar downloadcsv(string scalar eid1, string matrix spops1, string scalar ds1, real scalar epid1, string matrix varinfo1, string scalar querystring1, string scalar vlist1){ pointer (class libjson scalar) scalar results1 pointer (class libjson scalar) scalar trow string rowvector yearslist string rowvector relfiles string scalar tval string scalar tbaseurl string scalar addstrings string scalar liststrings string scalar relfilesstr real scalar dlyear real scalar numresults real scalar temp1 real scalar temp2 real scalar temp3 real scalar countfiles tbaseurl = st_global("base_url") + "/csv/" + ds1 + "/" results1 = getresults(st_global("base_url") + "/api/v1/api-downloads/?endpoint_id=" + eid1) yearslist = validoptions(spops1[2,1], epid1) numresults = results1->arrayLength() temp1 = 0 if (numresults == 1){ return(0) } if (numresults == 2){ printf("Downloading file, please wait...\n") tval = results1->getArrayValue(2)->getString("file_name", "") temp3 = copycsv(tval, tbaseurl) liststrings = numliststr(varinfo1) if (liststrings == "") addstrings = "" else addstrings = " stringcols(" + liststrings + ")" stata("clear") stata("qui import delimited temp_eddata_file_gen_012345.csv, clear" + addstrings) stata("qui rm temp_eddata_file_gen_012345.csv") temp1 = labelcsv(varinfo1, 1) temp2 = subsetkeep(spops1, querystring1, epid1, vlist1) } else{ printf("Progress for each CSV file will print to your screen. Please wait...\n\n") relfilesstr = "" for (r=1; r<=numresults; r++){ trow = results1->getArrayValue(r); tval = trow->getString("file_name",""); dlyear = 0 if (subinstr(tval, ".csv", "") != tval) dlyear = dlyear + 1 else dlyear = -10 for (c=1; c<=length(yearslist); c++){ if (subinstr(tval, yearslist[c], "") != tval) dlyear = dlyear + 1 } if (dlyear == 2){ if (relfilesstr == "") relfilesstr = tval else relfilesstr = relfilesstr + ";" + tval } } t = tokeninit(";") s = tokenset(t, relfilesstr) relfiles = tokengetall(t) for (r=1; r<=length(relfiles); r++){ if (r == 1){ temp3 = copycsv(relfiles[r], tbaseurl) liststrings = numliststr(varinfo1) if (liststrings == "") addstrings = "" else addstrings = " stringcols(" + liststrings + ")" stata("clear") } printf("Processing file " + strofreal(r) + " of " + strofreal(length(relfiles)) + "\n") stata("qui preserve") if (r == 1) { stata("qui import delimited temp_eddata_file_gen_012345.csv, clear" + addstrings) stata("qui rm temp_eddata_file_gen_012345.csv") } else stata("qui import delimited " + tbaseurl + subinstr(relfiles[r], " ", "") + ", clear" + addstrings) if (temp1 == 0) temp1 = labelcsv(varinfo1, 1) else temp1 = labelcsv(varinfo1, 0) temp2 = subsetkeep(spops1, querystring1, epid1, vlist1) stata("qui save temp_eddata_file_gen_012345, replace") stata("qui restore") stata("qui append using temp_eddata_file_gen_012345") } stata("qui rm temp_eddata_file_gen_012345.dta") } stata("qui compress") return(1) } // Gets all tables, using API to get the varlist and vartypes, and looping through all "nexts", calling gettable real scalar getalltables(string scalar eid, string scalar url2, real scalar totallen1, real scalar epcount1){ pointer (class libjson scalar) scalar root pointer (class libjson scalar) scalar results1 string matrix varinfo string scalar nextpage string scalar timea string scalar timetaken1 string scalar timetaken2 real scalar pagesize real scalar totalpages real scalar countpage real scalar timeper1 real scalar timeper2 varinfo = getvarinfo(st_global("base_url") + "/api/v1/api-endpoint-varlist/?endpoint_id=" + eid) if (st_global("debug_ind") == "1") printf(urlmode(st_global("base_url") + url2) + "\n") root = libjson::webcall(urlmode(st_global("base_url") + url2),""); results1 = root->getNode("results") pagesize = results1->arrayLength() totalpages = floor((strtoreal(root->getString("count", ""))) / pagesize) + 1 spos = 1 if (st_nobs() > 0) spos = st_nobs() + 1 countpage = 1 if (epcount1 == 1){ if (totalpages == .) totalpages = 1 timeper1 = 1500 * totalpages * totallen1 timeper2 = 10000 * totalpages * totallen1 timetaken1 = timeit(timeper1) timetaken2 = timeit(timeper2) timea = "\nI estimate that the download for the entire file you requested will take " if (timetaken1 == "less than one minute" && timetaken2 == "less than one minute") printf(timea + "less than one minute.\n") else if (timetaken1 == "less than one minute" && timetaken2 != "less than one minute") printf(timea + "less than " + timetaken2 + ".\n") else printf(timea + "between %s and %s.\n", timetaken1, timetaken2) printf("This is only an estimate, so actual time may vary due to internet speed and file size differences.\n\n") printf("Progress for each endpoint and call to the API will print to your screen. Please wait...\n") printf("If this time is too long for you to wait, try adding the " + `"""' + "csv" + `"""' + " option to the end of your command to download the full csv directly.\n") } printf("\nGetting data from %s, endpoint %s of %s (%s records).\n", url2, strofreal(epcount1), strofreal(totallen1), root->getString("count", "")) nextpage = gettable(st_global("base_url") + url2, spos, varinfo) if (nextpage!="null"){ do { spos = spos + pagesize countpage = countpage + 1 printf("Endpoint %s of %s: On page %s of %s\n", strofreal(epcount1), strofreal(totallen1), strofreal(countpage), strofreal(totalpages)) nextpage = gettable(nextpage, spos, varinfo) } while (nextpage!="null") } return(1) } real scalar raise_error(){ printf("\nThis Stata command is invalid. Please open the URL above in a browser for detailed error messages. More instructions can be found on the Education Data Portal Documentation Website (https://educationdata.urban.org/documentation/).") return(0) } // Gets all tables, using API to get the varlist and vartypes, and looping through all "nexts", calling gettable real scalar getalltables_summaries(string matrix varinfo, string scalar url2, real scalar totallen1, real scalar epcount1){ pointer (class libjson scalar) scalar root pointer (class libjson scalar) scalar results1 string scalar nextpage string scalar timea string scalar timetaken1 string scalar timetaken2 real scalar pagesize real scalar totalpages real scalar countpage real scalar timeper1 real scalar timeper2 if (st_global("debug_ind") == "1") printf(st_global("base_url") + url2 + "\n") root = libjson::webcall(st_global("base_url") + url2, ""); if (root){ results1 = root->getNode("results") pagesize = results1->arrayLength() totalpages = floor((strtoreal(root->getString("count", ""))) / pagesize) + 1 spos = 1 if (st_nobs() > 0) spos = st_nobs() + 1 countpage = 1 nextpage = gettable_summaries(st_global("base_url") + url2, spos, varinfo) return(1) } else{ error=raise_error() return(0) } } // helper function to get data from summary endpoints string scalar getsummarydata(string scalar dataoptions, string scalar summaries, string scalar opts, string scalar vlist){ string matrix varinfo real scalar spos string matrix summary_ep_url string rowvector allopts string rowvector token_cmd string matrix varinfo1 string matrix varinfo2 string matrix varinfo_groupby_var real scalar tempdata real scalar totallen real scalar epcount summary_ep_url = getsummariesurl(dataoptions, summaries) allopts = tokens(opts) for (i=1; i<=length(allopts); i++){ summary_ep_url = summary_ep_url + "&" + allopts[i] } printf("\n\nGetting data from: " + st_global("base_url") + summary_ep_url + "\n") token_cmd = tokens(summaries) var_to_agg = token_cmd[2] agg_by = "" token_cmd = select(token_cmd, token_cmd[1,.]:!="year") for (c=4; c<=length(token_cmd); c++){ if (c != length(token_cmd)){ agg_by = agg_by + token_cmd[c] + "," } else { agg_by = agg_by + token_cmd[c] } } if (strmatch(agg_by, "*,*") == 1) { groupby_lst = tokens(agg_by, ",") } else { groupby_lst = tokens(agg_by) } varinfo1 = getvarinfo(st_global("base_url") + "/api/v1/api-variables/?variable=year") varinfo_var_to_agg = getvarinfo(st_global("base_url") + "/api/v1/api-variables/?variable=" + var_to_agg) num_var = 2 + (length(groupby_lst) + 1)/2 var_attr = 6 varinfo = J(var_attr, num_var, "") for (r=1; r<=var_attr; r++){ varinfo[r, 1] = varinfo1[r, 1] } temp = 2 for (j=1; j<=length(groupby_lst); j++){ if (groupby_lst[j] != ","){ varinfo_groupby_var = getvarinfo(st_global("base_url") + "/api/v1/api-variables/?variable=" + groupby_lst[j]) for (r=1; r<=var_attr; r++){ varinfo[r, temp] = varinfo_groupby_var[r, 1] } temp = temp + 1 } } for (r=1; r<=var_attr; r++){ varinfo[r, temp] = varinfo_var_to_agg[r, 1] } spos = 1 epcount = 0 totallen = 1 tempdata = createdataset_summaries_ep(varinfo) for (i=1; i<=totallen; i++){ epcount = epcount + 1 alldata = getalltables_summaries(varinfo, summary_ep_url, totallen, epcount) } if (alldata == 1){ stata("qui compress") if (vlist != "") stata("keep " + vlist) else printf("\n\nData successfully loaded into Stata and ready to use.") } return("") } // Main function to get data based on Stata request - calls other helper functions string scalar getalldata(string scalar dataoptions, string scalar vlist, string scalar opts, string scalar summaries, real scalar clearme, real scalar metadataonly, real scalar staging, real scalar csv, real scalar clearcache, real scalar debugind){ string matrix endpoints string matrix spops string matrix varinfo string rowvector allopts string rowvector validopts string rowvector res2 string rowvector respre string rowvector temp1 string rowvector temp2 string scalar eid string scalar urltemp string scalar urladds string scalar querystring string scalar dataoptions1 string scalar validfilters string scalar ds string scalar summary_ep_url real scalar epid real scalar spos real scalar spos1 real scalar hidereturn real scalar totallen real scalar epcount real scalar tempdata real scalar temp3 real scalar test st_global("base_url","https://educationdata.urban.org") st_global("staging_url","https://educationdata-stg.urban.org") if (staging > 0) st_global("base_url", st_global("staging_url")) st_global("cc","0") if (clearcache > 0) st_global("cc","1") st_global("debug_ind", "0") if (debugind > 0) st_global("debug_ind", "1") X = st_data(.,.) if (clearme > 0) stata("clear") else{ if (length(X[.,.]) > 0) { printf("Error: You currently have data loaded in Stata. Please add " + `"""' + "clear" + `"""' + " to the end of this command if you wish to remove your current data.") return("") } else stata("clear") } endpoints = endpointstrings() dataoptions1 = shorttolongname(strlower(dataoptions), endpoints) if (strlen(summaries) > 0){ getsummarydata(dataoptions1, summaries, opts, vlist) return("") } else{ if (dataoptions1 == "Error1"){ printf("Error: You must enter the complete name of a dataset in the 'using' statement. The first is the 'short' name for the data category, and the remaining words are the unique name of the dataset. E.g., using " + `"""' + "school directory" + `"""' + ". Type " + `"""' + "help educationdata" + `"""' + " to learn more.") return("") } else if (dataoptions1 == "Error2"){ printf("Error: The option you selected was invalid. The three options are: " + `"""' + "school" + `"""' + ", " + `"""' + "district" + `"""' + ", and " + `"""' + "college" + `"""' + ". Type " + `"""' + "help educationdata" + `"""' + " to learn more.") return("") } epid = validendpoints(dataoptions1) if (epid == 0 || dataoptions1 == "Error3"){ printf("Error: The name of the category ('school', 'district', or 'college') is correct, but the name of the dataset you chose is not. Please verify the list of allowed options by typing " + `"""' + "help educationdata" + `"""' + ".") return("") } eid = endpoints[1,epid] varinfo = getvarinfo(st_global("base_url") + "/api/v1/api-endpoint-varlist/?endpoint_id=" + eid) for (c=1; c<=length(varinfo[1,.]); c++){ varinfo[1,c] = strlower(varinfo[1,c]) } validfilters = "" for (c=1; c<=length(varinfo[6,.]); c++){ /* varinfo[6,c] indicates is_filter */ if (varinfo[6,c] == "1" && varinfo[3,c] == "double"){ /* note that no float variables are filters per metadata */ if (validfilters == "") validfilters = varinfo[1,c] else validfilters = validfilters + ", " + varinfo[1,c] } } t = tokeninit(", ") s = tokenset(t, validfilters) respre = tokengetall(t) allopts = tokens(opts) validopts = parseurls(endpoints[2,epid], "optional") spops = J(2,length(validopts),"") spops[1,.] = validopts[1,.] urladds = "" if (length(varinfo[1,.]) > 0){ for (i=1; i<=length(allopts); i++){ t = tokeninit("=") s = tokenset(t, allopts[i]) res2 = tokengetall(t) spos = stringpos(res2[1], validopts) if (spos > 0) spops[2,spos] = allopts[i] else{ spos1 = stringpos(res2[1], varinfo[1,.]) if (spos1 > 0){ if (res2[2] != subinstr(subinstr(res2[2], ":", ""), ",", "")){ if (iteminlist(res2[1], respre) == 0){ printf("Error, option " + allopts[i] + " is not valid, because it may only be filtered on a single value, not multiple values.\n") printf("Decimal variables may not be filtered at all. The variables that can be filtered on multiple values in this dataset are as follows:\n\n") printf(validfilters) return("\n\nDownload failed. Please try again.") } } if (urladds == "") { urladds = urladds + allopts[i] } else { urladds = urladds + ";" + allopts[i] } } else { printf("Error, option " + allopts[i] + " is not valid. Valid variable selections are as follows:\n") urladds = "" for (c=1; c<=length(varinfo[1,.]); c++){ if (stringpos(strofreal(c),("1","6","11","16","21","26","31","36","41","46","51","56","61","66","71","76","81","86","91","96","101")) > 0) urladds = urladds + varinfo[1,c] else urladds = urladds + ", " + varinfo[1,c] if (stringpos(strofreal(c),("5","10","15","20","25","30","35","40","45","50","55","60","65","70","75","80","85","90","95","100")) > 0) urladds = urladds + "\n" } return("\n\nDownload failed. Please try again.") } } } } querystring = getquerystrings(urladds) for (i=1; i<=length(spops[1,.]); i++){ if (spops[2,i] == "") spops[2,i] = spops[1,i] + "=alldata" } temp1 = validoptions(spops[2,1], epid) if (tokens(temp1[1])[1] == "Invalid"){ printf(temp1[1]) return("") } epcount = 0 if (metadataonly <= 0) printf("Please be patient - downloading data.\n") if (csv > 0 && metadataonly <= 0){ printf("\nNote that this function temporarily writes data to the current working directory.\n") printf("If you do not have read and write privileges to the current directory, please change your working directory.\n") printf("For example, you can enter " + `"""' + "cd D:/Users/[Your username here]/Documents" + `"""' + ".\n\n") ds = tokens(dataoptions)[2] temp3 = downloadcsv(eid,spops,ds,epid,varinfo,querystring,vlist) if (temp3 == 0){ printf("Error: Sorry, there is no CSV file available for download for this dataset at this time.") } } else{ tempdata = createdataset(eid) if (metadataonly <= 0){ if (length(spops[1,.]) == 1){ totallen = length(temp1) for (i=1; i<=length(temp1); i++){ epcount = epcount + 1 urltemp = subinstr(endpoints[2,epid], "{" + spops[1,1] + "}", temp1[i]) + querystring hidereturn = getalltables(eid, urltemp, totallen, epcount) } } else{ temp2 = validoptions(spops[2,2], epid) if (tokens(temp2[1])[1] == "Invalid"){ printf(temp2[1]) return("") } totallen = length(temp1) * length(temp2) for (i=1; i<=length(temp1); i++){ for (j=1; j<=length(temp2); j++){ epcount = epcount + 1 urltemp = subinstr(subinstr(endpoints[2,epid], "{" + spops[1,1] + "}", temp1[i]), "{" + spops[1,2] + "}", temp2[j]) + querystring hidereturn = getalltables(eid, urltemp, totallen, epcount) } } } stata("qui compress") } if (metadataonly > 0) { printf("Metadata successfully loaded into Stata and ready to view. Remove the " + `"""' + "metadata" + `"""' + " argument if you want to load the data itself.\n\n") printf("Note: You may filter this dataset on any variable (as long as it does not have a decimal value) using a single value (e.g. grade=1), however only the following variables allow filtering on multiple values (e.g.grade=1:3 or grade=1,2):\n\n") printf(validfilters) } } if (vlist != "") stata("keep " + vlist) else printf("\nData successfully loaded into Stata and ready to use.") return("") } } end