实现 DOM2JSON:将 DOM 节点转换为 JSON 格式

手写一个函数,将 DOM 树结构转换为 JSON 对象,保留节点的标签名、属性和子节点信息

问题

在前端开发中,有时需要将 DOM 节点序列化为 JSON 格式,以便于存储、传输或进行其他处理。这道题要求实现一个 DOM2JSON 函数,能够将一个 DOM 节点及其子节点转换为 JSON 对象,包含节点的标签名、属性和子节点等信息。

解答

/**
 * 将 DOM 节点转换为 JSON 格式
 * @param {HTMLElement} node - DOM 节点
 * @returns {Object} JSON 对象
 */
function DOM2JSON(node) {
  // 创建结果对象
  const result = {};
  
  // 1. 保存节点标签名
  result.tag = node.tagName.toLowerCase();
  
  // 2. 保存节点属性
  if (node.attributes && node.attributes.length > 0) {
    result.attributes = {};
    Array.from(node.attributes).forEach(attr => {
      result.attributes[attr.name] = attr.value;
    });
  }
  
  // 3. 保存子节点
  if (node.childNodes && node.childNodes.length > 0) {
    result.children = [];
    
    Array.from(node.childNodes).forEach(child => {
      // 处理元素节点
      if (child.nodeType === Node.ELEMENT_NODE) {
        result.children.push(DOM2JSON(child));
      }
      // 处理文本节点(过滤空白文本)
      else if (child.nodeType === Node.TEXT_NODE) {
        const text = child.textContent.trim();
        if (text) {
          result.children.push({
            type: 'text',
            content: text
          });
        }
      }
    });
    
    // 如果没有有效子节点,删除 children 属性
    if (result.children.length === 0) {
      delete result.children;
    }
  }
  
  return result;
}

使用示例

// 示例 HTML 结构
const html = `
  <div id="container" class="wrapper">
    <h1>标题</h1>
    <p class="text">这是一段文本</p>
    <ul>
      <li>列表项1</li>
      <li>列表项2</li>
    </ul>
  </div>
`;

// 创建 DOM 节点
const container = document.createElement('div');
container.innerHTML = html;
const domNode = container.firstElementChild;

// 转换为 JSON
const json = DOM2JSON(domNode);
console.log(JSON.stringify(json, null, 2));

/* 输出结果:
{
  "tag": "div",
  "attributes": {
    "id": "container",
    "class": "wrapper"
  },
  "children": [
    {
      "tag": "h1",
      "children": [
        {
          "type": "text",
          "content": "标题"
        }
      ]
    },
    {
      "tag": "p",
      "attributes": {
        "class": "text"
      },
      "children": [
        {
          "type": "text",
          "content": "这是一段文本"
        }
      ]
    },
    {
      "tag": "ul",
      "children": [
        {
          "tag": "li",
          "children": [
            {
              "type": "text",
              "content": "列表项1"
            }
          ]
        },
        {
          "tag": "li",
          "children": [
            {
              "type": "text",
              "content": "列表项2"
            }
          ]
        }
      ]
    }
  ]
}
*/

关键点

  • 递归遍历:使用递归方式处理 DOM 树结构,确保所有层级的节点都能被正确转换

  • 节点类型判断:需要区分元素节点(ELEMENT_NODE)和文本节点(TEXT_NODE),分别进行处理

  • 属性处理:通过 node.attributes 获取所有属性,使用 Array.from() 转换为数组后遍历

  • 文本节点过滤:使用 trim() 过滤掉空白文本节点,避免 JSON 中出现无意义的空白内容

  • 数据结构设计:合理设计 JSON 结构,包含 tag(标签名)、attributes(属性对象)、children(子节点数组)等字段

  • 边界处理:当节点没有属性或子节点时,可以选择不添加对应字段,使 JSON 结构更简洁

  • 可扩展性:可以根据需求扩展功能,如处理注释节点、保留样式信息等