docs: public I_CmsFormatterBean parse(CmsXmlContent content, String location, String id)
      throws CmsException, ParseException {
  
          String path = content.getFile().getRootPath();
          I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(content.getFile());
          boolean isMacroFromatter = CmsFormatterConfigurationCache.TYPE_MACRO_FORMATTER.equals(type.getTypeName());
          boolean isFlexFormatter = CmsFormatterConfigurationCache.TYPE_FLEX_FORMATTER.equals(type.getTypeName());
          boolean isFunction = OpenCms.getResourceManager().matchResourceType(
              CmsResourceTypeFunctionConfig.TYPE_NAME,
              content.getFile().getTypeId());
  
          Locale en = Locale.ENGLISH;
          I_CmsXmlContentValue niceName = content.getValue(N_NICE_NAME, en);
          m_niceName = niceName != null ? niceName.getStringValue(m_cms) : null;
          CmsXmlContentRootLocation root = new CmsXmlContentRootLocation(content, en);
          I_CmsXmlContentValueLocation rankLoc = root.getSubValue(N_RANK);
          if (rankLoc != null) {
              String rankStr = rankLoc.getValue().getStringValue(m_cms);
              if (rankStr != null) {
                  rankStr = rankStr.trim();
              }
              int rank;
              try {
                  rank = Integer.parseInt(rankStr);
              } catch (NumberFormatException e) {
                  rank = CmsFormatterBean.DEFAULT_CONFIGURATION_RANK;
                  LOG.debug("Error parsing formatter rank.", e);
              }
              m_rank = rank;
          }
  
          m_resourceType = getStringSet(root, N_TYPE);
          parseSettings(root);
          List<I_CmsXmlContentValue> settingIncludes = content.getValues(N_INCLUDE_SETTINGS, en);
          settingIncludes = Lists.reverse(settingIncludes); // make defaults from earlier include files 'win' when merging them into a map
          Map<String, CmsXmlContentProperty> includesByIncludeName = new HashMap<>();
          for (I_CmsXmlContentValue settingInclude : settingIncludes) {
              try {
                  CmsXmlVfsFileValue includeFileVal = (CmsXmlVfsFileValue)settingInclude;
                  CmsUUID includeSettingsId = includeFileVal.getLink(m_cms).getStructureId();
                  List<CmsXmlContentProperty> includedSettings = m_additionalSettingConfigs.get(includeSettingsId);
                  if (includedSettings == null) {
                      continue;
                  }
                  for (CmsXmlContentProperty prop : includedSettings) {
                      String includeName = prop.getIncludeName(prop.getName());
                      if (includeName != null) {
                          CmsXmlContentProperty existingProp = includesByIncludeName.get(includeName);
                          if (existingProp != null) {
                              LOG.warn("Conflict with included setting configuration: " + path);
                          }
                          includesByIncludeName.put(includeName, prop);
                      }
                  }
              } catch (Exception e) {
                  LOG.error(e.getLocalizedMessage(), e);
              }
          }
  
          Map<String, CmsXmlContentProperty> mergedSettings = new LinkedHashMap<>();
  
          for (CmsXmlContentProperty setting : m_settingList) {
              String includeName = setting.getIncludeName(setting.getName());
              if (includeName == null) {
                  LOG.warn("Neither name nor include name given in setting definition in " + path);
                  continue;
              }
              CmsXmlContentProperty defaultSetting = includesByIncludeName.get(includeName);
              CmsXmlContentProperty mergedSetting;
              if (defaultSetting != null) {
                  mergedSetting = setting.mergeDefaults(defaultSetting);
              } else {
                  mergedSetting = setting;
              }
              if (mergedSetting.getName() == null) {
                  LOG.warn("Invalid setting without name in " + path);
                  continue;
              }
              mergedSettings.put(mergedSetting.getName(), mergedSetting);
          }
          m_settings = mergedSettings;
  
          String isDetailStr = getString(root, N_DETAIL, "false");
          boolean isDetail = Boolean.parseBoolean(isDetailStr);
  
          String displayType = getString(root, N_DISPLAY, null);
          if (CmsStringUtil.isEmptyOrWhitespaceOnly(displayType) || "false".equals(displayType)) {
              displayType = null;
          } else if (!m_settings.containsKey(SETTING_DISPLAY_TYPE)) {
              m_settings.put(
                  SETTING_DISPLAY_TYPE,
                  new CmsXmlContentProperty(
                      SETTING_DISPLAY_TYPE,
                      "string",
                      "hidden",
                      null,
                      null,
                      null,
                      displayType,
                      null,
                      null,
                      null,
                      null));
          }
  
          String isAllowSettingsStr = getString(root, N_ALLOWS_SETTINGS_IN_EDITOR, "false");
          boolean isAllowSettings = Boolean.parseBoolean(isAllowSettingsStr);
  
          String isStrictContainersStr = getString(root, N_STRICT_CONTAINERS, "false");
          boolean isStrictContainers = Boolean.parseBoolean(isStrictContainersStr);
  
          String description = getString(root, N_DESCRIPTION, null);
  
          String autoEnabled = getString(root, N_AUTO_ENABLED, "false");
          m_autoEnabled = Boolean.parseBoolean(autoEnabled);
  
          String nestedFormatterSettings = getString(root, N_NESTED_FORMATTER_SETTINGS, "false");
          boolean nestedFormatters = Boolean.parseBoolean(nestedFormatterSettings);
  
          String useMetaMappinsForNormalElementsStr = getString(root, N_USE_META_MAPPINGS_FOR_NORMAL_ELEMENTS, "false");
          boolean useMetaMappingsForNormalElements = Boolean.parseBoolean(useMetaMappinsForNormalElementsStr);
  
          // Functions which just have been created don't have any matching rules, but should fit anywhere
          boolean strictMode = !isFunction;
          parseMatch(root, strictMode);
  
          List<CmsMetaMapping> mappings = parseMetaMappings(root);
          Map<String, String> attributes = parseAttributes(root);
  
          I_CmsFormatterBean formatterBean;
          if (isMacroFromatter || isFlexFormatter) {
              // setting macro formatter defaults
              m_formatterResource = content.getFile();
              m_preview = false;
              m_extractContent = true;
              CmsResource defContentRes = null;
              I_CmsXmlContentValueLocation defContentLoc = root.getSubValue(N_DEFAULT_CONTENT);
              if (defContentLoc != null) {
                  CmsXmlVfsFileValue defContentValue = (CmsXmlVfsFileValue)(defContentLoc.getValue());
                  CmsLink defContentLink = defContentValue.getLink(m_cms);
                  if (defContentLink != null) {
                      CmsUUID defContentID = defContentLink.getStructureId();
                      defContentRes = m_cms.readResource(defContentID);
                  }
              }
              if (isMacroFromatter) {
                  String macroInput = getString(root, N_MACRO, "");
                  String placeholderMacroInput = getString(root, N_PLACEHOLDER_MACRO, "");
                  Map<String, CmsUUID> referencedFormatters = readReferencedFormatters(content);
                  formatterBean = new CmsMacroFormatterBean(
                      m_containerTypes,
                      m_formatterResource.getRootPath(),
                      m_formatterResource.getStructureId(),
                      m_width,
                      m_maxWidth,
                      m_extractContent,
                      location,
                      m_niceName,
                      description,
                      m_resourceType,
                      m_rank,
                      id,
                      defContentRes != null ? defContentRes.getRootPath() : null,
                      defContentRes != null ? defContentRes.getStructureId() : null,
                      m_settings,
                      m_autoEnabled,
                      isDetail,
                      displayType,
                      isAllowSettings,
                      macroInput,
                      placeholderMacroInput,
                      referencedFormatters,
                      m_cms.getRequestContext().getCurrentProject().isOnlineProject(),
                      mappings,
                      useMetaMappingsForNormalElements);
              } else {
                  String stringTemplate = getString(root, N_STRING_TEMPLATE, "");
                  String placeholder = getString(root, N_PLACEHOLDER_STRING_TEMPLATE, "");
                  formatterBean = new CmsFlexFormatterBean(
                      m_containerTypes,
                      m_formatterResource.getRootPath(),
                      m_formatterResource.getStructureId(),
                      m_width,
                      m_maxWidth,
                      m_extractContent,
                      location,
                      m_niceName,
                      description,
                      m_resourceType,
                      m_rank,
                      id,
                      defContentRes != null ? defContentRes.getRootPath() : null,
                      defContentRes != null ? defContentRes.getStructureId() : null,
                      m_settings,
                      m_autoEnabled,
                      isDetail,
                      displayType,
                      isAllowSettings,
                      stringTemplate,
                      placeholder,
                      mappings,
                      useMetaMappingsForNormalElements);
              }
          } else {
              I_CmsXmlContentValueLocation jspLoc = root.getSubValue(N_JSP);
              CmsXmlVfsFileValue jspValue = (CmsXmlVfsFileValue)(jspLoc.getValue());
              CmsLink link = jspValue.getLink(m_cms);
  
              CmsUUID jspID = null;
              if (link == null) {
                  if (isFunction) {
                      CmsResource defaultFormatter = CmsFunctionRenderer.getDefaultFunctionJsp(m_cms);
                      jspID = defaultFormatter.getStructureId();
                  } else {
                      // JSP link is not set (for example because the formatter configuration has just been created)
                      LOG.info("JSP link is null in formatter configuration: " + content.getFile().getRootPath());
                      return null;
                  }
              } else {
                  jspID = link.getStructureId();
              }
  
              if (jspID == null) {
                  throw new CmsConfigurationException(
                      org.opencms.main.Messages.get().container(
                          org.opencms.main.Messages.ERR_READ_FORMATTER_CONFIG_4,
                          new Object[] {
                              link != null ? link.getUri() : " ??? ",
                              m_niceName,
                              location,
                              "" + m_resourceType}));
              }
  
              CmsResource formatterRes = m_cms.readResource(jspID);
              m_formatterResource = formatterRes;
              String previewStr = getString(root, N_PREVIEW, "false");
              m_preview = Boolean.parseBoolean(previewStr);
  
              String searchableStr = getString(root, N_SEARCH_CONTENT, "true");
              m_extractContent = Boolean.parseBoolean(searchableStr);
              parseHeadIncludes(root);
              if (isFunction) {
                  CmsResource functionFormatter = m_cms.readResource(CmsResourceTypeFunctionConfig.FORMATTER_PATH);
                  Map<String, String[]> rparams = parseParams(root);
                  formatterBean = new CmsFunctionFormatterBean(
                      m_containerTypes,
                      m_formatterResource.getRootPath(),
                      m_formatterResource.getStructureId(),
                      functionFormatter.getStructureId(),
                      m_width,
                      m_maxWidth,
                      location,
                      m_cssPaths,
                      m_inlineCss.toString(),
                      m_jsPaths,
                      m_inlineJs.toString(),
                      m_niceName,
                      description,
                      id,
                      m_settings,
                      isAllowSettings,
                      isStrictContainers,
                      rparams);
              } else {
                  formatterBean = new CmsFormatterBean(
                      m_containerTypes,
                      m_formatterResource.getRootPath(),
                      m_formatterResource.getStructureId(),
                      m_width,
                      m_maxWidth,
                      m_preview,
                      m_extractContent,
                      location,
                      m_cssPaths,
                      m_inlineCss.toString(),
                      m_jsPaths,
                      m_inlineJs.toString(),
                      m_niceName,
                      description,
                      m_resourceType,
                      m_rank,
                      id,
                      m_settings,
                      true,
                      m_autoEnabled,
                      isDetail,
                      displayType,
                      isAllowSettings,
                      isStrictContainers,
                      nestedFormatters,
                      mappings,
                      attributes,
                      useMetaMappingsForNormalElements);
              }
          }
  
          return formatterBean;
      }