or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdcore-api.mddocument-creation.mdindex.mdio-operations.mdxpath.md

advanced-features.mddocs/

0

# DOM4J Advanced Features

1

2

This section covers DOM4J's advanced capabilities including JAXB integration, JavaBean binding, XML Schema datatype support, DTD processing, rule-based processing, Swing integration, and other specialized features for enterprise XML processing scenarios.

3

4

## JAXB Integration

5

6

DOM4J provides comprehensive integration with JAXB (Java Architecture for XML Binding) for object-to-XML mapping and vice versa.

7

8

### Package and Import

9

```java { .api }

10

import org.dom4j.jaxb.JAXBReader;

11

import org.dom4j.jaxb.JAXBWriter;

12

import org.dom4j.jaxb.JAXBSupport;

13

import org.dom4j.jaxb.JAXBObjectHandler;

14

import org.dom4j.jaxb.JAXBModifier;

15

import org.dom4j.jaxb.JAXBRuntimeException;

16

import javax.xml.bind.JAXBContext;

17

import javax.xml.bind.Unmarshaller;

18

import javax.xml.bind.Marshaller;

19

```

20

21

### JAXBReader - XML to Object Binding

22

```java { .api }

23

public class JAXBReader extends SAXReader {

24

// Constructors

25

public JAXBReader(String contextPath);

26

public JAXBReader(String contextPath, ClassLoader classLoader);

27

public JAXBReader(JAXBContext jaxbContext);

28

29

// Object handling

30

public void setObjectHandler(JAXBObjectHandler objectHandler);

31

public JAXBObjectHandler getObjectHandler();

32

33

// JAXB context

34

public JAXBContext getJAXBContext();

35

public Unmarshaller getUnmarshaller() throws JAXBException;

36

}

37

```

38

39

### Using JAXBReader

40

```java { .api }

41

// Define JAXB classes

42

@XmlRootElement(name = "book")

43

@XmlAccessorType(XmlAccessType.FIELD)

44

public class Book {

45

@XmlAttribute

46

private String isbn;

47

48

@XmlElement

49

private String title;

50

51

@XmlElement

52

private String author;

53

54

@XmlElement

55

private BigDecimal price;

56

57

// Constructors, getters, setters...

58

}

59

60

@XmlRootElement(name = "catalog")

61

@XmlAccessorType(XmlAccessType.FIELD)

62

public class Catalog {

63

@XmlElement(name = "book")

64

private List<Book> books = new ArrayList<>();

65

66

// Constructors, getters, setters...

67

}

68

69

// Create JAXBReader

70

JAXBContext jaxbContext = JAXBContext.newInstance(Catalog.class, Book.class);

71

JAXBReader reader = new JAXBReader(jaxbContext);

72

73

// Object handler to process unmarshalled objects

74

reader.setObjectHandler(new JAXBObjectHandler() {

75

@Override

76

public void handleObject(Object object) throws Exception {

77

if (object instanceof Book) {

78

Book book = (Book) object;

79

System.out.println("Processed book: " + book.getTitle());

80

// Process book object

81

} else if (object instanceof Catalog) {

82

Catalog catalog = (Catalog) object;

83

System.out.println("Processed catalog with " + catalog.getBooks().size() + " books");

84

}

85

}

86

});

87

88

// Read and process XML

89

Document document = reader.read("catalog.xml");

90

// Objects are automatically unmarshalled and processed through handler

91

92

// Access unmarshalled objects from document

93

Catalog catalog = (Catalog) document.getRootElement().getData();

94

```

95

96

### JAXBWriter - Object to XML Binding

97

```java { .api }

98

public class JAXBWriter extends XMLWriter {

99

// Constructors

100

public JAXBWriter(String contextPath);

101

public JAXBWriter(String contextPath, ClassLoader classLoader);

102

public JAXBWriter(JAXBContext jaxbContext);

103

public JAXBWriter(String contextPath, Writer writer);

104

public JAXBWriter(JAXBContext jaxbContext, Writer writer, OutputFormat format);

105

106

// Object writing

107

public void writeObject(Object object) throws IOException, JAXBException;

108

public void writeCloseObject(Object object) throws IOException;

109

public void writeOpenObject(Object object) throws IOException;

110

111

// JAXB context

112

public JAXBContext getJAXBContext();

113

public Marshaller getMarshaller() throws JAXBException;

114

}

115

```

116

117

### Using JAXBWriter

118

```java { .api }

119

// Create objects to marshal

120

Catalog catalog = new Catalog();

121

catalog.getBooks().add(new Book("978-1234567890", "XML Processing", "John Doe", new BigDecimal("29.99")));

122

catalog.getBooks().add(new Book("978-0987654321", "JAXB Guide", "Jane Smith", new BigDecimal("34.99")));

123

124

// Create JAXBWriter

125

JAXBContext jaxbContext = JAXBContext.newInstance(Catalog.class, Book.class);

126

127

try (FileWriter writer = new FileWriter("output.xml")) {

128

OutputFormat format = OutputFormat.createPrettyPrint();

129

JAXBWriter jaxbWriter = new JAXBWriter(jaxbContext, writer, format);

130

131

// Write object as XML

132

jaxbWriter.writeObject(catalog);

133

}

134

135

// Stream writing for large collections

136

try (FileWriter writer = new FileWriter("streaming.xml")) {

137

JAXBWriter jaxbWriter = new JAXBWriter(jaxbContext, writer);

138

139

// Manual document structure with object marshalling

140

jaxbWriter.writeOpen(new Catalog());

141

142

for (Book book : getAllBooks()) {

143

jaxbWriter.writeObject(book);

144

}

145

146

jaxbWriter.writeClose(new Catalog());

147

}

148

```

149

150

### JAXBModifier - Document Transformation with Objects

151

```java { .api }

152

public class JAXBModifier extends SAXModifier {

153

public JAXBModifier(String contextPath);

154

public JAXBModifier(JAXBContext jaxbContext);

155

156

public void addObjectHandler(String path, JAXBObjectHandler handler);

157

public void removeObjectHandler(String path);

158

}

159

```

160

161

### Using JAXBModifier

162

```java { .api }

163

// Modify documents using JAXB objects

164

JAXBContext jaxbContext = JAXBContext.newInstance(Book.class);

165

JAXBModifier modifier = new JAXBModifier(jaxbContext);

166

167

// Add handler for specific elements

168

modifier.addObjectHandler("/catalog/book", new JAXBObjectHandler() {

169

@Override

170

public void handleObject(Object object) throws Exception {

171

if (object instanceof Book) {

172

Book book = (Book) object;

173

174

// Modify book object

175

if (book.getPrice().compareTo(new BigDecimal("50")) > 0) {

176

book.setPrice(book.getPrice().multiply(new BigDecimal("0.9"))); // 10% discount

177

}

178

179

// Return modified object

180

return book;

181

}

182

}

183

});

184

185

// Process document

186

Document modifiedDoc = modifier.modify(originalDocument);

187

```

188

189

## JavaBean Integration

190

191

DOM4J provides reflection-based XML binding through the bean package for automatic JavaBean to XML mapping.

192

193

### Package and Import

194

```java { .api }

195

import org.dom4j.bean.BeanElement;

196

import org.dom4j.bean.BeanAttribute;

197

import org.dom4j.bean.BeanDocumentFactory;

198

import org.dom4j.bean.BeanMetaData;

199

```

200

201

### BeanElement - JavaBean as XML Element

202

```java { .api }

203

public class BeanElement extends DefaultElement {

204

// Constructors

205

public BeanElement(String name, Object bean);

206

public BeanElement(QName qname, Object bean);

207

208

// Bean access

209

public Object getBean();

210

public void setBean(Object bean);

211

212

// Attribute mapping

213

public BeanMetaData getBeanMetaData();

214

}

215

```

216

217

### Using JavaBean Integration

218

```java { .api }

219

// JavaBean class

220

public class Product {

221

private String id;

222

private String name;

223

private String category;

224

private double price;

225

private boolean available;

226

227

// Standard getters and setters

228

public String getId() { return id; }

229

public void setId(String id) { this.id = id; }

230

231

public String getName() { return name; }

232

public void setName(String name) { this.name = name; }

233

234

public String getCategory() { return category; }

235

public void setCategory(String category) { this.category = category; }

236

237

public double getPrice() { return price; }

238

public void setPrice(double price) { this.price = price; }

239

240

public boolean isAvailable() { return available; }

241

public void setAvailable(boolean available) { this.available = available; }

242

}

243

244

// Create BeanElement from JavaBean

245

Product product = new Product();

246

product.setId("P123");

247

product.setName("XML Parser");

248

product.setCategory("Software");

249

product.setPrice(99.99);

250

product.setAvailable(true);

251

252

// Create document with bean elements

253

Document document = DocumentHelper.createDocument();

254

BeanElement productElement = new BeanElement("product", product);

255

document.setRootElement(productElement);

256

257

// Bean properties become XML attributes and elements automatically

258

String xml = document.asXML();

259

// Results in XML reflecting bean properties

260

261

// Read bean data from XML

262

String value = productElement.attributeValue("id"); // "P123"

263

boolean available = Boolean.parseBoolean(productElement.attributeValue("available")); // true

264

265

// Modify bean through XML

266

productElement.addAttribute("price", "89.99");

267

// This updates the underlying bean object

268

double newPrice = product.getPrice(); // 89.99

269

```

270

271

### BeanDocumentFactory - Bean-Aware Document Creation

272

```java { .api }

273

public class BeanDocumentFactory extends DocumentFactory {

274

public BeanDocumentFactory();

275

276

@Override

277

public Element createElement(QName qname);

278

279

@Override

280

public Attribute createAttribute(Element owner, QName qname, String value);

281

}

282

```

283

284

### Using BeanDocumentFactory

285

```java { .api }

286

// Use bean-aware factory

287

BeanDocumentFactory beanFactory = new BeanDocumentFactory();

288

SAXReader reader = new SAXReader();

289

reader.setDocumentFactory(beanFactory);

290

291

// Documents created with bean support

292

Document beanDocument = reader.read("products.xml");

293

294

// Elements automatically become BeanElements where appropriate

295

Element root = beanDocument.getRootElement();

296

if (root instanceof BeanElement) {

297

BeanElement beanRoot = (BeanElement) root;

298

Object bean = beanRoot.getBean();

299

// Work with underlying bean object

300

}

301

```

302

303

## XML Schema Datatype Support

304

305

DOM4J provides XML Schema datatype integration for type-safe XML processing through the datatype package.

306

307

### Package and Import

308

```java { .api }

309

import org.dom4j.datatype.DatatypeDocumentFactory;

310

import org.dom4j.datatype.DatatypeElement;

311

import org.dom4j.datatype.DatatypeAttribute;

312

import org.dom4j.datatype.DatatypeElementFactory;

313

import org.dom4j.datatype.InvalidSchemaException;

314

```

315

316

### DatatypeDocumentFactory - Schema-Aware Factory

317

```java { .api }

318

public class DatatypeDocumentFactory extends DocumentFactory {

319

// Constructors

320

public DatatypeDocumentFactory();

321

322

// Schema loading

323

public void loadSchema(Document schemaDocument) throws InvalidSchemaException;

324

public void loadSchema(Document schemaDocument, String uri) throws InvalidSchemaException;

325

326

// Datatype-aware creation

327

@Override

328

public Element createElement(QName qname);

329

330

@Override

331

public Attribute createAttribute(Element owner, QName qname, String value);

332

}

333

```

334

335

### Using Schema Datatype Support

336

```java { .api }

337

// Load XML Schema

338

Document schemaDoc = new SAXReader().read("product-schema.xsd");

339

340

// Create datatype-aware factory

341

DatatypeDocumentFactory datatypeFactory = new DatatypeDocumentFactory();

342

datatypeFactory.loadSchema(schemaDoc);

343

344

// Use with SAX reader

345

SAXReader reader = new SAXReader();

346

reader.setDocumentFactory(datatypeFactory);

347

348

// Parse document with datatype support

349

Document document = reader.read("products.xml");

350

351

// Elements have datatype information

352

Element priceElement = (Element) document.selectSingleNode("//price");

353

if (priceElement instanceof DatatypeElement) {

354

DatatypeElement dtPrice = (DatatypeElement) priceElement;

355

356

// Get typed data

357

Object typedValue = dtPrice.getData(); // Returns appropriate Java type

358

if (typedValue instanceof BigDecimal) {

359

BigDecimal price = (BigDecimal) typedValue;

360

System.out.println("Price: " + price);

361

}

362

363

// Schema validation

364

boolean valid = dtPrice.isValid();

365

if (!valid) {

366

String error = dtPrice.getValidationMessage();

367

System.err.println("Validation error: " + error);

368

}

369

}

370

371

// Attributes also have datatype support

372

Attribute idAttr = priceElement.attribute("id");

373

if (idAttr instanceof DatatypeAttribute) {

374

DatatypeAttribute dtId = (DatatypeAttribute) idAttr;

375

Object idValue = dtId.getData(); // Typed according to schema

376

}

377

```

378

379

### Custom Datatype Elements

380

```java { .api }

381

// Implement custom datatype element factory

382

public class CustomDatatypeElementFactory implements DatatypeElementFactory {

383

@Override

384

public Element createElement(QName qname, XSType xsType) {

385

if ("decimal".equals(xsType.getName())) {

386

return new CurrencyElement(qname, xsType);

387

}

388

return new DatatypeElement(qname, xsType);

389

}

390

}

391

392

// Custom currency element with business logic

393

class CurrencyElement extends DatatypeElement {

394

public CurrencyElement(QName qname, XSType xsType) {

395

super(qname, xsType);

396

}

397

398

@Override

399

public void setText(String text) {

400

// Custom validation and formatting for currency

401

try {

402

BigDecimal amount = new BigDecimal(text);

403

if (amount.scale() > 2) {

404

amount = amount.setScale(2, RoundingMode.HALF_UP);

405

}

406

super.setText(amount.toString());

407

} catch (NumberFormatException e) {

408

throw new IllegalArgumentException("Invalid currency format: " + text);

409

}

410

}

411

412

public BigDecimal getCurrencyValue() {

413

return (BigDecimal) getData();

414

}

415

}

416

417

// Use custom factory

418

DatatypeDocumentFactory factory = new DatatypeDocumentFactory();

419

factory.setDatatypeElementFactory(new CustomDatatypeElementFactory());

420

```

421

422

## Rule-Based Processing

423

424

DOM4J provides XSLT-style pattern matching and rule-based processing through the rule package.

425

426

### Package and Import

427

```java { .api }

428

import org.dom4j.rule.Pattern;

429

import org.dom4j.rule.Rule;

430

import org.dom4j.rule.RuleSet;

431

import org.dom4j.rule.Stylesheet;

432

import org.dom4j.rule.Action;

433

```

434

435

### Pattern Interface

436

```java { .api }

437

public interface Pattern extends NodeFilter {

438

// Pattern matching priority (higher = more specific)

439

double getPriority();

440

441

// Match mode support

442

String getMatchesNodeName();

443

444

// Union pattern support

445

Pattern[] getUnionPatterns();

446

447

// Pattern properties

448

short getMatchType();

449

String getMatchesNodeName();

450

}

451

```

452

453

### Rule and RuleSet

454

```java { .api }

455

public class Rule {

456

// Constructors

457

public Rule();

458

public Rule(Pattern pattern);

459

public Rule(Pattern pattern, Action action);

460

461

// Pattern and action

462

public Pattern getPattern();

463

public void setPattern(Pattern pattern);

464

public Action getAction();

465

public void setAction(Action action);

466

467

// Execution

468

public void fireRule(Node node) throws Exception;

469

}

470

471

public class RuleSet {

472

// Rule management

473

public void addRule(Rule rule);

474

public void removeRule(Rule rule);

475

public Rule getMatchingRule(Node node);

476

477

// Rule execution

478

public void fireRule(Node node) throws Exception;

479

}

480

```

481

482

### Using Rule-Based Processing

483

```java { .api }

484

// Define processing actions

485

Action bookAction = new Action() {

486

@Override

487

public void run(Node node) throws Exception {

488

Element book = (Element) node;

489

String title = book.elementText("title");

490

String author = book.elementText("author");

491

System.out.println("Processing book: " + title + " by " + author);

492

493

// Add processing timestamp

494

book.addAttribute("processed", Instant.now().toString());

495

}

496

};

497

498

Action priceAction = new Action() {

499

@Override

500

public void run(Node node) throws Exception {

501

Element priceElement = (Element) node;

502

String priceText = priceElement.getText();

503

504

try {

505

BigDecimal price = new BigDecimal(priceText);

506

// Format price to 2 decimal places

507

String formatted = price.setScale(2, RoundingMode.HALF_UP).toString();

508

priceElement.setText(formatted);

509

} catch (NumberFormatException e) {

510

System.err.println("Invalid price: " + priceText);

511

}

512

}

513

};

514

515

// Create patterns and rules

516

Pattern bookPattern = DocumentHelper.createPattern("book");

517

Pattern pricePattern = DocumentHelper.createPattern("book/price");

518

519

Rule bookRule = new Rule(bookPattern, bookAction);

520

Rule priceRule = new Rule(pricePattern, priceAction);

521

522

// Create rule set

523

RuleSet ruleSet = new RuleSet();

524

ruleSet.addRule(bookRule);

525

ruleSet.addRule(priceRule);

526

527

// Apply rules to document

528

Document document = loadDocument();

529

applyRules(document, ruleSet);

530

531

// Recursive rule application

532

private void applyRules(Node node, RuleSet ruleSet) throws Exception {

533

// Apply rule to current node

534

Rule rule = ruleSet.getMatchingRule(node);

535

if (rule != null) {

536

rule.fireRule(node);

537

}

538

539

// Apply rules to children

540

if (node instanceof Branch) {

541

Branch branch = (Branch) node;

542

for (int i = 0; i < branch.nodeCount(); i++) {

543

applyRules(branch.node(i), ruleSet);

544

}

545

}

546

}

547

```

548

549

### Stylesheet - Template Processing

550

```java { .api }

551

public class Stylesheet {

552

// Template management

553

public void addTemplate(Rule rule);

554

public void setModeName(String modeName);

555

public String getModeName();

556

557

// Processing modes

558

public void applyTemplates(List<Node> list) throws Exception;

559

public void applyTemplates(List<Node> list, String mode) throws Exception;

560

public void run(List<Node> list) throws Exception;

561

public void run(List<Node> list, String mode) throws Exception;

562

}

563

```

564

565

### Using Stylesheet Processing

566

```java { .api }

567

// Create stylesheet with templates

568

Stylesheet stylesheet = new Stylesheet();

569

570

// Template for catalog root

571

stylesheet.addTemplate(new Rule(

572

DocumentHelper.createPattern("catalog"),

573

new Action() {

574

@Override

575

public void run(Node node) throws Exception {

576

System.out.println("Processing catalog...");

577

Element catalog = (Element) node;

578

579

// Process children with different mode

580

List<Node> books = catalog.selectNodes("book");

581

stylesheet.applyTemplates(books, "summary");

582

}

583

}

584

));

585

586

// Template for books in summary mode

587

Rule summaryRule = new Rule(

588

DocumentHelper.createPattern("book"),

589

new Action() {

590

@Override

591

public void run(Node node) throws Exception {

592

Element book = (Element) node;

593

String title = book.elementText("title");

594

String isbn = book.attributeValue("isbn");

595

System.out.println("Book summary: " + title + " (ISBN: " + isbn + ")");

596

}

597

}

598

);

599

summaryRule.setMode("summary");

600

stylesheet.addTemplate(summaryRule);

601

602

// Apply stylesheet

603

Document document = loadCatalog();

604

List<Node> roots = Arrays.asList(document.getRootElement());

605

stylesheet.run(roots);

606

```

607

608

## DTD Processing and Validation

609

610

DOM4J provides support for DTD (Document Type Definition) processing and validation.

611

612

### Package and Import

613

```java { .api }

614

import org.dom4j.DocumentType;

615

import org.dom4j.dtd.*;

616

```

617

618

### DocumentType Interface

619

```java { .api }

620

public interface DocumentType extends Node {

621

// DTD properties

622

String getElementName();

623

void setElementName(String elementName);

624

String getPublicID();

625

void setPublicID(String publicID);

626

String getSystemID();

627

void setSystemID(String systemID);

628

629

// Internal subset

630

List getInternalDeclarations();

631

void setInternalDeclarations(List internalDeclarations);

632

633

// External subset

634

List getExternalDeclarations();

635

void setExternalDeclarations(List externalDeclarations);

636

}

637

```

638

639

### Using DTD Support

640

```java { .api }

641

// Create document with DTD

642

Document document = DocumentHelper.createDocument();

643

644

// Add DOCTYPE declaration

645

DocumentType docType = DocumentHelper.createDocType(

646

"catalog", // Root element name

647

"-//Example//DTD Catalog 1.0//EN", // Public ID

648

"http://example.com/dtd/catalog.dtd" // System ID

649

);

650

document.setDocType(docType);

651

652

// Parse document with DTD validation

653

SAXReader reader = new SAXReader(true); // Enable validation

654

655

// Custom entity resolver for DTD

656

reader.setEntityResolver(new EntityResolver() {

657

@Override

658

public InputSource resolveEntity(String publicId, String systemId) throws IOException {

659

if (systemId.endsWith("catalog.dtd")) {

660

// Return local DTD copy

661

return new InputSource(new FileInputStream("local-catalog.dtd"));

662

}

663

return null; // Use default resolution

664

}

665

});

666

667

try {

668

Document validatedDoc = reader.read("catalog.xml");

669

System.out.println("Document is valid according to DTD");

670

} catch (DocumentException e) {

671

System.err.println("DTD validation failed: " + e.getMessage());

672

}

673

674

// Access DTD information

675

DocumentType docTypeInfo = document.getDocType();

676

if (docTypeInfo != null) {

677

String rootElement = docTypeInfo.getElementName();

678

String publicId = docTypeInfo.getPublicID();

679

String systemId = docTypeInfo.getSystemID();

680

681

System.out.printf("DTD: %s PUBLIC '%s' '%s'%n", rootElement, publicId, systemId);

682

}

683

```

684

685

## Swing Integration

686

687

DOM4J provides Swing integration for creating tree and table models from XML documents.

688

689

### Package and Import

690

```java { .api }

691

import org.dom4j.swing.DocumentTreeModel;

692

import org.dom4j.swing.XMLTableModel;

693

import org.dom4j.swing.XMLTableDefinition;

694

import javax.swing.*;

695

import javax.swing.tree.TreeModel;

696

import javax.swing.table.TableModel;

697

```

698

699

### DocumentTreeModel - XML Tree Visualization

700

```java { .api }

701

public class DocumentTreeModel implements TreeModel {

702

// Constructors

703

public DocumentTreeModel(Document document);

704

public DocumentTreeModel(Node rootNode);

705

706

// TreeModel implementation

707

@Override

708

public Object getRoot();

709

@Override

710

public Object getChild(Object parent, int index);

711

@Override

712

public int getChildCount(Object parent);

713

@Override

714

public boolean isLeaf(Object node);

715

@Override

716

public int getIndexOfChild(Object parent, Object child);

717

718

// Tree event support

719

@Override

720

public void addTreeModelListener(TreeModelListener listener);

721

@Override

722

public void removeTreeModelListener(TreeModelListener listener);

723

}

724

```

725

726

### Using DocumentTreeModel

727

```java { .api }

728

// Create JTree from XML document

729

Document document = loadXMLDocument();

730

DocumentTreeModel treeModel = new DocumentTreeModel(document);

731

732

JTree xmlTree = new JTree(treeModel);

733

734

// Customize tree rendering

735

xmlTree.setCellRenderer(new DefaultTreeCellRenderer() {

736

@Override

737

public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected,

738

boolean expanded, boolean leaf, int row, boolean hasFocus) {

739

740

Component component = super.getTreeCellRendererComponent(

741

tree, value, selected, expanded, leaf, row, hasFocus);

742

743

if (value instanceof Element) {

744

Element element = (Element) value;

745

setText(element.getName());

746

setIcon(getElementIcon(element));

747

} else if (value instanceof Attribute) {

748

Attribute attr = (Attribute) value;

749

setText("@" + attr.getName() + " = " + attr.getValue());

750

setIcon(getAttributeIcon());

751

} else if (value instanceof Text) {

752

Text text = (Text) value;

753

setText("\"" + text.getText().trim() + "\"");

754

setIcon(getTextIcon());

755

}

756

757

return component;

758

}

759

});

760

761

// Add to Swing component

762

JScrollPane treeScrollPane = new JScrollPane(xmlTree);

763

frame.add(treeScrollPane, BorderLayout.CENTER);

764

```

765

766

### XMLTableModel - Tabular XML Data

767

```java { .api }

768

public class XMLTableModel implements TableModel {

769

// Constructors

770

public XMLTableModel(XMLTableDefinition definition, Document document);

771

public XMLTableModel(XMLTableDefinition definition, List<Node> rows);

772

773

// TableModel implementation

774

@Override

775

public int getRowCount();

776

@Override

777

public int getColumnCount();

778

@Override

779

public String getColumnName(int columnIndex);

780

@Override

781

public Class<?> getColumnClass(int columnIndex);

782

@Override

783

public boolean isCellEditable(int rowIndex, int columnIndex);

784

@Override

785

public Object getValueAt(int rowIndex, int columnIndex);

786

@Override

787

public void setValueAt(Object value, int rowIndex, int columnIndex);

788

789

// Table event support

790

@Override

791

public void addTableModelListener(TableModelListener listener);

792

@Override

793

public void removeTableModelListener(TableModelListener listener);

794

}

795

```

796

797

### XMLTableDefinition - Table Structure Definition

798

```java { .api }

799

public class XMLTableDefinition {

800

// Constructors

801

public XMLTableDefinition();

802

803

// Row definition

804

public void setRowExpression(String rowXPath);

805

public String getRowExpression();

806

807

// Column definition

808

public void addColumnDefinition(String columnName, String columnXPath);

809

public void addColumnDefinition(String columnName, String columnXPath, Class<?> columnClass);

810

811

// Column access

812

public int getColumnCount();

813

public String getColumnName(int index);

814

public String getColumnXPath(int index);

815

public Class<?> getColumnClass(int index);

816

}

817

```

818

819

### Using XMLTableModel

820

```java { .api }

821

// Define table structure

822

XMLTableDefinition tableDef = new XMLTableDefinition();

823

tableDef.setRowExpression("//book"); // Each book is a row

824

825

// Define columns

826

tableDef.addColumnDefinition("Title", "title/text()", String.class);

827

tableDef.addColumnDefinition("Author", "author/text()", String.class);

828

tableDef.addColumnDefinition("ISBN", "@isbn", String.class);

829

tableDef.addColumnDefinition("Price", "@price", Double.class);

830

tableDef.addColumnDefinition("Available", "@available", Boolean.class);

831

832

// Create table model

833

Document catalog = loadCatalog();

834

XMLTableModel tableModel = new XMLTableModel(tableDef, catalog);

835

836

// Create JTable

837

JTable xmlTable = new JTable(tableModel);

838

839

// Configure table

840

xmlTable.setAutoCreateRowSorter(true);

841

xmlTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

842

843

// Custom cell renderers

844

xmlTable.getColumnModel().getColumn(3).setCellRenderer(new DefaultTableCellRenderer() {

845

private final NumberFormat currencyFormat = NumberFormat.getCurrencyInstance();

846

847

@Override

848

public void setValue(Object value) {

849

if (value instanceof Number) {

850

setText(currencyFormat.format(((Number) value).doubleValue()));

851

} else {

852

setText(value != null ? value.toString() : "");

853

}

854

}

855

});

856

857

// Add to Swing interface

858

JScrollPane tableScrollPane = new JScrollPane(xmlTable);

859

frame.add(tableScrollPane, BorderLayout.CENTER);

860

861

// Handle selection changes

862

xmlTable.getSelectionModel().addListSelectionListener(e -> {

863

if (!e.getValueIsAdjusting()) {

864

int selectedRow = xmlTable.getSelectedRow();

865

if (selectedRow >= 0) {

866

String title = (String) tableModel.getValueAt(selectedRow, 0);

867

System.out.println("Selected book: " + title);

868

}

869

}

870

});

871

```

872

873

## Utility Classes and Helper Features

874

875

### Singleton Strategy Pattern

876

```java { .api }

877

import org.dom4j.util.SingletonStrategy;

878

import org.dom4j.util.SimpleSingleton;

879

880

// Custom singleton strategy

881

public class ThreadLocalSingletonStrategy<T> implements SingletonStrategy<T> {

882

private final ThreadLocal<T> threadLocal = new ThreadLocal<>();

883

private final Class<T> type;

884

885

public ThreadLocalSingletonStrategy(Class<T> type) {

886

this.type = type;

887

}

888

889

@Override

890

public T instance() {

891

T instance = threadLocal.get();

892

if (instance == null) {

893

try {

894

instance = type.newInstance();

895

threadLocal.set(instance);

896

} catch (Exception e) {

897

throw new RuntimeException("Cannot create instance", e);

898

}

899

}

900

return instance;

901

}

902

}

903

904

// Use with document factory

905

SingletonStrategy<DocumentFactory> strategy = new ThreadLocalSingletonStrategy<>(DocumentFactory.class);

906

DocumentFactory factory = strategy.instance();

907

```

908

909

### User Data Support

910

```java { .api }

911

import org.dom4j.util.UserDataElement;

912

import org.dom4j.util.UserDataAttribute;

913

import org.dom4j.util.UserDataDocumentFactory;

914

915

// Elements that can store arbitrary user data

916

UserDataDocumentFactory userDataFactory = new UserDataDocumentFactory();

917

Document document = userDataFactory.createDocument();

918

919

Element element = userDataFactory.createElement("product");

920

if (element instanceof UserDataElement) {

921

UserDataElement userElement = (UserDataElement) element;

922

923

// Store custom application data

924

userElement.setData("businessObject", productBusinessObject);

925

userElement.setData("validationState", ValidationState.VALID);

926

userElement.setData("lastModified", Instant.now());

927

928

// Retrieve user data

929

Product businessObj = (Product) userElement.getData("businessObject");

930

ValidationState state = (ValidationState) userElement.getData("validationState");

931

}

932

```

933

934

### Error Handling Utilities

935

```java { .api }

936

import org.dom4j.util.XMLErrorHandler;

937

938

// Comprehensive error handling

939

XMLErrorHandler errorHandler = new XMLErrorHandler();

940

941

// Configure error levels

942

errorHandler.setIgnoreWarnings(false);

943

errorHandler.setIgnoreErrors(false);

944

945

SAXReader reader = new SAXReader();

946

reader.setErrorHandler(errorHandler);

947

948

try {

949

Document document = reader.read("document.xml");

950

951

// Check for warnings and errors after parsing

952

if (errorHandler.hasErrors()) {

953

List<String> errors = errorHandler.getErrors();

954

System.err.println("Parsing errors occurred:");

955

errors.forEach(System.err::println);

956

}

957

958

if (errorHandler.hasWarnings()) {

959

List<String> warnings = errorHandler.getWarnings();

960

System.out.println("Parsing warnings:");

961

warnings.forEach(System.out::println);

962

}

963

964

} catch (DocumentException e) {

965

System.err.println("Fatal parsing error: " + e.getMessage());

966

}

967

```

968

969

### Node Comparison and Sorting

970

```java { .api }

971

import org.dom4j.util.NodeComparator;

972

import java.util.Comparator;

973

974

public class NodeComparator implements Comparator<Node> {

975

// Constructors

976

public NodeComparator();

977

978

// Comparison methods

979

public int compare(Node node1, Node node2);

980

981

// Comparison by different criteria

982

public static Comparator<Node> createDocumentOrderComparator();

983

public static Comparator<Node> createNameComparator();

984

public static Comparator<Node> createTextComparator();

985

}

986

```

987

988

**Usage Examples:**

989

990

```java

991

import org.dom4j.util.NodeComparator;

992

993

// Sort elements by name

994

List<Element> elements = document.selectNodes("//element");

995

elements.sort(NodeComparator.createNameComparator());

996

997

// Sort by document order

998

List<Node> nodes = document.selectNodes("//node()");

999

nodes.sort(new NodeComparator());

1000

1001

// Custom sorting

1002

elements.sort((e1, e2) -> {

1003

NodeComparator comparator = new NodeComparator();

1004

int nameCompare = e1.getName().compareTo(e2.getName());

1005

return nameCompare != 0 ? nameCompare : comparator.compare(e1, e2);

1006

});

1007

```

1008

1009

### Indexed Elements for Fast Access

1010

```java { .api }

1011

import org.dom4j.util.IndexedElement;

1012

import org.dom4j.util.IndexedDocumentFactory;

1013

1014

public class IndexedElement extends DefaultElement {

1015

// Constructor

1016

public IndexedElement(QName qname);

1017

public IndexedElement(String name);

1018

1019

// Indexed access methods

1020

public Element elementByID(String elementID);

1021

public List<Element> elementsByName(QName qname);

1022

public List<Element> elementsByName(String name);

1023

1024

// Index management

1025

public void indexElements();

1026

public boolean isIndexed();

1027

}

1028

1029

public class IndexedDocumentFactory extends DocumentFactory {

1030

// Singleton access

1031

public static IndexedDocumentFactory getInstance();

1032

1033

// Override factory methods to create indexed elements

1034

public Element createElement(QName qname);

1035

public Element createElement(String name);

1036

}

1037

```

1038

1039

**Usage Examples:**

1040

1041

```java

1042

// Create document with indexed elements

1043

IndexedDocumentFactory factory = IndexedDocumentFactory.getInstance();

1044

SAXReader reader = new SAXReader();

1045

reader.setDocumentFactory(factory);

1046

1047

Document document = reader.read("large-document.xml");

1048

Element root = document.getRootElement();

1049

1050

if (root instanceof IndexedElement) {

1051

IndexedElement indexedRoot = (IndexedElement) root;

1052

1053

// Fast element lookup by ID

1054

Element elementById = indexedRoot.elementByID("product-123");

1055

1056

// Fast lookup by name (faster than XPath for large documents)

1057

List<Element> products = indexedRoot.elementsByName("product");

1058

List<Element> categories = indexedRoot.elementsByName(QName.get("category", namespace));

1059

}

1060

```

1061

1062

## Performance Optimization Features

1063

1064

### Memory-Efficient Processing

1065

```java { .api }

1066

// Custom lightweight implementations

1067

public class LightweightDocumentFactory extends DocumentFactory {

1068

@Override

1069

public Element createElement(QName qname) {

1070

return new LightweightElement(qname);

1071

}

1072

1073

@Override

1074

public Document createDocument() {

1075

return new LightweightDocument();

1076

}

1077

}

1078

1079

// Optimized for memory usage

1080

class LightweightElement extends AbstractElement {

1081

private QName qname;

1082

private Object content; // Single object or List for multiple children

1083

private Object attributes; // Single attribute or Map for multiple

1084

1085

public LightweightElement(QName qname) {

1086

this.qname = qname;

1087

}

1088

1089

// Optimized implementations that use less memory

1090

// ... implementation details

1091

}

1092

```

1093

1094

### Caching and Performance

1095

```java { .api }

1096

// XPath compilation caching

1097

public class CachedXPathProcessor {

1098

private final Map<String, XPath> xpathCache = new ConcurrentHashMap<>();

1099

private final Map<String, String> namespaces;

1100

1101

public CachedXPathProcessor(Map<String, String> namespaces) {

1102

this.namespaces = namespaces != null ? Map.copyOf(namespaces) : Map.of();

1103

}

1104

1105

public XPath getOrCreateXPath(String expression) {

1106

return xpathCache.computeIfAbsent(expression, expr -> {

1107

try {

1108

XPath xpath = DocumentHelper.createXPath(expr);

1109

if (!namespaces.isEmpty()) {

1110

xpath.setNamespaceURIs(namespaces);

1111

}

1112

return xpath;

1113

} catch (InvalidXPathException e) {

1114

throw new RuntimeException("Invalid XPath: " + expr, e);

1115

}

1116

});

1117

}

1118

1119

// Batch processing methods

1120

public Map<String, List<Node>> executeQueries(Document document, List<String> expressions) {

1121

return expressions.parallelStream()

1122

.collect(Collectors.toConcurrentMap(

1123

expr -> expr,

1124

expr -> getOrCreateXPath(expr).selectNodes(document)

1125

));

1126

}

1127

}

1128

```

1129

1130

DOM4J's advanced features provide enterprise-grade capabilities for complex XML processing scenarios. From object binding and schema validation to rule-based processing and GUI integration, these features enable sophisticated XML applications while maintaining DOM4J's core principles of flexibility and ease of use.