You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Node.js/Discord.js实现Discord机器人解析XML并返回标签内容

Discord机器人XML解析及斜杠命令问题修复

问题背景

需要开发Discord机器人的/lookup斜杠命令:用户选择分类和名称后,机器人读取对应预准备的XML文件,解析标签内容并以Embed形式返回。例如选择spell分类和acid splash名称时,需从对应XML文件读取法术详情并返回。

示例XML文件结构:

<spell>
        <name>Acid Splash</name>
        <level>0</level>
        <school>C</school>
        <ritual>NO</ritual>
        <time>1 action</time>
        <range>60 feet</range>
        <components>V, S</components>
        <duration>Instantaneous</duration>
        <classes>Fighter (Eldritch Knight), Rogue (Arcane Trickster), Sorcerer, Wizard, Artificer</classes>
        <text>You hurl a bubble of acid. Choose one creature you can see within range, or choose two creatures you can see within range that are within 5 feet of each other. A target must succeed on a Dexterity saving throw or take 1d6 acid damage.</text>
        <text>  This spells damage increases by 1d6 when you reach 5th Level (2d6), 11th level (3d6) and 17th level (4d6).</text>
        <text/>
        <text>Source: Player's Handbook p. 211</text>
        <roll>1d6</roll>
</spell>

尝试A:机器人返回undefined

问题现象

代码无报错,控制台能打印测试XML字符串,但机器人返回内容显示undefined。

代码片段

const { SlashCommandBuilder } = require('discord.js');

module.exports = {
  data: new SlashCommandBuilder()
  .setName('test5')
  .setDescription('returns the contents of an xml file'),

  async execute(interaction){
    
    fs = require('fs');
    var parser = require('xml2json-light');

    fs.readFile( 'xml/a.xml', function(err, data) {

    // Attempt A
    // This version doesn't error, but it also doesn't produce a response...
    var xml = '<person><name>John Doe</name></person>';
    console.log("to json ->", xml);
    interaction.reply("to json ->", xml);
    
    // // Attempt B
    // // This version produces the attached error...
    // var json = parser.xml2json(data);
    // console.log("to json ->", data);
    // interaction.reply("to json ->", data);
    });
  }
}

控制台日志

// NOTE: I CAN'T GET ANYTHING AFTER THE -> TO PRODUCE AS A RESPONSE FROM THE BOT BECAUSE IT'S REGARDED AS 'UNDEFINED'...

to json -> <person><name>John Doe</name></person>

尝试B:xml2json-light解析触发TypeError

问题现象

调用parser.xml2json(data)时触发错误:TypeError: xmlStr.replace is not a function

报错信息

*************************Smashmouth-2\node_modules\xml2json-light\xml2json.js:67
    xmlStr = xmlStr.replace( /<!--[\s\S]*?-->/g, '' ); //remove commented lines
                    ^

TypeError: xmlStr.replace is not a function
    at cleanXML (C:\Users\snake\OneDrive\Documents\discord\Smashmouth-2\node_modules\xml2json-light\xml2json.js:11:14)
    at Object.xml2json (C:\Users\snake\OneDrive\Documents\discord\Smashmouth-2\node_modules\xml2json-light\xml2json.js:11:14)
    at C:\Users\snake\OneDrive\Documents\discord\Smashmouth-2\commands\utility\test5.js:23:23
    at FSReqCallback.readFileAfterClose [as oncomplete] (node:internal/fs/read_file_context:68:3)

问题修复方案

1. 修复尝试A的返回undefined问题

interaction.reply()仅接受单个字符串参数或配置对象,传入两个参数会导致第二个参数被忽略,正确写法是拼接字符串后传入:

// 错误写法
interaction.reply("to json ->", xml);
// 正确写法
interaction.reply(`to json -> ${xml}`);

同时建议改用fs.promises.readFile替代回调式读取,避免嵌套并更好适配async函数。

2. 修复尝试B的xml2json-light解析错误

fs.readFile默认返回Buffer对象,而xml2json-light需要字符串格式的XML内容,有两种解决方式:

  • 读取时指定编码为utf8:
fs.readFile('xml/a.xml', 'utf8', function(err, data) {
  var json = parser.xml2json(data);
});
  • 将Buffer转换为字符串:
var json = parser.xml2json(data.toString('utf8'));

3. 完整实现代码(含Embed返回)

整合修复后的完整命令代码,实现读取XML、解析并返回Discord Embed:

const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
const fs = require('fs').promises;
const parser = require('xml2json-light');

module.exports = {
  data: new SlashCommandBuilder()
    .setName('lookup')
    .setDescription('查询指定分类的内容')
    .addStringOption(option =>
      option.setName('category')
        .setDescription('选择分类(如spell)')
        .setRequired(true)
        .addChoices(
          { name: '法术', value: 'spell' },
          // 可添加更多分类选项
        ))
    .addStringOption(option =>
      option.setName('name')
        .setDescription('输入内容名称(如Acid Splash)')
        .setRequired(true)),

  async execute(interaction) {
    // 延迟回复避免超时
    await interaction.deferReply();

    const category = interaction.options.getString('category');
    const name = interaction.options.getString('name').toLowerCase();

    // 构建XML文件路径(实际可根据分类映射到不同文件)
    const filePath = `xml/${category}.xml`;

    try {
      // 读取XML文件(字符串格式)
      const xmlContent = await fs.readFile(filePath, 'utf8');
      // 解析XML为JSON
      const jsonData = parser.xml2json(xmlContent);

      const spell = jsonData.spell;
      if (!spell) {
        return interaction.editReply(`未找到名称为${name}的${category}内容`);
      }

      // 合并多段text内容
      let description = '';
      if (Array.isArray(spell.text)) {
        description = spell.text.filter(text => text).join('\n\n');
      } else if (spell.text) {
        description = spell.text;
      }

      // 构建Embed
      const embed = new EmbedBuilder()
        .setTitle(spell.name)
        .setColor('#0099ff')
        .addFields(
          { name: '等级', value: spell.level, inline: true },
          { name: '学派', value: spell.school, inline: true },
          { name: '仪式', value: spell.ritual, inline: true },
          { name: '施法时间', value: spell.time, inline: true },
          { name: '射程', value: spell.range, inline: true },
          { name: '组件', value: spell.components, inline: true },
          { name: '持续时间', value: spell.duration, inline: true },
          { name: '可用职业', value: spell.classes },
          { name: '伤害骰', value: spell.roll, inline: true }
        )
        .setDescription(description)
        .setFooter({ text: '数据来源:预准备XML文件' });

      await interaction.editReply({ embeds: [embed] });
    } catch (error) {
      console.error('查询出错:', error);
      await interaction.editReply('查询过程中发生错误,请检查日志');
    }
  }
};

额外优化建议

  • 若XML文件包含多个条目,需解析后遍历查找对应名称的内容
  • 添加名称模糊匹配功能,提升用户体验
  • 缓存已解析的XML数据,避免重复读取文件,加快响应速度

内容的提问来源于stack exchange,提问作者Jake Livsey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 23:25:52