Node.js中过滤格式化XML并返回客户端的推荐实现方案咨询
Node.js XML处理最优方案推荐
原有方案的性能问题原因
你现在用的xml2js属于DOM式解析库,会把完整XML结构全部加载到内存后再转换成JSON对象,如果你处理的XML文件体积较大、或者并发请求量较高,内存占用和处理延迟都会明显升高,确实不是最优选择。
分场景推荐方案
场景1:处理大体积XML/高并发请求
优先选择SAX流式解析方案,无需加载完整文件,边读取边解析,内存占用始终维持在极低水平,性能上限最高。推荐使用sax流式解析库配合轻量XML生成库xmlbuilder2实现,示例代码如下:
const fs = require('fs') const sax = require('sax') const { create } = require('xmlbuilder2') // 自定义过滤条件 const TARGET_DATE = '12.21.2000' const MIN_DISH_COUNT = 2 const saxStream = sax.createStream(true, { trim: true }) let currentMenu = null let currentTag = '' let dishCounter = 0 // 监听标签开事件 saxStream.on('opentag', node => { if (node.name === 'menu') { currentMenu = { date: '' } dishCounter = 0 } currentTag = node.name }) // 监听标签内文本事件 saxStream.on('text', text => { if (!currentMenu) return if (currentTag === 'date') currentMenu.date = text if (currentTag === 'dish') dishCounter++ }) // 监听标签关事件 saxStream.on('closetag', tagName => { if (tagName === 'menu') { // 匹配过滤条件则生成返回XML if (currentMenu.date === TARGET_DATE && dishCounter >= MIN_DISH_COUNT) { const resXml = create({ version: '1.0' }) .ele('menu') .ele('date').txt(currentMenu.date).up() .ele('numberofdishes').txt(String(dishCounter)).up() .end({ prettyPrint: true }) // 直接返回给请求客户端即可 console.log(resXml) } currentMenu = null dishCounter = 0 } currentTag = '' }) // 流式读取本地XML文件输入到解析器 fs.createReadStream('./menu-data.xml').pipe(saxStream)
场景2:处理小体积XML(10MB以内)
如果你的XML文件体积很小,优先选择轻量高性能的fast-xml-parser库,比xml2js解析性能高3~5倍,API更简洁,代码维护成本低。示例代码如下:
const fs = require('fs') const { XMLParser, XMLBuilder } = require('fast-xml-parser') // 自定义过滤条件 const TARGET_DATE = '12.21.2000' const MIN_DISH_COUNT = 2 // 初始化解析器,关闭不必要的解析能力减少开销 const parser = new XMLParser({ ignoreAttributes: true, trimValues: true }) const rawXml = fs.readFileSync('./menu-data.xml', 'utf8') const parsedData = parser.parse(rawXml) // 过滤符合条件的menu const matchedMenu = parsedData.root.menu.find(menu => { const dishCount = Array.isArray(menu.dishes.dish) ? menu.dishes.dish.length : 1 return menu.date === TARGET_DATE && dishCount >= MIN_DISH_COUNT }) // 生成目标格式XML const builder = new XMLBuilder({ prettyPrint: true }) const resXml = builder.build({ menu: { date: matchedMenu.date, numberofdishes: Array.isArray(matchedMenu.dishes.dish) ? matchedMenu.dishes.dish.length : 1 } }) console.log(resXml)
注意:如果XML中存在单个dish的情况(解析后为对象而非数组),需要额外做兼容判断,避免取length属性时报错。
内容的提问来源于stack exchange,提问作者EdgyCoder
相关产品推荐
相关产品推荐

