docs: protected CmsFile writeCategories(CmsObject cms, CmsFile file, CmsXmlContent content) throws CmsException {
  
          if (CmsWorkplace.isTemporaryFile(file)) {
              // ignore temporary file if the original file exists (not the case for direct edit: "new")
              if (CmsResource.isTemporaryFileName(file.getRootPath())) {
                  String originalFileName = CmsResource.getFolderPath(file.getRootPath())
                      + CmsResource.getName(file.getRootPath()).substring(CmsResource.TEMP_FILE_PREFIX.length());
                  if (cms.existsResource(cms.getRequestContext().removeSiteRoot(originalFileName))) {
                      // original file exists, ignore it
                      return file;
                  }
              } else {
                  // file name does not start with temporary prefix, ignore the file
                  return file;
              }
          }
          // check the presence of a category widget
          boolean hasCategoryWidget = false;
          Iterator<I_CmsWidget> it = m_elementWidgets.values().iterator();
          while (it.hasNext()) {
              Object widget = it.next();
              if (widget instanceof CmsCategoryWidget) {
                  hasCategoryWidget = true;
                  break;
              }
          }
          if (!hasCategoryWidget) {
              // nothing to do if no category widget is present
              return file;
          }
          boolean modified = false;
          // clone the cms object, and use the root site
          CmsObject tmpCms = OpenCms.initCmsObject(cms);
          tmpCms.getRequestContext().setSiteRoot("");
          // read all siblings
          try {
              List<CmsResource> listsib = tmpCms.readSiblings(file.getRootPath(), CmsResourceFilter.ALL);
              for (int i = 0; i < listsib.size(); i++) {
                  CmsResource resource = listsib.get(i);
                  // get the default locale of the sibling
                  List<Locale> locales = getLocalesForResource(tmpCms, resource.getRootPath());
                  Locale locale = locales.get(0);
                  for (Locale l : locales) {
                      if (content.hasLocale(l)) {
                          locale = l;
                          break;
                      }
                  }
                  // remove all previously set categories
                  boolean clearedCategories = false;
                  // iterate over all values checking for the category widget
                  CmsXmlContentWidgetVisitor widgetCollector = new CmsXmlContentWidgetVisitor(locale);
                  content.visitAllValuesWith(widgetCollector);
                  Iterator<Map.Entry<String, I_CmsXmlContentValue>> itWidgets = widgetCollector.getValues().entrySet().iterator();
                  while (itWidgets.hasNext()) {
                      Map.Entry<String, I_CmsXmlContentValue> entry = itWidgets.next();
                      String xpath = entry.getKey();
                      I_CmsWidget widget = widgetCollector.getWidgets().get(xpath);
                      I_CmsXmlContentValue value = entry.getValue();
                      if (!(widget instanceof CmsCategoryWidget)
                          || value.getTypeName().equals(CmsXmlDynamicCategoryValue.TYPE_NAME)) {
                          // ignore other values than categories
                          continue;
                      }
                      if (!clearedCategories) {
                          CmsCategoryService.getInstance().clearCategoriesForResource(tmpCms, resource.getRootPath());
                          clearedCategories = true;
                      }
                      String stringValue = value.getStringValue(tmpCms);
                      if (CmsStringUtil.isEmptyOrWhitespaceOnly(stringValue)) {
                          // skip empty values
                          continue;
                      }
                      try {
                          // add the file to the selected category
                          String[] catRootPathes = stringValue.split(",");
                          for (String catRootPath : catRootPathes) {
                              CmsCategory cat = CmsCategoryService.getInstance().getCategory(tmpCms, catRootPath);
                              CmsCategoryService.getInstance().addResourceToCategory(
                                  tmpCms,
                                  resource.getRootPath(),
                                  cat.getPath());
                          }
                      } catch (CmsVfsResourceNotFoundException e) {
                          // invalid category
                          try {
                              // try to remove invalid value
                              content.removeValue(value.getName(), value.getLocale(), value.getIndex());
                              modified = true;
                          } catch (CmsRuntimeException ex) {
                              // in case minoccurs prevents removing the invalid value
                              if (LOG.isDebugEnabled()) {
                                  LOG.debug(ex.getLocalizedMessage(), ex);
                              }
                          }
                      }
                  }
              }
          } catch (CmsException ex) {
              if (LOG.isErrorEnabled()) {
                  LOG.error(ex.getLocalizedMessage(), ex);
              }
          }
          if (modified) {
              // when an invalid category has been removed
              file = content.correctXmlStructure(cms);
              content.setFile(file);
          }
          return file;
      }