如何用Node.js遍历XML节点并输出指定标签下全部子节点内容
问题
我希望通过Node.js结合用户输入遍历XML节点,例如输入“unit”时,输出该标签下的所有内容。XML结构如下:
<course> <name>...</name> <duration>...</duration> <unit> <title>...</title> <lecturer> <surname language="English">...</surname> <othernames language="English">...</othernames> <email>...</email> </lecturer> </unit> </course>
目前我能获取unit标签下的title内容,但无法输出lecturer、surname、othernames和email标签的内容。请问该如何修改代码以实现需求?当前使用的代码如下:
const xmldom = require('xmldom').DOMParser; const fs = require('fs'); const readLineSync = require('readline-sync'); let parser, doc, targetNodes; let i, count = 0, userInput; let targetObj, fcObj, parentObj; // use fs to read xml document fs.readFile('course.xml', 'utf-8', function (err, data) { if (err) { throw err; } // construct parser parser = new xmldom(); // call method to parse document - not the type doc = parser.parseFromString(data, 'application/xml'); userInput = readLineSync.question("Enter tag to be printed: "); // use DOM Node method targetNodes = doc.getElementsByTagName(userInput.toLowerCase()); console.log("Tag " + userInput + " entered"); for (i in targetNodes) { // process current ith node targetObj = targetNodes[i]; // if it is the firstchild if (targetObj.firstChild) { // obtain the node value fcObj = targetObj.childNodes; parentObj = targetObj.parentNode; if (parentObj == null && count == 0){ console.log("No identical tag found."); } else { count = 1; if (parentObj != null) { if (fcObj[count].childNodes) { console.log(fcObj[count].childNodes[0].nodeValue); } else { console.log(fcObj[count].nodeValue); } } } } } });
解决方案
原代码仅处理了目标节点的单个子节点,未递归遍历嵌套子元素,同时未过滤XML解析产生的空白文本节点。以下是修改后的代码,可实现遍历目标标签下所有内容的功能:
const xmldom = require('xmldom').DOMParser; const fs = require('fs'); const readLineSync = require('readline-sync'); // 递归遍历节点并输出内容的函数 function traverseNode(node, indent = 0) { // 过滤空白文本节点和注释节点 if (node.nodeType === Node.TEXT_NODE && node.nodeValue.trim() === '') { return; } const indentStr = ' '.repeat(indent); if (node.nodeType === Node.ELEMENT_NODE) { // 输出标签名及属性 let tagStr = `${indentStr}<${node.tagName}`; if (node.attributes.length > 0) { Array.from(node.attributes).forEach(attr => { tagStr += ` ${attr.name}="${attr.value}"`; }); } tagStr += '>'; console.log(tagStr); // 递归遍历所有子节点 Array.from(node.childNodes).forEach(child => { traverseNode(child, indent + 1); }); // 输出闭合标签 console.log(`${indentStr}</${node.tagName}>`); } else if (node.nodeType === Node.TEXT_NODE) { // 输出文本内容 console.log(`${indentStr}${node.nodeValue.trim()}`); } } fs.readFile('course.xml', 'utf-8', function (err, data) { if (err) { throw err; } const parser = new xmldom(); const doc = parser.parseFromString(data, 'application/xml'); const userInput = readLineSync.question("Enter tag to be printed: "); const targetNodes = doc.getElementsByTagName(userInput.toLowerCase()); console.log(`Tag ${userInput} entered`); if (targetNodes.length === 0) { console.log("No identical tag found."); return; } // 遍历所有匹配的目标节点 Array.from(targetNodes).forEach((node, index) => { console.log(`\n--- 匹配的第 ${index + 1} 个 ${userInput} 节点内容 ---`); traverseNode(node); }); });
修改说明
- 新增递归遍历函数:
traverseNode负责递归处理所有子节点,包括嵌套的lecturer、surname等元素。 - 过滤无效节点:跳过XML中因换行、缩进产生的空白文本节点,避免输出冗余内容。
- 完整输出标签信息:不仅输出标签内容,还会打印标签的属性(比如
surname的language属性),并保持层级缩进,结构更清晰。 - 优化节点遍历逻辑:用
Array.from将NodeList转为数组,避免遍历到非节点属性;增加匹配节点数量判断,直接提示无匹配的情况。
内容的提问来源于stack exchange,提问作者allen walker
相关产品推荐
相关产品推荐

