Java 使用JSoup解析HTML列表以创建树结构

Java 使用JSoup解析HTML列表以创建树结构,java,html,jsoup,Java,Html,Jsoup,我有HTML列表,其结构与我需要使用JSoup(我的语言是Java)解析的结构完全相同。下面是一个例子: <div class="ulist"> <ul> <li><p>Healthy Food</p></li> <div class="ulist"> <ul> <li><p>Vegetables</p></li

我有HTML列表,其结构与我需要使用JSoup(我的语言是Java)解析的结构完全相同。下面是一个例子:

<div class="ulist">
  <ul>
    <li><p>Healthy Food</p></li>
    <div class="ulist">
      <ul>
        <li><p>Vegetables</p></li>
        <div class="ulist">
          <ul>
            <li> <p>Carrots</p> </li>
            <li> <p>Lettuce</p> </li>
            <li> <p>Cucumbers</p> </li>
          </ul>
        </div> </li>
        <li> <p>Fruits</p>
          <div class="ulist">
            <ul>
              <li> <p>Apples</p> </li>
              <li> <p>Bananas</p> </li>
              <li> <p>Canned Fruits</p></li>
              <div class="ulist">
                <ul>
                  <li> <p>Peaches</p> </li>
                  <li> <p>Pears</p> </li>
                </ul>
              </div>
            </ul>
          </div>
        </li>
      </ul>
    </div>
  </ul>
</div>
生成以下结果,其中显示的不是向下“行走”或“遍历”,而是一直从文档中选择相同的内容:


什么代码可以遍历这个列表并将其放入树结构中?

JSoup将DOM构建为内存中的数据结构,您可以通过非常强大的“随机访问”方式访问它,例如使用出色的css选择器实现。要解决JSoup的问题,您可以循环使用以下结果:

Elements elList = doc.select("ul");
for (Element el: elList){
    Elements subList = el.select("ul");
    for (Element subEl : subList){
       //do whatever you need to do
    }
}

但是,如果需要遍历非常大的html文件,并且这些文件结构良好,则可能需要使用SAX之类的库。这样可以避免将整个DOM保存在内存中

在JSoup中,
select()
getElementByTag()
如果当前元素与标记匹配,则返回当前元素作为结果的一部分

因此,当您执行
doc.select(“ul”)
,并对结果执行
select()
,您将得到相同的结果,正如您已经注意到的那样

正确执行此操作的关键是获取第一个元素,然后搜索其子元素

大致如下:

public static Node processTree( Element elem ) {

     Node result;

     Elements elList = elem.getElementsByTag("ul");

     if ( elList == null || elList.size() == 0 ) {
         return null;
     };

     result = new Node();
     Element current = elList.first();
     elList = current.children();

     // Process LI elements and add them as content to the
     // result Node
     ...

     // Now go down the tree

     if ( elList != null && elList.size() != 0 ) {

        for ( Element el : elList ) {
            Node elTree = processTree( el );
            if ( elTree != null ) {
                result.addChild( elTree );
            }
        }
     }

     return result;
}

(当然,这只是一个草图。
节点
将是您的树结构节点。这一点是为了告诉您必须遍历子节点。如果您愿意,您可以在同一个循环中处理
li
元素)

遍历DOM有什么问题?我想问题是我,我不知道如何正确使用JSoup来遍历DOM。基本上,问题在于调用的结果,如
Element list=doc.select(“ul”).first(),如果我在results
Element subList=list上再次调用相同的代码。选择(“ul”).first(),我得到与第一次调用相同的结果。我想我希望库只“消费”选定的部分。不确定这是否有意义。谢谢你的回答,但这并没有像预期的那样有效(这是我问题的根源)。我在上面添加了一个屏幕截图和示例,您可以用它来澄清。谢谢您的回答,简单而有用。
public static Node processTree( Element elem ) {

     Node result;

     Elements elList = elem.getElementsByTag("ul");

     if ( elList == null || elList.size() == 0 ) {
         return null;
     };

     result = new Node();
     Element current = elList.first();
     elList = current.children();

     // Process LI elements and add them as content to the
     // result Node
     ...

     // Now go down the tree

     if ( elList != null && elList.size() != 0 ) {

        for ( Element el : elList ) {
            Node elTree = processTree( el );
            if ( elTree != null ) {
                result.addChild( elTree );
            }
        }
     }

     return result;
}