docs: public static String replaceDataReferencesInString(
              final String input,
              final Map<String, Map<String, String>> data,
              final Converter<String, String> converter,
              boolean failOnUnexpanded,
              boolean blankIfUnexpanded
      )
      {
          if (null == data || null == input) {
              return input;
          }
          final Matcher m = SharedDataContextUtils.PROPERTY_REF_PATTERN.matcher(input);
          final StringBuffer sb = new StringBuffer();
          while (m.find()) {
              final String key = m.group(1);
              final String nm = m.group(2);
              if (null!=key && null!=nm && null!=data.get(key) && null!= data.get(key).get(nm)) {
                  String value = data.get(key).get(nm);
                  if (null != converter) {
                      value = converter.convert(value);
                  }
                  m.appendReplacement(sb, Matcher.quoteReplacement(value));
              }else if (failOnUnexpanded && null != key && null != nm && (null == data.get(key) || null == data.get(key)
                                                                                                               .get(nm))) {
                  throw new UnresolvedDataReferenceException(input, m.group());
              }else if(blankIfUnexpanded) {
                  m.appendReplacement(sb, "");
              } else {
                  String value = m.group(0);
                  if (null != converter) {
                      value = converter.convert(value);
                  }
                  m.appendReplacement(sb, Matcher.quoteReplacement(value));
              }
          }
          m.appendTail(sb);
          return sb.toString();
      }