如何通过嵌套DOMElement类生成HTML标记?修复递归转换方法
修复DOMElement转HTML的递归方法及替代方案
原代码存在的问题
- 递归时错误传递
str参数,导致字符串重复累积 - 属性格式错误,缺少前引号,正确格式应为
attr="value" - 未处理当前节点,直接遍历子节点,根元素(如
<html>)不会被输出 - 强制清空有子节点元素的
TextContent,忽略了元素可同时包含文本与子节点的情况 - 使用
forEach修改str无效,字符串是值类型,修改不会影响外部变量
修复后的递归方法
public convertToHtml(domTree: DOMElement): string { // 处理属性,生成标准的attr="value"格式 const attributes = domTree.Attributes.map((attr, index) => { const value = domTree.AttributesValue[index] || ''; return `${attr}="${value}"`; }).join(' '); // 构建开始标签,属性为空时省略空格 const startTag = attributes ? `<${domTree.TagName.toLowerCase()} ${attributes}>` : `<${domTree.TagName.toLowerCase()}>`; // 递归生成所有子节点的HTML const childrenHtml = domTree.Children.map(child => this.convertToHtml(child)).join(''); // 处理文本内容,null转为空字符串避免输出异常 const textContent = domTree.TextContent ?? ''; // 拼接当前节点的完整HTML return `${startTag}${textContent}${childrenHtml}</${domTree.TagName.toLowerCase()}>`; }
修复说明
- 正确处理当前节点:每个节点先生成自身的开始标签,再拼接文本和子节点的HTML,最后闭合标签,根节点也会被正确输出
- 属性格式修正:用
map生成标准属性字符串,再通过join拼接,避免格式错误 - 递归逻辑优化:不再传递
str参数,每个递归调用返回当前节点的HTML字符串,父节点直接拼接子节点的返回值,杜绝重复累积 - 保留文本与子节点共存:不再强制清空
TextContent,支持元素同时包含文本和子元素(如示例中的<div>既有123又有<a>标签) - 空值安全处理:用
??运算符将TextContent的null转为空字符串,避免输出null文本
非递归替代方案(迭代法)
适合深层DOM结构,避免递归栈溢出:
public convertToHtmlIterative(root: DOMElement): string { let html = ''; // 栈元素:[节点, 是否已处理闭合标签] const stack: [DOMElement, boolean][] = [[root, false]]; while (stack.length > 0) { const [node, isClosed] = stack.pop()!; if (isClosed) { // 处理闭合标签 html += `</${node.TagName.toLowerCase()}>`; continue; } // 生成属性字符串 const attributes = node.Attributes.map((attr, index) => { const value = node.AttributesValue[index] || ''; return `${attr}="${value}"`; }).join(' '); // 添加开始标签 const startTag = attributes ? `<${node.TagName.toLowerCase()} ${attributes}>` : `<${node.TagName.toLowerCase()}>`; html += startTag; // 添加文本内容 html += node.TextContent ?? ''; // 先推入当前节点的闭合标记,再反向推入子节点(保证子节点顺序正确) stack.push([node, true]); for (let i = node.Children.length - 1; i >= 0; i--) { stack.push([node.Children[i], false]); } } return html; }
内容的提问来源于stack exchange,提问作者ehhh
相关产品推荐
相关产品推荐

