Jsoup: как получить весь html между двумя тегами заголовка

Я пытаюсь получить весь html между двумя тегами h1. Актуальная задача состоит в том, чтобы разбить html на фреймы (главы) на основе тегов h1 (заголовок 1).

Цените любую помощь.

Спасибо, Сунил.


person Sunil Ramu    schedule 30.06.2011    source источник
comment
Вы пытаетесь получить из него '‹h1›abc‹/h1›' abc   -  person Rasel    schedule 30.06.2011
comment
Я думаю, он хочет получить весь контент до следующего h1, чтобы он мог разделить страницу по заголовкам.   -  person Tim Büthe    schedule 30.06.2011


Ответы (3)


Если вы хотите получить и обработать все элементы между двумя последовательными тегами h1, вы можете работать с родственными элементами. Вот пример кода:

public static void h1s() {
  String html = "<html>" +
  "<head></head>" +
  "<body>" +
  "  <h1>title 1</h1>" +
  "  <p>hello 1</p>" +
  "  <table>" +
  "    <tr>" +
  "      <td>hello</td>" +
  "      <td>world</td>" +
  "      <td>1</td>" +
  "    </tr>" +
  "  </table>" +
  "  <h1>title 2</h1>" +
  "  <p>hello 2</p>" +
  "  <table>" +
  "    <tr>" +
  "      <td>hello</td>" +
  "      <td>world</td>" +
  "      <td>2</td>" +
  "    </tr>" +
  "  </table>" +
  "  <h1>title 3</h1>" +
  "  <p>hello 3</p>" +
  "  <table>" +
  "    <tr>" +
  "      <td>hello</td>" +
  "      <td>world</td>" +
  "      <td>3</td>" +
  "    </tr>" +
  "  </table>" +    
  "</body>" +
  "</html>";
  Document doc = Jsoup.parse(html);
  Element firstH1 = doc.select("h1").first();
  Elements siblings = firstH1.siblingElements();
  List<Element> elementsBetween = new ArrayList<Element>();
  for (int i = 1; i < siblings.size(); i++) {
    Element sibling = siblings.get(i);
    if (! "h1".equals(sibling.tagName()))
      elementsBetween.add(sibling);
    else {
      processElementsBetween(elementsBetween);
      elementsBetween.clear();
    }
  }
  if (! elementsBetween.isEmpty())
    processElementsBetween(elementsBetween);
}

private static void processElementsBetween(
    List<Element> elementsBetween) {
  System.out.println("---");
  for (Element element : elementsBetween) {
    System.out.println(element);
  }
}
person MarcoS    schedule 30.06.2011
comment
Как сделать так, чтобы название заголовка печаталось раньше и чтобы заголовки шли по порядку? Есть ли хорошее место, где я могу найти больше примеров на jsoup. - person Sunil Ramu; 14.07.2011
comment
Я предполагаю, что вы хотите напечатать текст заголовка, а не его имя (имя заголовка H1 всегда H1). Итак, для этого вы просто печатаете sibling.ownText() перед вызовом processElementsBetween(elementsBetween);. Я не уверен, что вы имеете в виду, говоря, чтобы заголовки шли по порядку. Документация JSoup: поваренная книга и apidocs - person MarcoS; 14.07.2011
comment
Это не будет работать для текста, не являющегося частью тега, например <h1/>this<h1/>. Кажется, это дыра в концепции jsoup. - person Jarekczek; 23.04.2012

Я не очень хорошо знаю Jsoup, но прямой подход может выглядеть так:

public class Test {

    public static void main(String[] args){

        Document document = Jsoup.parse("<html><body>" +
            "<h1>First</h1><p>text text text</p>" +
            "<h1>Second</h1>more text" +
            "</body></html>");

        List<List<Node>> articles = new ArrayList<List<Node>>();
        List<Node> currentArticle = null;

        for(Node node : document.getElementsByTag("body").get(0).childNodes()){
            if(node.outerHtml().startsWith("<h1>")){
                currentArticle = new ArrayList<Node>();
                articles.add(currentArticle);
            }

            currentArticle.add(node);
        }

        for(List<Node> article : articles){
            for(Node node : article){
                System.out.println(node);
            }
            System.out.println("------- new page ---------");
        }

    }

}

Знаете ли вы структуру статей и всегда ли она одинакова? Что вы хотите сделать со статьями? Рассматривали ли вы их разделение на стороне клиента? Это была бы простая работа jQuery.

person Tim Büthe    schedule 30.06.2011
comment
РЕДАКТИРОВАТЬ: изменен элемент на узел, чтобы он был более общим и захватывал текстовый узел без окружающих тегов. - person Tim Büthe; 30.06.2011
comment
Никакая структура не всегда одинакова. На самом деле это все текстовые документы, преобразованные в фильтрованный HTML. - person Sunil Ramu; 14.07.2011

Перебор элементов между последовательными элементами <h> выглядит нормально, за исключением одного. Текст, не принадлежащий ни одному тегу, как в <h1/>this<h1/>. Чтобы обойти это, я реализовал функцию splitElemText для получения этого текста. Сначала разделите весь родительский элемент, используя этот метод. Затем, кроме элемента, обработайте подходящую запись из разделенного текста. Удалите вызовы htmlToText, если вам нужен необработанный HTML.

/** Splits the text of the element <code>elem</code> by the children
  * tags.
  * @return An array of size <code>c+1</code>, where <copde>c</code>
  * is the number of child elements.
  * <p>Text after <code>n</code>th element is found in <code>[n+1]</code>.
  */
public static String[] splitElemText(Element elem)
{
  int c = elem.children().size();
  String as[] = new String[c + 1];
  String sAll = elem.html();
  int iBeg = 0;
  int iChild = 0;
  for (Element ch : elem.children()) {
    String sChild = ch.outerHtml();
    int iEnd = sAll.indexOf(sChild, iBeg);
    if (iEnd < 0) { throw new RuntimeException("Tag " + sChild
                    +" not found in its parent: " + sAll);
    }
    as[iChild] = htmlToText(sAll.substring(iBeg, iEnd));
    iBeg = iEnd + sChild.length();
    iChild += 1;
  }
  as[iChild] = htmlToText(sAll.substring(iBeg));
  assert(iChild == c);
  return as;
}

public static String htmlToText(String sHtml)
{
  Document doc = Jsoup.parse(sHtml);
  return doc.text();
}
person Jarekczek    schedule 25.04.2012