Inspired by the answer of Andrey Lebedenko.
Capable of sorting by a Nodes attribute or by a Nodes text content.
Ready to be used in Your XML utility class.
public static Collection<Node> nodeListCollection(final NodeList nodeList) {
  if (nodeList == null) {
    return Collections.emptyList();
  }
  final int length = nodeList.getLength();
  if (length == 0) {
    return Collections.emptyList();
  }
  return IntStream.range(0, length)
      .mapToObj(nodeList::item)
      .collect(Collectors.toList());
}
private static int compareString(final String str1, final String str2, final boolean nullIsLess) {
  if (Objects.equals(str1, str2)) { 
    return 0;
  }
  if (str1 == null) {
    return nullIsLess ? -1 : 1;
  }
  if (str2 == null) {
    return nullIsLess ? 1 : -1;
  }
  return str1.compareTo(str2);
}
private static final Function<Boolean, Comparator<Node>> StringNodeValueComparatorSupplier = (asc) ->
    (Node a, Node b) -> {
      final String va = a == null ? null : a.getTextContent();
      final String vb = b == null ? null : b.getTextContent();
      return (asc ? 1 : -1) * compareString(va, vb,asc);
    };
private static final BiFunction<Boolean, String, Comparator<Node>> StringNodeAttributeComparatorSupplier = (asc, attrName) ->
    (Node a, Node b) -> {
      final String va = a == null ? null : a.hasAttributes() ?
          ((Element) a).getAttribute(attrName) : null;
      final String vb = b == null ? null : b.hasAttributes() ?
          ((Element) b).getAttribute(attrName) : null;
      return (asc ? 1 : -1) * compareString(va, vb,asc);
    };
private static <T extends Comparable<T>> Comparator<Node> nodeComparator(
    final boolean asc,
    final boolean useAttr,
    final String attribute,
    final Constructor<T> constructor
) {
  return (Node a, Node b) -> {
    if (a == null && b == null) {
      return 0;
    } else if (a == null) {
      return (asc ? -1 : 1);
    } else if (b == null) {
      return (asc ? 1 : -1);
    }
    T aV;
    try {
      final String aStr;
      if (useAttr) {
        aStr = a.hasAttributes() ? ((Element) a).getAttribute(attribute) : null;
      } else {
        aStr = a.getTextContent();
      }
      aV = aStr == null || aStr.matches("\\s+") ? null : constructor.newInstance(aStr);
    } catch (Exception ignored) {
      aV = null;
    }
    T bV;
    try {
      final String bStr;
      if (useAttr) {
        bStr = b.hasAttributes() ? ((Element) b).getAttribute(attribute) : null;
      } else {
        bStr = b.getTextContent();
      }
      bV = bStr == null || bStr.matches("\\s+") ? null : constructor.newInstance(bStr);
    } catch (Exception ignored) {
      bV = null;
    }
    final int ret;
    if (aV == null && bV == null) {
      ret = 0;
    } else if (aV == null) {
      ret = -1;
    } else if (bV == null) {
      ret = 1;
    } else {
      ret = aV.compareTo(bV);
    }
    return (asc ? 1 : -1) * ret;
  };
}
/**
 * Method to sort any NodeList by an attribute all nodes must have. <br>If the attribute is absent for a signle
 * {@link Node} or the {@link NodeList} does contain elements without Attributes, null is used instead. <br>If
 * <code>asc</code> is
 * <code>true</code>, nulls first, else nulls last.
 *
 * @param nodeList The {@link NodeList} containing all {@link Node} to sort.
 * @param attribute Name of the attribute to extract and compare
 * @param asc <code>true</code>: ascending, <code>false</code>: descending
 * @param compareType Optional class to use for comparison. Must implement {@link Comparable} and have Constructor
 * that takes a single {@link String} argument. If <code>null</code> is supplied, {@link String} is used.
 * @return A collection of the {@link Node}s passed as {@link NodeList}
 * @throws RuntimeException If <code>compareType</code> does not have a constructor taking a single {@link String}
 * argument. Also, if the comparator created does violate the {@link Comparator} contract, an
 * {@link IllegalArgumentException} is raised.
 * @implNote Exceptions during calls of the single String argument constructor of <code>compareType</code> are
 * ignored. Values are substituted by <code>null</code>
 */
public static <T extends Comparable<T>> Collection<Node> sortNodesByAttribute(
    final NodeList nodeList,
    String attribute,
    boolean asc,
    Class<T> compareType) {
  final Comparator<Node> nodeComparator;
  if (compareType == null) {
    nodeComparator = StringNodeAttributeComparatorSupplier.apply(asc, attribute);
  } else {
    final Constructor<T> constructor;
    try {
      constructor = compareType.getDeclaredConstructor(String.class);
    } catch (NoSuchMethodException e) {
      throw new RuntimeException(
          "Cannot compare Node Attribute '" + attribute + "' using the Type '" + compareType.getName()
              + "': No Constructor available that takes a single String argument.", e);
    }
    nodeComparator = nodeComparator(asc, true, attribute, constructor);
  }
  final List<Node> nodes = new ArrayList<>(nodeListCollection(nodeList));
  nodes.sort(nodeComparator);
  return nodes;
}
/**
 * Method to sort any NodeList by their text content using an optional type. <br>If
 * <code>asc</code> is
 * <code>true</code>, nulls first, else nulls last.
 *
 * @param nodeList The {@link NodeList} containing all {@link Node}s to sort.
 * @param asc <code>true</code>: ascending, <code>false</code>: descending
 * @param compareType Optional class to use for comparison. Must implement {@link Comparable} and have Constructor
 * that takes a single {@link String} argument. If <code>null</code> is supplied, {@link String} is used.
 * @return A collection of the {@link Node}s passed as {@link NodeList}
 * @throws RuntimeException If <code>compareType</code> does not have a constructor taking a single {@link String}
 * argument. Also, if the comparator created does violate the {@link Comparator} contract, an
 * {@link IllegalArgumentException} is raised.
 * @implNote Exceptions during calls of the single String argument constructor of <code>compareType</code> are
 * ignored. Values are substituted by <code>null</code>
 */
public static <T extends Comparable<T>> Collection<Node> sortNodes(
    final NodeList nodeList,
    boolean asc,
    Class<T> compareType) {
  final Comparator<Node> nodeComparator;
  if (compareType == null) {
    nodeComparator = StringNodeValueComparatorSupplier.apply(asc);
  } else {
    final Constructor<T> constructor;
    try {
      constructor = compareType.getDeclaredConstructor(String.class);
    } catch (NoSuchMethodException e) {
      throw new RuntimeException(
          "Cannot compare Nodes using the Type '" + compareType.getName()
              + "': No Constructor available that takes a single String argument.", e);
    }
    nodeComparator = nodeComparator(asc, false, null, constructor);
  }
  final List<Node> nodes = new ArrayList<>(nodeListCollection(nodeList));
  nodes.sort(nodeComparator);
  return nodes;
}