or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

comparison.mdindex.mdinput.mdtransform.mdvalidation.mdxpath.md

comparison.mddocs/

0

# XML Document Comparison

1

2

Comprehensive XML comparison functionality for detecting structural differences, content variations, and attribute changes between XML documents. XMLUnit provides flexible comparison strategies with customizable difference evaluation and detailed reporting.

3

4

## Capabilities

5

6

### DiffBuilder

7

8

The main entry point for XML comparison operations, providing a fluent API for configuring and executing comparisons.

9

10

```java { .api }

11

/**

12

* Creates a new DiffBuilder to compare XML documents

13

* @param control - The control (expected) XML document as any supported input type

14

* @returns DiffBuilder instance for configuration

15

*/

16

public static DiffBuilder compare(Object control);

17

18

public class DiffBuilder implements DifferenceEngineConfigurer<DiffBuilder> {

19

/** Set the test (actual) document to compare against control */

20

public DiffBuilder withTest(Object test);

21

22

/** Ignore whitespace-only text nodes */

23

public DiffBuilder ignoreWhitespace();

24

25

/** Normalize whitespace in text content */

26

public DiffBuilder normalizeWhitespace();

27

28

/** Ignore whitespace between elements */

29

public DiffBuilder ignoreElementContentWhitespace();

30

31

/** Ignore XML comments during comparison */

32

public DiffBuilder ignoreComments();

33

34

/** Ignore XML comments using specific XSLT version */

35

public DiffBuilder ignoreCommentsUsingXSLTVersion(String xsltVersion);

36

37

/** Check for similarity rather than identical match */

38

public DiffBuilder checkForSimilar();

39

40

/** Check for identical match (default) */

41

public DiffBuilder checkForIdentical();

42

43

/** Configure custom DocumentBuilderFactory */

44

public DiffBuilder withDocumentBuilderFactory(DocumentBuilderFactory f);

45

46

/** Build the final Diff instance */

47

public Diff build();

48

}

49

```

50

51

**Usage Examples:**

52

53

```java

54

import org.xmlunit.builder.Input;

55

import org.xmlunit.builder.DiffBuilder;

56

import org.xmlunit.diff.Diff;

57

58

// Basic XML comparison

59

Source control = Input.fromString("<users><user id='1'>John</user></users>").build();

60

Source test = Input.fromString("<users><user id='1'>Jane</user></users>").build();

61

62

Diff diff = DiffBuilder.compare(control)

63

.withTest(test)

64

.build();

65

66

if (diff.hasDifferences()) {

67

System.out.println("Documents differ: " + diff.toString());

68

}

69

70

// Ignore whitespace differences

71

Diff lenientDiff = DiffBuilder.compare(control)

72

.withTest(test)

73

.ignoreWhitespace()

74

.normalizeWhitespace()

75

.ignoreComments()

76

.build();

77

78

// Check for similarity instead of identical

79

Diff similarityDiff = DiffBuilder.compare(control)

80

.withTest(test)

81

.checkForSimilar()

82

.build();

83

```

84

85

### Advanced Configuration

86

87

DiffBuilder extends `DifferenceEngineConfigurer` providing advanced customization options.

88

89

```java { .api }

90

public interface DifferenceEngineConfigurer<D> {

91

/** Configure custom node matching strategy */

92

D withNodeMatcher(NodeMatcher nodeMatcher);

93

94

/** Configure custom difference evaluation */

95

D withDifferenceEvaluator(DifferenceEvaluator differenceEvaluator);

96

97

/** Configure comparison control flow */

98

D withComparisonController(ComparisonController comparisonController);

99

100

/** Add comparison event listeners */

101

D withComparisonListeners(ComparisonListener... listeners);

102

103

/** Add difference event listeners */

104

D withDifferenceListeners(ComparisonListener... listeners);

105

106

/** Configure namespace prefixes for XPath */

107

D withNamespaceContext(Map<String, String> prefix2Uri);

108

109

/** Filter attributes during comparison */

110

D withAttributeFilter(Predicate<Attr> attributeFilter);

111

112

/** Filter nodes during comparison */

113

D withNodeFilter(Predicate<Node> nodeFilter);

114

115

/** Configure comparison output formatting */

116

D withComparisonFormatter(ComparisonFormatter formatter);

117

}

118

```

119

120

**Usage Examples:**

121

122

```java

123

import org.xmlunit.diff.*;

124

125

// Custom difference evaluation

126

DifferenceEvaluator customEvaluator = new DifferenceEvaluator() {

127

@Override

128

public ComparisonResult evaluate(Comparison comparison, ComparisonResult outcome) {

129

// Treat attribute order differences as similar, not different

130

if (comparison.getType() == ComparisonType.ATTR_SEQUENCE) {

131

return ComparisonResult.SIMILAR;

132

}

133

return outcome;

134

}

135

};

136

137

Diff customDiff = DiffBuilder.compare(control)

138

.withTest(test)

139

.withDifferenceEvaluator(customEvaluator)

140

.build();

141

142

// Custom node matching

143

NodeMatcher elementMatcher = new DefaultNodeMatcher(

144

ElementSelectors.byNameAndText,

145

ElementSelectors.byName

146

);

147

148

Diff matchedDiff = DiffBuilder.compare(control)

149

.withTest(test)

150

.withNodeMatcher(elementMatcher)

151

.build();

152

153

// Namespace context for XPath evaluation

154

Map<String, String> namespaces = new HashMap<>();

155

namespaces.put("ns", "http://example.com/namespace");

156

157

Diff namespaceAwareDiff = DiffBuilder.compare(control)

158

.withTest(test)

159

.withNamespaceContext(namespaces)

160

.build();

161

```

162

163

### Diff Results

164

165

The result of a comparison operation containing all detected differences.

166

167

```java { .api }

168

public class Diff {

169

/** Check if any differences were found */

170

public boolean hasDifferences();

171

172

/** Get all differences found during comparison */

173

public Iterable<Difference> getDifferences();

174

175

/** Get the control (expected) XML source */

176

public Source getControlSource();

177

178

/** Get the test (actual) XML source */

179

public Source getTestSource();

180

181

/** Get complete description of all differences */

182

public String fullDescription();

183

184

/** Get complete description using custom formatter */

185

public String fullDescription(ComparisonFormatter formatter);

186

187

/** String representation of first difference */

188

@Override

189

public String toString();

190

191

/** String representation using custom formatter */

192

public String toString(ComparisonFormatter formatter);

193

}

194

```

195

196

### Individual Differences

197

198

Detailed information about specific differences found during comparison.

199

200

```java { .api }

201

public class Difference {

202

/** Get the comparison that was performed */

203

public Comparison getComparison();

204

205

/** Get the result of the comparison */

206

public ComparisonResult getResult();

207

}

208

209

public class Comparison {

210

/** Get the type of comparison performed */

211

public ComparisonType getType();

212

213

/** Get details of the control (expected) side */

214

public Detail getControlDetails();

215

216

/** Get details of the test (actual) side */

217

public Detail getTestDetails();

218

219

/** Formatted string representation */

220

public String toString(ComparisonFormatter formatter);

221

}

222

223

public static class Detail {

224

/** Get the target node being compared */

225

public Node getTarget();

226

227

/** Get XPath to the target node */

228

public String getXPath();

229

230

/** Get the value being compared */

231

public Object getValue();

232

233

/** Get XPath to the parent node */

234

public String getParentXPath();

235

}

236

```

237

238

### Comparison Types and Results

239

240

Enumerations defining what is being compared and the outcome.

241

242

```java { .api }

243

public enum ComparisonType {

244

ATTR_NAME_LOOKUP, ATTR_VALUE, CHILD_LOOKUP, CHILD_NODELIST_LENGTH,

245

CHILD_NODELIST_SEQUENCE, ELEMENT_NAME, ELEMENT_TAG_NAME, HAS_DOCTYPE_DECLARATION,

246

NAMESPACE_PREFIX, NAMESPACE_URI, NODE_TYPE, NO_NAMESPACE_SCHEMA_LOCATION,

247

PROCESSING_INSTRUCTION_DATA, PROCESSING_INSTRUCTION_TARGET, SCHEMA_LOCATION,

248

TEXT_VALUE, XML_VERSION, XML_STANDALONE, XML_ENCODING, DOCTYPE_NAME,

249

DOCTYPE_PUBLIC_ID, DOCTYPE_SYSTEM_ID, COMMENT_VALUE, CDATA_VALUE

250

}

251

252

public enum ComparisonResult {

253

/** Content is identical */

254

EQUAL,

255

256

/** Content is similar but not identical */

257

SIMILAR,

258

259

/** Content is completely different */

260

DIFFERENT

261

}

262

```

263

264

### Node Matching Strategies

265

266

Configure how control and test nodes are matched during comparison.

267

268

```java { .api }

269

public interface NodeMatcher {

270

/** Match child nodes between control and test parents */

271

Iterable<Map.Entry<Node, Node>> match(Iterable<Node> controlNodes,

272

Iterable<Node> testNodes);

273

}

274

275

public class DefaultNodeMatcher implements NodeMatcher {

276

/** Create matcher with element selector strategies */

277

public DefaultNodeMatcher(ElementSelector... selectors);

278

}

279

280

// Built-in element selectors

281

public class ElementSelectors {

282

public static final ElementSelector byName;

283

public static final ElementSelector byNameAndText;

284

public static final ElementSelector byNameAndAllAttributes;

285

public static final ElementSelector byNameAndAttributes(String... attributeNames);

286

287

/** Chain multiple selectors with fallback behavior */

288

public static ElementSelector conditionalBuilder()

289

.whenElementIsNamed(String expectedName)

290

.thenUse(ElementSelector selector)

291

.elseUse(ElementSelector selector)

292

.build();

293

}

294

```

295

296

### Difference Evaluation

297

298

Customize how comparison results are interpreted and handled.

299

300

```java { .api }

301

public interface DifferenceEvaluator {

302

/** Evaluate a comparison and potentially change its result */

303

ComparisonResult evaluate(Comparison comparison, ComparisonResult outcome);

304

}

305

306

// Built-in evaluators

307

public class DifferenceEvaluators {

308

/** Default evaluator that accepts all results as-is */

309

public static final DifferenceEvaluator Default;

310

311

/** Ignore specific comparison types */

312

public static DifferenceEvaluator ignorePaths(String... xPaths);

313

314

/** Chain multiple evaluators */

315

public static DifferenceEvaluator chain(DifferenceEvaluator... evaluators);

316

317

/** Upgrade SIMILAR results to EQUAL */

318

public static final DifferenceEvaluator upgradeDifferencesToEqual;

319

320

/** Downgrade DIFFERENT results to SIMILAR */

321

public static final DifferenceEvaluator downgradeDifferencesToSimilar;

322

}

323

```

324

325

**Usage Examples:**

326

327

```java

328

// Ignore attribute order differences

329

DifferenceEvaluator ignoreAttrSequence = (comparison, outcome) -> {

330

if (comparison.getType() == ComparisonType.ATTR_SEQUENCE) {

331

return ComparisonResult.SIMILAR;

332

}

333

return outcome;

334

};

335

336

// Chain multiple evaluators

337

DifferenceEvaluator chained = DifferenceEvaluators.chain(

338

ignoreAttrSequence,

339

DifferenceEvaluators.ignorePaths("/users/user/@created"),

340

DifferenceEvaluators.downgradeDifferencesToSimilar

341

);

342

343

Diff customEvaluatedDiff = DiffBuilder.compare(control)

344

.withTest(test)

345

.withDifferenceEvaluator(chained)

346

.build();

347

```

348

349

### Comparison Formatting

350

351

Customize how comparison results are displayed and reported.

352

353

```java { .api }

354

public interface ComparisonFormatter {

355

/** Format comparison details for display */

356

String getDescription(Comparison difference);

357

358

/** Get short summary of comparison */

359

String getDetails(Detail details, ComparisonType type, boolean formatting);

360

}

361

362

public class DefaultComparisonFormatter implements ComparisonFormatter {

363

/** Default formatting implementation */

364

}

365

```

366

367

### Low-Level Difference Engine

368

369

Direct access to the comparison engine for advanced use cases.

370

371

```java { .api }

372

public interface DifferenceEngine {

373

/** Add listener for comparison events */

374

void addDifferenceListener(ComparisonListener listener);

375

376

/** Add listener that can control comparison flow */

377

void addComparisonController(ComparisonController controller);

378

379

/** Add listener for completed comparisons */

380

void addMatchListener(ComparisonListener listener);

381

382

/** Perform comparison between control and test sources */

383

void compare(Source control, Source test);

384

}

385

386

public class DOMDifferenceEngine extends AbstractDifferenceEngine {

387

/** DOM-based difference engine implementation */

388

}

389

390

public interface ComparisonListener {

391

/** Called for each comparison performed */

392

void comparisonPerformed(Comparison comparison, ComparisonResult outcome);

393

}

394

395

public interface ComparisonController extends ComparisonListener {

396

/** Control whether comparison should continue */

397

boolean stopDiffing(Comparison comparison);

398

}

399

```

400

401

**Usage Examples:**

402

403

```java

404

// Direct engine usage with listeners

405

DOMDifferenceEngine engine = new DOMDifferenceEngine();

406

407

engine.addDifferenceListener((comparison, outcome) -> {

408

if (outcome == ComparisonResult.DIFFERENT) {

409

System.out.println("Found difference: " + comparison);

410

}

411

});

412

413

engine.addComparisonController(new ComparisonController() {

414

private int differenceCount = 0;

415

416

@Override

417

public void comparisonPerformed(Comparison comparison, ComparisonResult outcome) {

418

if (outcome != ComparisonResult.EQUAL) {

419

differenceCount++;

420

}

421

}

422

423

@Override

424

public boolean stopDiffing(Comparison comparison) {

425

// Stop after finding 10 differences

426

return differenceCount >= 10;

427

}

428

});

429

430

engine.compare(controlSource, testSource);

431

```