2024年在线市场平台的11大最佳支付解决方案
如何在JavaScript中解析XML(分步指南)
虽然 XML(可扩展标记语言)仍然存在,但 JSON 已成为当今大多数 Web 应用程序的首选格式。许多服务继续使用这种长期存在的格式来存储和共享结构化数据。
在应用程序中使用此格式时,通常需要进行 XML 处理。解析将原始 XML 转换为您的代码可以轻松使用的结构。JavaScript 提供了多种 XML 解析方法,包括内置浏览器 API、Node.js 解决方案和第三方库。
本指南旨在帮助您根据项目需求选择适合的工具。我们将介绍它们的优势、用例以及如何解决 JavaScript 项目中常见的 XML 解析挑战。
什么是 XML?
XML是一种标记语言,用于存储和共享结构化数据,并且它仍然在不同系统和平台之间的数据交换中被广泛应用。
XML 和 HTML 在结构上具有相似之处。两者都通过标签、属性和值来定义文档中的元素,进而创建出层次结构,不过它们的目的却有所不同。HTML 旨在在 Web 浏览器中显示数据,而 XML 用于在系统之间存储和传输数据。
XML 既是人类可读的,又易于机器解析。这使得它可用于在服务之间交换数据,尤其是在简单对象访问协议 (SOAP) 应用程序中。它还为 Maven 项目创建站点地图并编写配置文件,如 pom.xml。
XML 允许开发人员创建自定义标记,使其适用于许多数据结构。这种灵活性帮助 XML 在技术领域保持相关性。尽管 JSON 在 Web 应用程序中如今更为常见,但 XML 在软件开发的众多领域里依然占据着重要地位。
了解 XML 文件的结构
在我们详细介绍如何解析 XML 文件之前,让我们先了解 XML 文档的不同部分。
XML 文件通常包括以下元素:
- 根元素:XML 文档中的顶级元素。它用作导航 XML 结构的起点,该结构包含所有其他元素作为其子元素。
- 命名空间:XML 命名空间是元素和属性的唯一标识符,可防止在组合来自不同来源的 XML 或创建复杂文档时发生命名冲突。当相同的名称被用于多种不同目的时,它们(指命名空间)能够确保元素保持其独特性。命名空间通常表示为 URL,通过有关底层组织或标准的上下文和信息,增强跨系统的理解和互操作性。例如:
<book xmlns="http://example.com/books">
- 属性:提供有关元素的其他信息。它们在元素的 start 标记中指定,由名称-值对组成。
- 元素:XML 文档的主要构建块,表示所描述的数据或结构。它们表示 XML 文件中的结构化信息。元素可以嵌套在其他元素中以创建分层结构。
- 文本内容:指包含在元素的开始和结束标签中的文本数据,可以包括纯文本、数字或其他字符。
下面是一个 XML 文件的示例:
<?xml version="1.0" encoding="UTF-8"?>
<vehicles xmlns="http://example.com/vehicles">
<item>
<name>Cars</name>
<description>I love cars.</description>
<models>
<model>Range Rover</model>
<model>Corolla</model>
<model>BMW</model>
<model>Toyota</model>
<model>Tesla</model>
</models>
</item>
</vehicles>
这些元素按层次结构进行组织,使文档易于人类和计算机理解。
您可以使用如 JSONformatter(等工具来查看 XML 元素的树状结构。这一方法既适用于我们的示例,也适用于您所拥有的任何 XML 数据。以这种方式查看 XML 有助于您掌握元素的组织方式。
现在我们已经介绍了有关 XML 文件组件的基本信息,我们可以使用此信息来帮助解析具有各种库的 XML 文件。
在 JavaScript 中解析 XML
XML 解析是分析 XML 文档并提取所需数据的过程。
通常,XML 解析器执行以下关键步骤:
- 语法检查:解析器检查 XML 文档是否符合 XML 语法规则。如果发现任何语法错误,例如缺少结束标签或格式不正确的属性值,解析器将报告这些错误,并且可能无法继续处理文档。
- 分词:解析器将 XML 文档分解为单独的标记,例如开始标记、结束标记、属性名称和值以及文本内容。
- 构建文档结构:解析器构建 XML 文档的分层表示形式,通常采用树结构。通过这个结构,我们可以遍历整棵树,查询特定的元素或属性,并根据实际需求对数据进行相应的操作。
JavaScript XML 解析器
创建自定义 XML 解析通常具有挑战性,尤其是在实现自定义解决方案时。
XML 文件执行更严格的规则;例如,缺少没有引号的标签或属性可能会导致文件不可用。另外,由于XML文档具有自描述性质,因此很难将其拆分成能够并行解析的块。
除非您有充分的理由,否则,使用标准且经过充分测试的解析器库和API,以避免解析过程的复杂性,会是一个更为有效的选择。
与其他语言一样,JavaScript 提供了多个可用于解析 XML 文件的 API 和库。他们每个人都有其独特的权衡。
有些针对速度进行了优化,有些针对内存进行了优化;无论您选择使用哪种方式,在很大程度上取决于您的项目要求。
在本指南中,我们将介绍以下内容:
- DOMParser API
- xml2js
- 使用 Streams
- SAX 解析器
方法 1:使用DOMParser API
文档对象模型 (DOM) 将文档的结构表示为节点树,其中每个节点对应于标记中的元素、属性或值。
此树结构允许解析器以编程方式访问、操作和修改 XML 内容。
JavaScript 提供了DOMParser API,它提供了一种方法,可以将XML内容解析成XML文档,这些文档能够轻松地遍历和访问,以便进行后续的处理。
现在,让我们看看如何使用此 API 解析 XML。首先,创建一个本地开发环境,我们将使用它来处理代码示例,同时按照本指南进行操作。
为此,请在终端中运行以下命令以创建一个演示项目目录和两个文件:.index.
和一个 jstest.xml
mkdir parsing-xml
cd parsing-xml
# For Linux/Unix systems:
touch index.js test.xml
# For Windows:
_echo. > index.js_
echo. > test.xml
然后,在 XML 示例中的test.xml
粘贴中,我们查看了如下:
<?xml version="1.0" encoding="UTF-8"?>
<vehicles xmlns="http://example.com/vehicles">
<item>
<name>Cars</name>
<description>I love cars.</description>
<models>
<model>Range Rover</model>
<model>Corolla</model>
<model>BMW</model>
<model>Toyota</model>
<model>Tesla</model>
</models>
</item>
</vehicles>
要使用 DOMParser API 解析 XML 数据,需要注意几个要点。
DOMParser API 是现代浏览器中支持的本机 Web API。即便如此,在处理 XML 文件时,也不能使用 DOMParser API 实例方法直接解析它们,即 parseFromString()
— 该方法需要 XML 字符串作为输入,而不是文件路径或 URL。
换句话说,它不具备从文件系统中读取文件或向服务器发送请求以获取XML文件的功能。相反,它的设计初衷是处理那些在内存中已经可用的XML源代码字符串。
由于预期是您将处理需要在任何其他处理之前进行解析的大型 XML 文件,因此正确加载这些文件非常重要。为此,您需要:
- 使用 fetch API 或其他方法获取 XML 文件。
- 将获取的 XML 文件转换为字符串。
- 最后,将
parseFromString()
字符串传递给 DOMParser API 实例方法进行解析。
完成这些步骤后,您可以使用 DOM 方法访问解析的 XML。
让我们看一个代码可能是什么样子的示例。在index.js
文件中,粘贴以下代码:
async function loadXML() {
try {
const response = await fetch('test.xml');
const xmlString = await response.text();
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlString, 'text/xml');
const name = xmlDoc.querySelector('name').textContent;
console.log(name);
} catch (error) {
console.error('Error loading XML:', error);
}
}
loadXML()
现在,在同一个项目目录中,创建一个文件并添加以下代码:
<!DOCTYPE html>
<html>
<head>
<title>XML Parser</title>
</head>
<body>
<script src="index.js"></script>
</body>
</html>
此时,要显示解析后的名称,请在浏览器中打开index.html
文件,导航到开发人员工具中的浏览器控制台,并希望能查看输出。
这种方法在技术上是正确的。但是,由于我们使用 Fetch API 在您的本地环境中加载 XML 文件,因此它不会工作,并且浏览器很可能会引发错误。这是因为 Web 服务器尚未提供文件。
现代浏览器使用同源安全策略。这个策略会阻止网页向不同于为该页面提供服务的域的其它域发起请求。在使用 Fetch API 本地加载 XML 文件时,我们就会遇到这样的策略限制。这是一项安全措施,但它可能会阻碍当地发展。
当您直接从文件系统打开 HTML 文件时,浏览器会将其视为具有唯一的来源。使用 JavaScript 的 Fetch API 获取本地文件(包括 XML 文件)的任何尝试都将被同源策略阻止。浏览器可能会因为跨域请求(CORS)策略而引发阻止错误,或者出现其他与安全相关的类似错误。
为了克服这个限制,我们需要从 Web 服务器提供我们的文件。这种方法确保我们的所有文件(HTML、JavaScript 和 XML)都从同一源提供,从而满足同源策略要求。
有几种方法可以实现此目的:
- 使用本地开发服务器:可以使用 Node.js 和 Express 等工具来设置简单的本地服务器。
- 或者,在终端中运行以提供文件。
- 代码编辑器扩展(如 Live Server 扩展)可以使用最少的配置启动本地服务器。这将在您的代码编辑器中模拟相同的服务器端环境,作为提供文件的替代方案。
在本演示中,我们将在 Visual Studio Code 中使用 Live Server 扩展。这个扩展提供了一个快速且简便的方法,使我们能够在本地提供文件,而无需进行复杂的服务器设置。
要使用 Live Server:
- 打开 Visual Studio Code 并导航到 Extensions 选项卡。
- 在扩展市场中搜索 Live Server。
- 单击 Live Server 扩展的 Install 按钮。
- 安装后,您将在 VS Code 窗口底部的状态栏中看到一个 Go Live (上线) 按钮。
- 单击 Go Live 按钮启动本地服务器并在默认 Web 浏览器中自动打开 index.html 文件。
在本地服务器运行后,您的浏览器现在可以获取 XML 文件。
要打开浏览器的控制台,您需要访问浏览器的开发人员工具。为此,请右键单击,选择 检查,然后单击 控制台 选项卡。
在这里,您应该看到 XML 解析脚本的输出。
这种设置允许我们在浏览器中使用 DOMParser API 直接解析 XML 文件。此基本步骤为更复杂的 XML 处理任务奠定了基础。
上面的示例主要聚焦于在浏览器环境中解析XML内容。但值得注意的是,相同的过程在服务器端环境中同样适用——您依然可以使用相同的DOMParser API方法来解析XML数据。
这可以使用像 XMLDOM 这样的包来实现 — 它提供了一个 DOMParser 实现,允许您在 Node.js 服务器环境中解析 XML。
要使用 ,我们首先需要设置一个本地服务器端开发环境。为此,您需要首先安装 Node.js 和 Node 包管理器 npm。
首先,为此示例创建一个新的项目目录,或者您可以使用当前的工作目录。然后,通过在终端中运行以下命令来初始化新的 Node.js 项目:
npm init --y
接下来,安装 .xmldom
npm install @xmldom/xmldom
现在,在项目文件夹的根目录中,创建一个新文件。
# For Linux/Unix systems:
touch app.js
# For Windows:
_echo. > app.js_
然后,粘贴以下代码:
import fs from 'fs';
import { DOMParser } from '@xmldom/xmldom';
const xml = fs.readFileSync('test.xml', 'utf8');
const parser = new DOMParser();
const doc = parser.parseFromString(xml, 'application/xml');
console.log(doc.getElementsByTagName('name')[0].textContent);
在此示例中,我们执行两个主要操作:
- 使用 Node.js
fs
模块将整个 XML 文件 (test.xml
) 作为字符串同步读入内存。 - 创建
DOMParser
的实例并使用parseFromString
方法解析 XML 数据。
解析后,我们可以使用 DOM 遍历方法访问单个元素。在这种情况下,我们使用 getElementsByTagName
和 textContent
检索第一个元素的文本内容。
确保通过添加属性来更新文件,以便在文件中使用 ES6 语法。
您可以在终端上运行此命令来测试此最小设置。
node app.js
输出将是 XML 文件中第一个元素的文本内容,即:.Cars
方法 2:使用 XML2JS
xml2js 库是用于解析 XML 数据的常用 Node.js 包。与DOMParser(它提供XML的DOM表示)不同,这个方法更侧重于将XML转换为一种更便于在JavaScript应用程序中使用的格式。
对于您希望快速访问API或其他服务中的数据,而又不想处理通过操作DOM来访问所需数据的复杂性的场景,它特别有用。
实质上,xml2js
允许您将 XML 直接解析为 JSON 格式。由于 JSON 是应用程序中使用的一种常见格式,因此您的使用者(API、客户端等)可以轻松摄取和使用解析后的数据。
要使用 ,首先,安装软件包:xml2js
npm install xml2js
安装后,要解析 XML 文件,请首先使用fs
模块读取文件,然后使用xml2js
将 XML 字符串转换为 JavaScript 对象。
下面是如何执行此操作的示例:
import fs from 'fs';
import { parseString } from 'xml2js';
const xml = fs.readFileSync('test.xml', 'utf8');
parseString(xml, (err, result) => {
if (err) {
console.error('Error parsing XML:', err);
return;
}
console.log(result);
});
在此代码片段中,我们读取 test.xml
字符串的内容,然后使用该parseString
函数将 XML 字符串转换为 JavaScript 对象(JSON 对象)。
当您运行此代码时,您将获得如下输出:
{
vehicles: { '$': { xmlns: '[http://example.com/vehicles](http://example.com/vehicles)' }, item: [ [Object] ] }
}
这并不完全是错误,您不用担心!这种输出的原因是parseString
方法遵循了Node.js的默认行为,即在记录大型或嵌套的对象时,通常会限制检查的深度,因此导致了这样的输出(这一行为在GitHub存储库中有明确的说明)。
要查看已解析的 XML 的完整结构,可以使用util.inspect
方法。现在,您可以获得 JSON 对象的更详细结构。
继续导入util
模块,将result
对象包装在util.inspect
方法中,然后将其记录在终端中。
import util from 'util';
console.log(util.inspect(result, { depth: null, colors: true }));
这将为您提供已解析的 XML 对象的详细视图,包括所有嵌套属性。
假设您希望从此解析的对象中访问各个项目。为此,您可以遍历每个嵌套项并记录每个嵌套项,如下所示:
const items = result.vehicles.item;
items.forEach(item => {
console.log('Name:', item.name[0]);
console.log('Description:', item.description[0]);
console.log('Models:', item.models[0].model[0]);
});
XMLDOM 与 XML2JS:有什么区别?
现在,我们已经了解了两个很棒的解析库,xmldom
和 xml2js
,尽管如此,在解析过程中使用这两者时,有一些重要的权衡值得考虑。
对于初学者来说,xmldom提供了XML的DOM表示作为输出。要访问和操作这些数据,您需要利用标准的DOM方法来遍历DOM树。
相反,xml2js
将 XML 直接转换为 JavaScript 对象。这简化了数据访问和操作。这种方法更直观,允许与数据直接交互,而无需导航 DOM 树。
性能在所有软件进程中都很重要,包括 XML 解析。对于大型 XML 文档,将其解析为 DOM 可能会消耗大量资源。特别是当 XML 深度嵌套时,管理完整的 DOM 结构可能会显著降低处理速度。
相比之下,xml2js在解析和访问数据时通常更加迅速,原因在于它直接将XML转换为JavaScript对象,避免了产生DOM表示所带来的额外开销。这可以在主要读取 XML 数据的应用程序中获得更好的性能。
方法 3:使用 Stream 模块解析大型 XML 文件
在处理大型 XML 文件时,将整个文档加载到内存中可能效率低下,并导致性能瓶颈。要有效地处理大型 XML 文件,您可以使用Stream
模块以块的形式处理 XML 数据,而不是一次加载所有数据。
该模块是一个内置的 Node.js 模块,它提供了一种处理流数据的方法。它使得您可以按较小的数据块进行读取或写入操作,这在处理大型文件或数据流时显得尤为有用。
要测试 Stream 模块,请继续创建一个新文件并包含large.xml
内容。理想情况下,它不是一个大型 XML 文件,但对于此演示,我们将使用它:
<?xml version="1.0" encoding="UTF-8"?>
<vehicles xmlns="http://example.com/vehicles">
<vehicle type="http://example.com/car">
<name>Cars</name>
<description>I love cars.</description>
<models>
<model>Range Rover</model>
<model>Corolla</model>
<model>BMW</model>
<model>Toyota</model>
<model>Tesla</model>
</models>
</vehicle>
<vehicle type="http://example.com/motorcycle">
<name>Motorcycles</name>
<description>I also enjoy riding motorcycles.</description>
<models>
<model>Harley-Davidson</model>
<model>Honda</model>
<model>Yamaha</model>
<model>Ducati</model>
<model>Triumph</model>
</models>
</vehicle>
<vehicle type="http://example.com/minivan">
<name>Minivans</name>
<description>Minivans .</description>
<models>
<model>Honda Odyssey</model>
<model>Toyota Sienna</model>
<model>Chrysler Pacifica</model>
<model>Kia Carnival</model>
<model>Dodge Grand Caravan</model>
</models>
</vehicle>
</vehicles>
接下来,创建一个在同一目录中调用的新文件test-stream.js
。将以下代码复制并粘贴到该文件中。
此外,由于xml2js
在处理大型 XML 数据方面做得很好,我们可以轻松地将两者结合起来,如下所示:
import fs from 'fs';
import { Parser } from 'xml2js';
import util from 'util';
const parser = new Parser();
const readStream = fs.createReadStream('large.xml', 'utf8');
readStream.on('data', (chunk) => {
parser.parseString(chunk, (err, result) => {
if (err) {
console.error('Error parsing XML:', err);
return;
}
console.log('Parsed data:', util.inspect(result, { depth: null, colors: true }));
});
});
readStream.on('end', () => {
console.log('process completed');
});
readStream.on('error', (err) => {
console.error('Error:', err);
});
在此示例中,我们从库中导入fs
模块和parseString
函数。我们创建一个新实例,该parseString.Parser
实例将用于解析 XML 数据。
接下来,我们使用 fs.createReadStream
来创建一个读取流,并传递文件路径(例如 'large.xml'
)和编码(例如 'utf8'
)。这个读取流将会以块的形式来读取文件。
在读取流(readStream
)上监听'data'
事件以接收新的数据块,并使用某个解析器(可能是xml2js
或类似的库中的parseString
方法)来解析这些数据块。
使用 command 启动节点服务器,在node test-stream.js
终端中查看结果。
此实现能够无需一次性将整个大型 XML 文件加载到内存中,而是通过读取、处理和解析较小的数据块来有效地处理该示例文件。
对于生产应用程序,XML 文件可能比我们的示例大得多。这些数据块通常需要在被使用前进行适当的处理。如果不加以注意,它们可能会给您的应用程序带来沉重的负担,从而导致整体性能下降。有效地处理大型 XML 文件对于保持系统平稳运行非常重要。
使用流读取和解析数据有助于避免这些问题。您还可以使用 Sax.js 等包,它将 XML 作为流进行处理。这些方法可让您更高效地处理大型 XML 文件,从而保持应用程序的响应速度。
写入 XML 文件
让我们换个方向,探讨一下如何从零开始创建一个XML文件,这涉及将数据写入XML文件中。整个流程首先是构建出XML的结构,接着再将其序列化为具体的文件。
您可以使用一些库来实现此目的,包括 xml2js
和 xmldom
用于更复杂的 XML 生成。
让我们看一个使用 xml2jsBuilder
,此库提供了一个类,可以轻松地将 JavaScript 对象转换为 XML。
在此示例中,创建一个名为 write-xml.js
的新文件。我们将使用此文件来写入 XML 数据。
首先,从 fs
中导入Builder
模块和xml2js
类。
import fs from 'fs';
import { Builder } from 'xml2js';
接下来,创建一个 JavaScript 对象,该对象表示要创建的 XML 结构。此对象应具有与我们要生成的 XML 文件相同的结构。
const obj = {
vehicles: {
item: [
{
$: { name: 'Car' },
carDetails: 'Details about the car'
},
{
$: { name: 'Bike' },
bikeDetails: 'Details about the bike'
}
]
}
};
现在,使用实例将 JavaScript 对象转换为 XML 字符串,如下所示:Builder
const builder = new Builder();
const xml = builder.buildObject(obj);
最后,使用 :fs.writeFileSync
fs.writeFileSync('output.xml', xml, 'utf8');
console.log('XML file written.');
没错!这就是利用xml2js库从头开始创建XML文件的方式。虽然这只是一个简单的例子,但它着重展示了将数据写入XML文件的基本流程。
在 JavaScript 中解析 XML 的常见问题和解决方案
有许多工具可用于解析 XML。无论您使用的是小文件还是大文件,都要记住以下几个关键点,以及 XML 解析的一些常见问题以及如何修复它们:
- 选择合适的库:第一步是为您的项目选择合适的 XML 解析工具。不同的库可以说有优点和缺点,其中一些是重叠的。请务必考虑重要的权衡和目标解析要求。
- 处理命名空间:XML命名空间通过为元素提供唯一标识来增加XML的复杂性。在解析带有命名空间的XML时,应选择那些支持命名空间的库,并根据XML的架构来验证其结构。这些步骤可以防止错误并确保正确的数据处理。在线工具可以帮助进行架构验证,从而提高应用程序的 XML 处理能力。
- 解析不明确或不完整的 XML:这通常是由于缺少元素或属性,或者 XML 结构不正确而发生的。将错误处理工具(如 try-catch 块或错误回调)添加到您的代码中以处理这些问题。这些工具可以捕获和管理意外的 XML 数据,这有助于防止您的应用崩溃。
- 大文件的性能问题:当文件太大而无法放入内存,或者解析过程花费的时间太长时,可能会发生这种情况。为了解决这个问题,可以采用流式处理方法。这种方法能够让您以数据块的形式来解析XML数据,而不是一次性地将整个文件加载到内存中。
结论
XML 解析有许多实际用途。您可能会使用 JavaScript 和 Node.js 来进行网页抓取,或者处理更复杂的应用程序中的 XML 数据。您在这里掌握的技能,将会成为您在未来JavaScript项目中处理结构化数据时坚实的基石。