@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

参数类型说明
baseXMLstring基准 XML 字符串(视为原始一侧)。
contrastXMLstring与基准对比的 XML 字符串。
optionsXMLCompareOptions可选的对比行为设置。

parseXML

function parseXML(xml: string): unknown;

使用 fast-xml-parser 将 XML 字符串解析为 JavaScript 对象。属性名带 @ 前缀。

validateXML

function validateXML(xml: string): void;

校验字符串是否为格式良好的 XML。当 XML 为空、仅包含空白字符或格式错误时抛出 XMLValidationError,错误在可用时包含 linecol 属性。

pathSegmentsToString

function pathSegmentsToString(pathSegments: string[]): string;

将路径片段数组(即 XMLValueDifference.pathSegments)转换为可读的点表示法字符串。数组索引片段(如 '[0]')不带前导点直接拼接;元素名用 . 连接。

pathSegmentsToString([]);                     // ''
pathSegmentsToString(['user', 'name']);       // 'user.name'
pathSegmentsToString(['items', '[2]', 'id']); // 'items[2].id'

XMLCompareOptions

选项类型默认值说明
arrayCompareMethodXMLArrayCompareMethod'byIndex'数组的对比策略。
keyCaseInsensitivebooleanfalsetrue 时,元素/属性名按大小写不敏感方式对比。
valueCaseInsensitivebooleanfalsetrue 时,文本值按大小写不敏感方式对比。

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

字段类型说明
pathSegmentsstring[]差异值的路径片段。元素名原样出现;数组索引以 '[n]' 形式出现(如 ['users', '[0]', 'name'])。
pathStringstring同一路径的点表示法字符串,数组索引保留为方括号后缀(如 'users[0].name')。
pathBelongsTo'base' | 'contrast' | 'both'路径所属一侧。deleted'base'added'contrast'valueChanged'both'
diffTypeXMLValueDiffType该路径检测到的差异类型。

XMLValidationError

class XMLValidationError extends Error {
  line?: number;
  col?: number;
}

当 XML 解析失败时由 validateXMLcompareXML 抛出。当底层解析器提供位置信息时,可读取 linecol 属性。

许可证

MIT