docs: public static DTree getDTreeFromCoNLLXString(final String input) {
          if (input == null || input.trim().isEmpty()) {
              return null;
          }
  
          Map<Integer, Map<Integer, String>> semanticHeadsMap = new HashMap<>();
          String[] dNodesString = input.split(System.lineSeparator());
          DTree tree = new DTree();
  
          Arrays.stream(dNodesString)
                  .map(s -> s.split("\t"))
                  .forEachOrdered(fields -> {
                      int currentIndex = 0;
                      int id = Integer.parseInt(fields[currentIndex++]);
                      String form = fields[currentIndex++];
                      String lemma = fields[currentIndex++];
                      String cPOSTag = fields[currentIndex++];
                      String pos = fields[currentIndex++];
                      String feats = fields[currentIndex++];
                      Map<String, String> featsMap = null;
                      if (!feats.equals("_")) {
                          featsMap = Arrays.stream(feats.split("\\|"))
                                  .map(entry -> entry.split("="))
                                  .collect(Collectors.toMap(e -> e[0], e -> e.length > 1 ? e[1] : StringUtils.EMPTY));
                      } else {
                          featsMap = new HashMap<>();
                      }
  
                      String headIndex = fields[currentIndex++];
                      String depLabel = fields[currentIndex++];
  
                      String dump1 = fields[currentIndex++];
                      String dump2 = fields[currentIndex++];
  
                      String semanticHeadsString = currentIndex >= fields.length ? "_" : fields[currentIndex];
  
                      if (!semanticHeadsString.equals("_")) {
                          Map<Integer, String> semanticHeads = Arrays.stream(semanticHeadsString.split("\\|"))
                                  .map(entry -> entry.split(":"))
                                  .collect(Collectors.toMap(e -> Integer.parseInt(e[0]), e -> (e.length > 1) ? e[1] : StringUtils.EMPTY));
                          semanticHeadsMap.put(id, semanticHeads);
                      }
  
                      DNode node = id == 0 ? tree.getPaddingNode() : new DNode(id, form, lemma, cPOSTag, pos, depLabel);
                      if (id == 0 && !featsMap.containsKey("uuid")) {
                          featsMap.put("uuid", tree.getUUID().toString());
                      }
                      node.setFeats(featsMap);
                      node.addFeature("head", headIndex); // by the time head might not be generated!
                      if (node.getId() == 0) {
                          tree.getPaddingNode().setFeats(node.getFeats());// Substitute padding with actual 0 node from CoNLLX
                      } else {
                          tree.add(node);
                      }
                  });
  
          tree.getPaddingNode().getFeats().remove("head");
          for (int i = 1; i < tree.size(); i++) {
              DNode node = tree.get(i);
              int headIndex = Integer.parseInt(node.getFeature("head"));
              DNode head = tree.get(headIndex);
              head.addChild(node);
              node.getFeats().remove("head");
              node.setHead(head);
          }
  
  
          // Recover semantic heads.
          semanticHeadsMap.entrySet().parallelStream().map(e -> {
              DNode node = tree.get(e.getKey());
              Map<Integer, String> nodeSemanticInfo = e.getValue();
              for (Integer id : nodeSemanticInfo.keySet()) {
                  node.addSemanticHead(tree.get(id), nodeSemanticInfo.get(id));
                  tree.get(id).getSemanticChildren().add(node);
              }
              return null;
          }).collect(Collectors.toList());
          return tree;
      }