@compare-xml/core(JavaScript)
@compare-xml/core 是一个轻量的 JavaScript/TypeScript 库,用于深度对比 XML 文档——也是本网站使用的对比引擎。它使用 fast-xml-parser 解析 XML,可以检测两个 XML 结构之间的新增、删除和值变更,并支持细粒度的对比行为控制。
语言:JavaScript/TypeScript —— 通过 npm 分发。其它语言的实现可能会陆续推出。
安装
# npm
npm install @compare-xml/core
# yarn
yarn add @compare-xml/core
# pnpm
pnpm add @compare-xml/core
快速开始
import { compareXML } from '@compare-xml/core';
const baseXML = '<user><name>Alice</name><age>30</age><hobbies><item>reading</item></hobbies></user>';
const contrastXML = '<user><name>Bob</name><age>30</age><hobbies><item>reading</item><item>coding</item></hobbies><email>[email protected]</email></user>';
const differences = compareXML({ baseXML, contrastXML });
console.log(differences);
// [
// { pathSegments: ['user', 'name'], pathString: 'user.name', pathBelongsTo: 'both', diffType: 'valueChanged' },
// { pathSegments: ['user', 'hobbies', 'item', '[1]'], pathString: 'user.hobbies.item[1]', pathBelongsTo: 'contrast', diffType: 'added' },
// { pathSegments: ['user', 'email'], pathString: 'user.email', pathBelongsTo: 'contrast', diffType: 'added' },
// ]
对比选项
import { compareXML } from '@compare-xml/core';
// 键名(元素/属性名)大小写不敏感
compareXML({
baseXML: '<root><Name>Alice</Name></root>',
contrastXML: '<root><name>Alice</name></root>',
options: { keyCaseInsensitive: true },
});
// [](无差异)
// 值大小写不敏感
compareXML({
baseXML: '<root><status>OK</status></root>',
contrastXML: '<root><status>ok</status></root>',
options: { valueCaseInsensitive: true },
});
// [](无差异)
各选项的详细说明请参阅对比选项。
数组对比方法
重复的子元素(如多个 <item> 节点)会作为数组进行对比:
import { compareXML } from '@compare-xml/core';
// 'byIndex'(默认)—— 按相同索引逐一对比
compareXML({
baseXML: '<root><items><item>1</item><item>2</item><item>3</item></items></root>',
contrastXML: '<root><items><item>2</item><item>3</item><item>4</item></items></root>',
});
// 'lcs' —— 使用最长公共子序列算法,得到最小差异
compareXML({
baseXML: '<root><items><item>1</item><item>2</item><item>3</item></items></root>',
contrastXML: '<root><items><item>2</item><item>3</item><item>4</item></items></root>',
options: { arrayCompareMethod: 'lcs' },
});
// 'unordered' —— 将数组视为多重集合,忽略元素顺序
compareXML({
baseXML: '<root><items><item>1</item><item>2</item><item>3</item></items></root>',
contrastXML: '<root><items><item>3</item><item>2</item><item>1</item></items></root>',
options: { arrayCompareMethod: 'unordered' },
});
// [](无差异)
每种策略的深入讲解请参阅数组对比方法。
格式化路径
import { pathSegmentsToString } from '@compare-xml/core';
pathSegmentsToString(['users', '[0]', 'name']);
// 'users[0].name'
API 参考
compareXML
function compareXML(params: {
baseXML: string;
contrastXML: string;
options?: XMLCompareOptions;
}): XMLValueDifference[];
解析两个 XML 字符串并深度对比其结构,返回差异数组。两个文档相等时返回空数组。任一输入不是格式良好的 XML 时抛出 XMLValidationError。
| 参数 | 类型 | 说明 |
|---|---|---|
baseXML | string | 基准 XML 字符串(视为原始一侧)。 |
contrastXML | string | 与基准对比的 XML 字符串。 |
options | XMLCompareOptions | 可选的对比行为设置。 |
parseXML
function parseXML(xml: string): unknown;
使用 fast-xml-parser 将 XML 字符串解析为 JavaScript 对象。属性名带 @ 前缀。
validateXML
function validateXML(xml: string): void;
校验字符串是否为格式良好的 XML。当 XML 为空、仅包含空白字符或格式错误时抛出 XMLValidationError,错误在可用时包含 line 和 col 属性。
pathSegmentsToString
function pathSegmentsToString(pathSegments: string[]): string;
将路径片段数组(即 XMLValueDifference.pathSegments)转换为可读的点表示法字符串。数组索引片段(如 '[0]')不带前导点直接拼接;元素名用 . 连接。
pathSegmentsToString([]); // ''
pathSegmentsToString(['user', 'name']); // 'user.name'
pathSegmentsToString(['items', '[2]', 'id']); // 'items[2].id'
XMLCompareOptions
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
arrayCompareMethod | XMLArrayCompareMethod | 'byIndex' | 数组的对比策略。 |
keyCaseInsensitive | boolean | false | 为 true 时,元素/属性名按大小写不敏感方式对比。 |
valueCaseInsensitive | boolean | false | 为 true 时,文本值按大小写不敏感方式对比。 |
XMLArrayCompareMethod
type XMLArrayCompareMethod = 'byIndex' | 'lcs' | 'unordered';
| 值 | 说明 |
|---|---|
'byIndex' | 按相同索引逐一对比数组元素,多余的尾部元素报告为 added/deleted。 |
'lcs' | 使用最长公共子序列算法,为有序数组检测最小差异。 |
'unordered' | 将数组视为多重集合,无论位置匹配相等元素。 |
XMLValueDiffType
type XMLValueDiffType = 'added' | 'deleted' | 'valueChanged';
| 值 | 说明 |
|---|---|
'added' | 元素/属性存在于 contrastXML 但不存在于 baseXML。 |
'deleted' | 元素/属性存在于 baseXML 但不存在于 contrastXML。 |
'valueChanged' | 基准与对比值之间值发生变化。 |
XMLValueDifference
| 字段 | 类型 | 说明 |
|---|---|---|
pathSegments | string[] | 差异值的路径片段。元素名原样出现;数组索引以 '[n]' 形式出现(如 ['users', '[0]', 'name'])。 |
pathString | string | 同一路径的点表示法字符串,数组索引保留为方括号后缀(如 'users[0].name')。 |
pathBelongsTo | 'base' | 'contrast' | 'both' | 路径所属一侧。deleted 为 'base',added 为 'contrast',valueChanged 为 'both'。 |
diffType | XMLValueDiffType | 该路径检测到的差异类型。 |
XMLValidationError
class XMLValidationError extends Error {
line?: number;
col?: number;
}
当 XML 解析失败时由 validateXML 和 compareXML 抛出。当底层解析器提供位置信息时,可读取 line 和 col 属性。
许可证
MIT