我在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)等方法为你做这件事,但我想自己做。任何提示都表示赞赏!
答案 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)
TagSoup
或Jsoup
将是您正在寻找的那个:)