在Node.js中为缺失闭合标签的XML补充标签以实现解析
解决Node.js解析无闭合标签的非标准XML问题
我之前处理过不少这类“半吊子”XML的场景,刚好能给你一套可行的Node.js解决方案!这种XML的核心问题是只有块级容器元素(比如<ISSUER>、<COMPANY-DATA>)有闭合标签,而叶子元素(比如<CONFORMED-NAME>、<CIK>)只有起始标签,内容直接跟在后面直到下一个标签出现。我们的思路是先预处理文本补全闭合标签,再用标准XML解析库处理。
方法一:正则表达式快速预处理(推荐)
这种方式简单直接,针对你的场景完全够用。核心是用正则匹配所有“<标签>内容”的模式,自动补上闭合标签:
const fs = require('fs'); const xml2js = require('xml2js'); // 也可以用cheerio、libxmljs等解析库 // 1. 读取原始非标准XML文件 const rawXml = fs.readFileSync('./your-file.xml', 'utf8'); // 2. 预处理:给所有叶子元素补全闭合标签 const processedXml = rawXml.replace(/<([A-Z-]+)>([^<]+)/g, (match, tagName, content) => { // 修剪内容前后的空白,避免解析后出现多余空格 const cleanContent = content.trim(); return `<${tagName}>${cleanContent}</${tagName}>`; }); // 3. 用标准XML解析库处理补全后的XML const parser = new xml2js.Parser({ explicitArray: false }); // 关闭自动数组转换,让结构更直观 parser.parseString(processedXml, (err, parsedResult) => { if (err) { console.error('解析出错:', err); return; } // 打印解析后的结构化数据 console.log(JSON.stringify(parsedResult, null, 2)); });
正则逻辑说明
/<([A-Z-]+)>([^<]+)/g 会精准匹配:
- 由大写字母和连字符组成的标签名(比如
CONFORMED-NAME、CIK) - 标签后紧跟的非
<字符内容(也就是叶子元素的文本值)
块级元素的起始标签(比如<COMPANY-DATA>)后面是下一个<标签,所以不会被这个正则匹配到,完美避开了不需要处理的容器标签。
方法二:状态机处理(复杂场景备选)
如果你的XML存在更极端的情况(比如内容里包含<字符),可以用状态机逐字符处理,确保准确性:
const fs = require('fs'); function fixUnclosedTags(xml) { let result = ''; let currentTag = null; let inTag = false; for (let char of xml) { if (char === '<') { // 如果之前有未闭合的标签,先补上闭合标签 if (currentTag) { result += `</${currentTag}>`; currentTag = null; } inTag = true; result += char; } else if (char === '>') { inTag = false; result += char; // 提取当前标签名(排除闭合标签的/) const tagMatch = result.match(/<([A-Z-]+)>$/); if (tagMatch && !result.endsWith('</')) { currentTag = tagMatch[1]; } } else { result += char; } } // 处理最后一个未闭合的标签 if (currentTag) { result += `</${currentTag}>`; } return result; } // 使用示例 const rawXml = fs.readFileSync('./your-file.xml', 'utf8'); const processedXml = fixUnclosedTags(rawXml); // 后续解析步骤同方法一
验证效果
用你提供的示例XML测试,预处理后会生成标准XML:
<ISSUER> <COMPANY-DATA> <CONFORMED-NAME>EXACTECH INC</CONFORMED-NAME> <CIK>000012345</CIK> <ASSIGNED-SIC>9999</ASSIGNED-SIC> <IRS-NUMBER>8979898988</IRS-NUMBER> <STATE-OF-INCORPORATION>FL</STATE-OF-INCORPORATION> <FISCAL-YEAR-END>1231</FISCAL-YEAR-END> </COMPANY-DATA> <BUSINESS-ADDRESS> <STREET1>22W 56TH COURT</STREET1> <CITY>GAINSVILLE</CITY> <STATE>FL</STATE> <ZIP>32653</ZIP> <PHONE>999-999-9999</PHONE> </BUSINESS-ADDRESS> <MAIL-ADDRESS> <STREET1>22W 56TH COURT</STREET1> <CITY>GAINSVILLE</CITY> <STATE>FL</STATE> <ZIP>32653</ZIP> </MAIL-ADDRESS> </ISSUER>
这个标准XML可以被任何主流XML解析库正常解析。
内容的提问来源于stack exchange,提问作者Shantanu Paul
相关产品推荐
相关产品推荐

