sclass WordDocumentTemplateProcessor { File inFile, outFile; new WordDocumentTextReplacer2 replacer; swappable S getValue(S key) { null; } run { replacer.inFile = inFile; replacer.outFile = outFile; S optSpace = regexp_spaceIncludingNbsp() + "*"; S space = regexp_spaceIncludingNbsp() + "+"; replacer.processParagraph = runs -> { // replace content replacer.regexpReplacement(runs, "\\[" + optSpace + "(\\d+[a-z]*)" // key + regexp_negativeLookahead(space + "if" + space) + "[:.]" // separator + optSpace + "(.*?)" // contents + "\\]", (text, groups) -> { new Matches m; S key = first(groups); S value = getValue(key); ret or(value, "undefined"); }); // conditional paragraph parts replacer.regexpReplacement(runs, "\\[" + optSpace + "(\\d+[a-z]*)" // key + space + "if" + space + "(.*?)" // condition + "[:.]" // end of condition + optSpace + "(.*?)" // contents + "\\]", (text, groups) -> { S key = first(groups); S condition = regexpReplace_direct(second(groups), space, " "); S contents = third(groups); bool result = evaluateFormCondition(key, condition); ret result ? contents : ""; }); // remove double commas replacer.regexpReplacement(runs, "," + regexp_spaceIncludingNbsp() + "*(?=,)", (text, groups) -> ""); }; replacer.postprocess = r { // bullet points for (int i = 0; i < l(replacer.outParagraphs); i++) { L para = replacer.outParagraphs.get(i); S text = replacer.fullText(para); LS groups = regexpMatchGroupsIC(optSpace + "\\[" + "(\\d+[a-z]*)" // key + space + "bullet" + space + "points" + "\\]" + optSpace, text); if (groups != null) { S key = first(groups); S value = getValue(key); replacer.outParagraphs.remove(i); LS items = trimAll(splitAt(value, "|")); printVars_str("bullet points", +value); for (S item : items) { print("Adding item at " + i + ": " + item); replacer.outParagraphs.add(i++, ll(new WordDocumentTextReplacer2.OutRun(first(para).run, unicode_bullet() + " " + item))); } --i; } } // process conditional paragraphs for (int i = l(replacer.outParagraphs)-1; i >= 0; i--) { L para = replacer.outParagraphs.get(i); S text = replacer.fullText(para); LS groups = regexpMatchGroupsIC(optSpace + "\\[START" + space + "(\\d+[a-z]*)" // key + space + "if" + space + "(.*?)" // condition + "\\]" + optSpace, text); if (groups != null) { int j = i+1; while (j < l(replacer.outParagraphs) && !cic( replacer.fullText(replacer.outParagraphs.get(j)), "[END]")) ++j; if (j >= l(replacer.outParagraphs)) continue with print("warn: no [END] found for " + text); S key = first(groups); S condition = second(groups); bool result = evaluateFormCondition(key, condition); if (result) { replacer.outParagraphs.remove(j); replacer.outParagraphs.remove(i); } else removeSubList(replacer.outParagraphs, i, j+1); --i; } } // take out runs of empty paragraphs for (int i = 0; i < l(replacer.outParagraphs); i++) { int j = i+1; while (j < l(replacer.outParagraphs) && regexpMatchesIC( optSpace, replacer.fullText(replacer.outParagraphs.get(j)))) ++j; if (j >= i+2) { print("Dropping empty paragraphs at " + i); removeSubList(replacer.outParagraphs, i+2, j); } } }; replacer.run(); } bool evaluateFormCondition(S key, S condition) { S value = getValue(key); bool result; new Matches m; if (swic(condition, "contains ", m)) result = cic(value, m.rest()); else if (eqic(condition, "not empty")) result = nempty(value); else result = eqic(value, condition); printVars_str(+key, +condition, +value, +result); ret result; } }