*! version 0.1 16Mar2021 * Programmed by Gustavo Iglésias * Dependencies: gtools program define metaxl_morph syntax anything, METAfile(string) [save(string) keep] if "`save'" != "" { gettoken save replacesave: save, p(",") local save = trim("`save'") local save "`save'.xlsx" gettoken lixo replacesave: replacesave, p(",") cap confirm file "`save'" if !_rc { if trim("`replacesave'") != "replace" { di as error `"File "`save'" already exists. Please specify "' /// `"sub-option "replace" to overwrite the existing file"' exit 602 } else { if "`save'" == "`metafile'.xlsx" { local save "`metafile'.xlsx" } else { cap rm "`save'" qui copy "`metafile'.xlsx" "`save'" } } } else { qui copy "`metafile'.xlsx" "`save'" } } else { local save "`metafile'_new.xlsx" cap confirm file "`save'" if !_rc { di as error `"File "`save'" already exists. Please specify "' /// `"option "save" to save the file under a different name"' exit 602 } qui copy "`metafile'.xlsx" "`save'" } parse_arg `anything' local sheet_count = `r(sheet_count)' forvalues i = 1/`sheet_count' { check_args, new(`r(new_sheet`i')') old(`r(old_sheets`i')') local new_sheet`i' "`r(new_sheet`i')'" local old_sheets`i' "`r(old_sheets`i')'" local new_sheets = "`new_sheets'" + " `new_sheet`i''" } check_existing_sheets, file(`save') sheets(`new_sheets') forvalues i = 1/`sheet_count' { merge_sheets, meta(`save') new(`new_sheet`i'') old(`old_sheets`i'') `keep' } end program define parse_arg, rclass syntax anything local right "`anything'" local case 1 local i 1 while `case' { gettoken left right: right, p(")") local exp`i' = substr("`left'", 2, .) gettoken left right: right, p(")") local right = trim("`right'") if "`right'" != "" { local ++i } else { local case 0 return local sheet_count `i' } } forvalues j = 1/`i' { gettoken left`j' right`j': exp`j', p("=") if trim("`left`j''") != "" { return local new_sheet`j' = trim("`left`j''") } else { di di as error "Error in argument expression. Expressions should be of" /// " the form (vl_name1 = vl_name2 vl_name3 ...), where vl_name# " /// "is the name of the sheet and name# is the name of the value label." exit 198 } gettoken left`j' right`j': right`j', p("=") if trim("`right`j''") != "" { return local old_sheets`j' = trim("`right`j''") } else { di di as error "Error in argument expression. Expressions should be of" /// " the form (vl_name1 = vl_name2 vl_name3 ...), where vl_name# " /// "is the name of the sheet and name# is the name of the value label." exit 198 } } end program define check_args syntax, new(string) old(string) local new = trim("`new'") local old = trim("`old'") if substr("`new'", 1, 3) != "vl_" { di di as error "`new' is not a valid sheet name. Expressions should be of" /// " the form (vl_name1 = vl_name2 vl_name3 ...), where vl_name# " /// "is the name of the sheet and name# is the name of the value label." exit 198 } foreach sheet in `old' { if substr("`sheet'", 1, 3) != "vl_" { di di as error "`sheet' is not a valid sheet name. Expressions should be of" /// " the form (vl_name1 = vl_name2 vl_name3 ...), where vl_name# " /// "is the name of the sheet and name# is the name of the value label." exit 198 } } end program define check_existing_sheets syntax, file(string) sheets(string) qui import excel using "`file'", describe foreach sheet in `sheets' { forvalues i = 1/`r(N_worksheet)' { if "`sheet'" == "`r(worksheet_`i')'" { di as error `"worksheet `sheet' already exists"' exit 602 } } } end program define merge_sheets syntax, meta(string) new(string) old(string) [keep] di di as text "merging worksheets " as result "`old'" tempname mergefr frame create `mergefr' frame `mergefr' { tempfile temp foreach sheet in `old' { qui import excel using "`meta'", sheet("`sheet'") first clear cap drop file* cap append using `temp' quietly { bysort value label: keep if _n == 1 } qui save `temp', replace } cap keep value label obs if _rc keep value label qui export excel using "`meta'", sheet("`new'", replace) first(var) } di di as text "worksheet " as result "`new'" as text " created" update_vars_vl, meta(`meta') new(`new') old(`old') frame drop `mergefr' if trim("`keep'") == "" { di di as text "removing worksheets " as result "`old'" mata: delete_sheets("`old'", "`meta'") } end program define update_vars_vl syntax, meta(string) new(string) old(string) tempname updatefr frame create `updatefr' frame `updatefr' { qui import excel using "`meta'", sheet("variables") first clear local vl_new = substr("`new'", 4, .) foreach sheet in `old' { local vl_old = substr("`sheet'", 4, .) foreach var of varlist value_label* { qui replace `var' = "`vl_new'" if `var' == "`vl_old'" } } qui export excel using "`meta'", sheet("variables", replace) first(var) } frame drop `updatefr' end mata: void delete_sheets(string scalar sheets, string scalar meta) { class xl scalar book book = xl() book.load_book(meta) sh = tokens(sheets) for (i=1; i<=length(sh); i++) { book.delete_sheet(sh[i]) } book.close_book() } end