如何使用Jericho HTML Parser递归解析HTML元素?求实现指引
递归解析HTML并转换标签的实现思路(基于Jericho HTML Parser)
我需要用Jericho HTML Parser递归解析一段HTML,核心需求是:提取元素的wicket:id属性值作为新标签名;没有该属性的标准HTML标签保持原样。目前的代码无法实现递归逻辑,求可行的实现思路。
HTML内容
<div wicket:id="Container1"> <div wicket:id="Panel1"></div> <form wicket:id="sampleForm" action=""> <div id="InterstitialPanel" class="usaa-interstitial s1"></div> <div wicket:id="DisclosureSection"> <div class="sample class"> <ul> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> <li>Item 4</li> </ul> </div> </div> </form> </div> <div wicket:id="Container2"> <h2>This is container 2</h2> </div>
预期输出
需求明确:从原始HTML中提取wicket:id属性值创建新标签;无wicket属性的标准HTML标签保持原样。
<Container1> <Panel1></Panel1> <Form id="sampleForm"> <InterstitialPanel></InterstitialPanel> <DisclosureSection> <div class="sample class"> <ul> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> <li>Item 4</li> </ul> </div> </DisclosureSection> </Form> This is container 2
现有Java代码
public static void main(String args[]) { Main m = new Main(); File file = new File("C:\\USAAPoC\\ClientSamplePage.html"); Source doc = new Source(file); Element element = doc.getElementByTag("body"); m.processBody(element, new ReactPageContext()); } private StringBuilder processBody(Element element, ReactPageContext reactPageContext) { StringBuilder sb = new StringBuilder(); if (!element.getChildElements().isEmpty()) { element.getChildElements().stream().forEach(child -> sb.append(processTag(child, reactPageContext))); } else { sb.append("<Container>\n"); } return sb; } private StringBuilder processTag(Element element, ReactPageContext reactPageContext) { StringBuilder sb = new StringBuilder(); element.getAllElements().stream().forEach(child -> { if (child.getName().equals("div") && child.getAttributes().get("wicket:id") != null) { sb.append("<Container>"); } else if (child.getName().equals("form")) { sb.append("<Form>"); List<Element> allChildFormElements = outputDocument.getSegment().getAllElements(); allChildFormElements.stream().forEach(childFormElement -> { if (childFormElement.getName().equals("div") && childFormElement.getAttributes().get("wicket:id") != null) { sb.append("<Container>"); } else { // 未实现的逻辑 } }); } }); return sb; }
实现思路与重构代码
核心递归逻辑
递归的核心是每个元素处理自身后,必须递归处理其所有子节点,不管是带wicket:id的自定义标签,还是普通HTML标签、文本节点,都要逐层遍历处理。
具体处理规则
- 标签转换规则:
- 若元素存在
wicket:id属性:- 除
<form>外,直接用wicket:id的值作为新标签名,丢弃原标签和属性 <form>需特殊处理:新标签名为<Form>,并将wicket:id的值转为id属性
- 除
- 若无
wicket:id属性:保留原标签名和所有属性
- 若元素存在
- 文本节点处理:直接保留文本内容,不要忽略
- 闭合标签:所有标签必须正确闭合,空标签也要生成完整的闭合结构(如
<Panel1></Panel1>)
重构后的代码示例
import net.htmlparser.jericho.Element; import net.htmlparser.jericho.Source; import net.htmlparser.jericho.StartTag; import java.io.File; import java.util.List; public class HtmlParser { public static void main(String args[]) throws Exception { HtmlParser parser = new HtmlParser(); File file = new File("C:\\USAAPoC\\ClientSamplePage.html"); Source doc = new Source(file); Element bodyElement = doc.getElementByTag("body"); StringBuilder result = parser.processElement(bodyElement); System.out.println(result.toString()); } private StringBuilder processElement(Element element) { StringBuilder sb = new StringBuilder(); // 处理当前元素的开始标签 StartTag startTag = element.getStartTag(); String wicketId = startTag.getAttributeValue("wicket:id"); if (wicketId != null) { if (element.getName().equalsIgnoreCase("form")) { // Form标签特殊处理:保留id属性 sb.append(String.format("<Form id=\"%s\">\n", wicketId)); } else { // 其他带wicket:id的元素,直接用属性值作为标签名 sb.append(String.format("<%s>\n", wicketId)); } } else { // 无wicket:id的元素,保留原标签和属性 sb.append(startTag.toString()); sb.append("\n"); } // 递归处理子节点:包括元素节点和文本节点 List<?> childNodes = element.getChildNodes(); for (Object node : childNodes) { if (node instanceof Element) { sb.append(processElement((Element) node)); } else { // 处理文本节点,去除多余空白(可选,根据需求调整) String text = node.toString().trim(); if (!text.isEmpty()) { sb.append(text).append("\n"); } } } // 处理闭合标签 if (wicketId != null) { if (element.getName().equalsIgnoreCase("form")) { sb.append("</Form>\n"); } else { sb.append(String.format("</%s>\n", wicketId)); } } else { sb.append(element.getEndTag().toString()).append("\n"); } return sb; } }
关键改进点
- 合并
processBody和processTag为统一的processElement方法,递归处理所有元素 - 覆盖所有节点类型:不仅处理元素节点,还处理文本节点
- 明确标签转换规则,包括form的特殊处理
- 自动处理标签闭合,避免遗漏
- 修复原代码中
outputDocument未定义的错误
内容的提问来源于stack exchange,提问作者Sai
相关产品推荐
相关产品推荐

