(算法)使用JS实现将XML解析为Dom树

228 阅读1分钟

最近参加了一个面试,和面试官聊的很好,但是最后的算法题让我有点尴尬了——第一反应是没思路,大概是对XML格式和对DOM树的理解还未到位,面试结束后,经过网上资料搜索和自己的学习,分析了以下算法题目:

给定一串xml文本,请解析成一个dom树, 不需要纠错,需要处理解析错误case​

综合以上题目,我就直接上代码分析了:

function parseXML(xmlString) {
  const stack = [];//用于存储解析过程中的节点
  let currentNode = null;//当前节点
  let tagName = "";//当前标签名
  let textContent = "";//当前文本内容

  for (let i = 0; i < xmlString.length; i++) {
    if (xmlString[i] === "<") {
      // 开始标签
      if (xmlString[i + 1] !== "/") {
        // 获取标签名
        const nextSpaceIndex = xmlString.indexOf(" ", i + 1);
        const nextCloseIndex = xmlString.indexOf(">", i + 1);
        const endIndex = Math.min(nextSpaceIndex, nextCloseIndex);
        tagName = xmlString.substring(i + 1, endIndex);
        //在找到空格和大于号之后,使用substring方法提取标签名

        // 创建节点
        const node = { tagName, attributes: {}, children: [], parent: currentNode };
        stack.push(node);
        currentNode = node;
        //创建了一个节点对象,该节点的属性包括'tagName'、'attributes'、'children'、'parent',然后将该节点对象推入栈中,并将当前节点更新为新创建的节点

        // 解析属性
        let attrName = "";//用于暂存属性名
        let attrValue = "";//用于暂存属性值
        for (let j = endIndex + 1; j < xmlString.length; j++) {
          if (xmlString[j] === "=") {
            attrName = xmlString.substring(endIndex + 1, j);//当遇到“=”时,则将“attrName”更新为等号前的字符串,即属性名。
          }
          if (xmlString[j] === "\"" || xmlString[j] === "'") {
            const nextQuoteIndex = xmlString.indexOf(xmlString[j], j + 1);
            attrValue = xmlString.substring(j + 1, nextQuoteIndex);
            j = nextQuoteIndex;
            currentNode.attributes[attrName] = attrValue;
            attrName = "";
            attrValue = "";
          }
        //如果遇到单引号或双引号,则表示属性值的开始和结束,通过查找下一个相同的引号位置,提取出属性值,并将属性名和属性值存储在当前节点的attributes对象中
          if (xmlString[j] === ">") {
            break;
          }//解析完成
          endIndex = j;
        }
      }
      // 结束标签
      else {
        currentNode.textContent = textContent.trim();
        textContent = "";
        currentNode = stack.pop();
      }
    } else {
      textContent += xmlString[i];
    }
  }
  return currentNode;
}

这个算法主要是使用递归和栈结构来实现解析XML字符串并构建DOM树,不过这个算法只适用于结构较为简单的XML文本(未处理错误),限制条件如下:

(1)合乎XML语法,不包含注释或者处理指令

(2)标签或属性名只包含字母、数字和下划线,且不以数字开头

(3)属性值只包含双引号或单引号