在Java中查找嵌套匹配的HTML标记

时间:2013-06-03 16:01:36

标签: java html tags jsoup

我在Java中使用有效的HTML字符串(使用jsoup解析,因此所有标记都有结束标记并且形成良好),我需要找到给定标记名称的内容,例如 ,使用以下字符串:

<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>

我通过简单地将apache.commons.lang库与该方法一起使用来完成这项工作 StringUtils.substringsBetween(String html,String“opentag”,String“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>

但是我得到一个(我知道它是因为标签出现在字符串中的方式)我只是不知道如何解决它。我现在已经苦苦挣扎了两个星期了,我已经尝试使用正则表达式而没有任何成功,我也尝试将html字符串拆分为一系列行,但也失败了。

你会如何解决这个问题?我已经知道有很多库使用jsoup的getAllElementsByTag(tagName)等方法为你做这件事,但我想自己做。任何提示都表示赞赏!

3 个答案:

答案 0 :(得分:1)

您需要大量使用标记化和递归来解决此问题。基本上,每次打开新标记(例如<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格式正确。但这足以让他们了解这个想法。声明的ArrayList<String>将包含所有<div>标记及其内容。

答案 1 :(得分:1)

标准方法是使用堆栈。即,当您遇到开始标记时,您将转储到堆栈中,并且每当遇到结束标记时,您都会弹出最顶层的项目。如果String确实格式正确,则所有结束标记都应弹出匹配的开始标记。从那里开始,弄清楚如何获得内部对的内容应该是一块蛋糕。

答案 2 :(得分:0)

TagSoupJsoup将是您正在寻找的那个:)