Удалите узлы, которые не содержат свой собственный текст, используя Jsoup - PullRequest
1 голос
/ 03 июня 2019

Я заметил, что на многих веб-страницах есть лишние (для моих целей) узлы HTML.Я хотел бы удалить их со страницы, так как это значительно облегчит мою обработку.

Есть ли способ сделать это с помощью JSoup?

Чтобы сделать ситуацию более понятной,скажем, у нас есть следующая страница:

<html>
  <head>
  </head>
  <body>
    <div>I have some text</div>
    <div class='useless'>
      <div class='useless'>
        <div>I also have text
          <div>I also have text</div>
        </div>
      </div>   
    </div>      
  </body>
</html>

Я хотел бы удалить div = 'бесполезные' класса - но, конечно, я не могу выбрать их по их классу / идентификатору / тегу и т. д. толькотот факт, что у них нет контента.Это, конечно, изменит структуру страницы, это совершенно нормально - это облегчит мою окончательную обработку.

Результатом будет:

<html>
  <head>
  </head>
  <body>
    <div>I have some text</div>
    <div class='useless'>
      <div class='useless'>
        <div>I also have text
          <div>I also have text</div>
        </div>
      </div>
    </div>   
  </body>
</html>

Возможно ли это в простой илитрудный путь.

Результат будет:

<html>
  <head>
  </head>
  <body>
    <div>I have some text</div>
    <div>I also have text
      <div>I also have text</div>
    </div>  
  </body>
</html>

Сейчас я не могу придумать ничего особенно элегантного.Я обычно склоняюсь к проверке метода ownText() для различных элементов (проверю ownText().length() > 0), и если false попытается удалить их, но я думаю, что это также удалит любые дочерние / дочерние элементы, даже если они совпадаютtrue для условия .ownText().

1 Ответ

1 голос
/ 04 июня 2019

Вы можете использовать Document.getAllElements() и проверить каждый элемент, если он имеет ownText(). Если это ничего не делать. Если нет, добавьте все дочерние элементы к родительскому узлу, если он есть. Это должно сделать работу:

Document document = Jsoup.parse(html);
document.getAllElements().stream()
        .filter(e -> e.ownText().isEmpty())
        .filter(Element::hasParent)
        .forEach(e -> {
            e.children().forEach(e.parent()::appendChild);
            e.remove();
        });

Результат кода, которым вы поделились, будет таким:

<div>
 I have some text
</div>
<div>
 I also have text 
 <div>
  I also have text
 </div> 
</div>

Как я уже упоминал в комментариях к правилу ownText(), элементы html, head и body также должны быть удалены.


Если вы хотите предотвратить удаление некоторых специальных тегов, вы можете использовать простые Set или List, которые содержат имена тегов, которые следует сохранить:

Set<String> retainTagNames = new HashSet<>(Arrays.asList("html", "body"));
Document document = Jsoup.parse(html);
document.getAllElements().stream()
        .filter(e -> ! retainTagNames.contains(e.tagName()))
        .filter(e -> e.ownText().isEmpty())
        .filter(Element::hasParent)
        .forEach(e -> {
            e.children().forEach(e.parent()::appendChild);
            e.remove();
        });

Результат этого будет:

<html>
 <head> 
 </head> 
 <body> 
  <div>
   I have some text
  </div>   
  <div>
   I also have text 
   <div>
    I also have text
   </div> 
  </div>
 </body>
</html>
...