Найти вложенные соответствующие HTML-теги в Java

Im работает с допустимой строкой HTML (разбирается с jsoup, поэтому все теги имеют закрывающие теги, и он хорошо сформирован) в Java, и мне нужно найти содержимое данного имени тега, например , работает со следующей строкой:

<p> hi! </p>
<p> hi again! </p>
<h1> foo </h1>
<p> bye! </p>

результаты, которые я ожидаю, учитывая тег "p":

1)<p> hi! </p>
2)<p> hi again! </p>
3)<p> bye! </p>

Ive завершил это, просто используя apache.палата общин.библиотека lang с методом StringUtils.substringsBetween (строка html, строка "opentag", строка " endtag") который вернет массив String с желаемыми результатами. Однако, когда я ищу тег, который имеет точно такой же тег, вложенный внутри ( общий пример-div), я получу неправильные результаты (я понимаю, почему)

например, работа С...

<div>
 <p> hey there </p>
 <div>  
  <div>
   <p> asd </p>
  </div>
 </div>
</div>

Я ожидал бы 3 результата: 1)

<div>
 <p> hey there </p>
 <div>  
  <div>
   <p> asd </p>
  </div>
 </div>
</div>

2)

<div>  
 <div>
  <p> asd </p>
 </div>
</div>

3)

<div>
 <p> asd </p>
</div>

однако я получаю один (я знаю его из-за того, как вхождения тега появляются в строке) I просто не знаю как ее решить. Я боролся с этим в течение 2 недель, я пробовал с regex без каких-либо успехов вообще, я также попытался разбить строку html на массив строк, но тоже не удалось.

как бы вы подошли к этой проблеме? Я уже знаю, что есть тонны библиотек, которые делают это для вас с помощью таких методов, как getAllElementsByTag(tagName) jsoup, но я хочу сделать это сам. Любые подсказки приветствуются!

3 ответов


вам нужно будет интенсивно использовать токенизацию и рекурсию для решения этой проблемы. По сути, каждый раз, когда открывается новый тег (скажем,<div>), вы снова запускаете свою обработку.

рассмотреть что-то вроде следующего:

ArrayList<String> elements = new ArrayList<String>();
Scanner scanner = new Scanner(html);

public String populateDivContents(String buildingString) {

    while(scanner.hasNext()) {

        //Get the next token
        String next = scanner.next();

        //If it's a <div>, call recursively
        if(next.equalsIgnoreCase("<div>")) {
            buildingString = buildingString + populateDivContents(next);
        }

        //If we've hit a closing tag, add our built String to the elements
        else if(next.equalsIgnoreCase("</div>") {
            buildingString = buildingString + next;
            elements.add(buildingString);
            return buildingString;
        }

        //Otherwise, simply add the text to our String and keep going
        else {
            buildingString = buildingString + next;
        }
    }
}

это очень грубый эскиз и имеет некоторые проблемы, особенно если ваши теги не отделены новыми строками или пробелами от их содержимого (как в ваших примерах). Он также предполагает, что HTML хорошо сформирован, как вы говорите. Но этого достаточно, чтобы понять идею. The ArrayList<String> объявлена будет содержать все <div> теги и их содержимое.


стандартным подходом для этого является использование стека. То есть, когда вы сталкиваетесь с открывающим тегом, вы сбрасываете в стек, и всякий раз, когда вы сталкиваетесь с закрывающим тегом, вы открываете самый верхний элемент. Если строка действительно хорошо сформирована, все закрывающие теги должны открыть соответствующий открывающий тег. Оттуда, это должно быть кусок пирога, чтобы выяснить, как добраться до содержимого внутренней пары.


TagSoup или Jsoup будет тот, который вы ищете:)