Ну вот, теперь, когда я привлёк внимание случайного зрителя, хочу узнать, что, чёрт возьми, нужно окаянному валидатору. Я перечитал кучу комментариев, я попробовал разную разметку, с trim() и без него, с вложенными тегами, со span словом между 2 тегами span, да как угодно. Сначала я решил эту задачу через TreeMap<Integer, Boolean> (позиция тега – открывающий/закрывающий), результат был тот же. Работаю в IDEA, выводит у меня из файла всё по-православному. Помогите понять, что хочет от меня эта адская машина.
package com.javarush.task.task19.task1918;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

/*
Знакомство с тегами
*/

public class Solution {
    private static ArrayList<String> tags = new ArrayList<>();

    public static void main(String[] args) throws IOException {
        StringBuilder sb = new StringBuilder();
        // считываем файл
        try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
             BufferedReader fr = new BufferedReader(new FileReader(br.readLine()))) {
            while (fr.ready()) {
                sb.append(fr.readLine().trim()); // считываем строку, убираем пробелы
            }
            sb = new StringBuilder(sb.toString().replaceAll(" +", " ")); // взята из комментов, пробовал и без неё
        }

        findTag(sb.toString(), 0, args[0]); // функция для занесения нужных тегов в tags
        tags.stream().forEach(System.out::println); // вывод результата в консоль
    }

    public static int findTag(String html, int startIndex, String tag) {
        final String start = "<" + tag, end = "</" + tag + ">";
        startIndex = html.indexOf(start, startIndex); // позиция начала первого открывающего тега
        int endIndex = html.indexOf(end, startIndex) + end.length(); // позиция конца ближайшего закрывающего тега
        // пока на текущем уровне есть открывающие теги, добавляем их в список и вызываем рекурсию для вложенных
        for (; (startIndex != -1) && (startIndex < endIndex);
             startIndex = html.indexOf(start, endIndex),
             endIndex = html.indexOf(end, endIndex) + end.length()) {
            int tagStartNext = html.indexOf(start, startIndex + 1); // позиция начала следующего открывающего тега
            int tagListIndex = tags.size(); // маркер, куда в tags записать тег внешнего уровня
            // если текущий тег имеет хотя бы 1 вложенный, рекурсивно вызываем функцию для вложенного тега
            if ((tagStartNext < endIndex) && (tagStartNext != -1)) {
                endIndex = findTag(html, startIndex + 1, tag);
            }
            tags.add(tagListIndex, html.substring(startIndex, endIndex));
        }

        return endIndex;
    }
}