# How to Load and Merge XML Property Files Using XMLLoader in Owner

> Effortlessly load and merge XML property files with Owner XMLLoader. Parse standard Java XML or custom hierarchies and combine multiple files using @LoadType MERGE. Get started now.

- Repository: [Matteo Baccan/owner](https://github.com/matteobaccan/owner)
- Tags: how-to-guide
- Published: 2026-03-07

---

**Use Owner's built-in `XMLLoader` to automatically parse standard Java XML properties or custom hierarchical XML by pointing `@Sources` to `.xml` files, and enable merging across multiple files with `@LoadType(MERGE)`.**

The Owner library (matteobaccan/owner) provides a type-safe configuration management system for Java applications. When you need to load and merge XML property files using XMLLoader, the framework handles resource detection, SAX-based parsing, and deterministic merging without requiring manual XML parsing code.

## Understanding XMLLoader in Owner

`XMLLoader` is Owner's built-in implementation for reading XML-based configuration files, located at [`owner/src/main/java/org/aeonbits/owner/loaders/XMLLoader.java`](https://github.com/matteobaccan/owner/blob/main/owner/src/main/java/org/aeonbits/owner/loaders/XMLLoader.java). This loader handles both the standard Java XML properties format (produced by `java.util.Properties.storeToXML`) and custom hierarchical XML structures where nested elements map to dot-notation property keys.

The loader is automatically registered in `LoadersManager` alongside `PropertiesLoader` and `SystemLoader` at lines 40-44 of [`owner/src/main/java/org/aeonbits/owner/LoadersManager.java`](https://github.com/matteobaccan/owner/blob/main/owner/src/main/java/org/aeonbits/owner/LoadersManager.java). This automatic registration means no additional configuration is required to process XML files.

## How XMLLoader Discovers and Parses XML Files

### File Discovery via accept()

When Owner initiates resource loading, it queries registered loaders through the `accept(URI)` method to determine capability. `XMLLoader` declares XML support by checking that the resource URL ends with the `.xml` extension, as implemented in lines 29-33 of [`XMLLoader.java`](https://github.com/matteobaccan/owner/blob/main/XMLLoader.java).

### Parsing Strategy with XmlToPropsHandler

Once a URI is accepted, the `load(Properties, URI)` method opens an input stream and instantiates a SAX parser, delegating document processing to the inner class `XmlToPropsHandler`. This handler builds a flat `java.util.Properties` map through three distinct parsing modes:

- **Standard Java XML format**: Resolves the `properties.dtd` system identifier (see `resolveEntity`) and maps each `<entry key="...">value</entry>` element to a corresponding property entry.
- **Custom hierarchical XML**: Constructs property keys by concatenating element names with dots (e.g., `<database><url>value</url></database>` becomes `database.url`) and extracts element attributes as separate properties prefixed by the element name.

The conversion logic resides in the `startElement`, `characters`, and `endElement` methods between lines 86-119 of [`XMLLoader.java`](https://github.com/matteobaccan/owner/blob/main/XMLLoader.java).

## Merging Multiple XML Property Files

Owner merges multiple XML sources when your configuration interface declares `@LoadType(MERGE)`. This annotation instructs the framework to combine properties from all specified sources in declaration order, rather than stopping at the first available file.

The merge operation executes in `PropertiesManager.merge` at lines 42-45 of [`owner/src/main/java/org/aeonbits/owner/PropertiesManager.java`](https://github.com/matteobaccan/owner/blob/main/owner/src/main/java/org/aeonbits/owner/PropertiesManager.java). The implementation iterates through loaded property maps and copies all entries into the final result, meaning later sources override earlier ones according to the `@Sources` declaration order.

## Practical Code Examples

### Loading a Single XML Configuration

Define an interface referencing your XML file:

```java
import org.aeonbits.owner.Config;
import org.aeonbits.owner.ConfigFactory;
import org.aeonbits.owner.Config.Sources;

@Sources("classpath:app-config.xml")
public interface AppConfig extends Config {
    String dbUrl();
    String dbUser();
    String dbPassword();
}

```

Instantiate the configuration:

```java
AppConfig cfg = ConfigFactory.create(AppConfig.class);
System.out.println(cfg.dbUrl());  // Outputs value read from app-config.xml

```

### Merging Multiple XML Sources

Enable merging to layer configurations with override capability:

```java
import org.aeonbits.owner.Config.LoadType;
import static org.aeonbits.owner.Config.LoadType.MERGE;

@LoadType(MERGE)
@Sources({
    "classpath:defaults.xml",        // Base configuration (lowest priority)
    "file:${user.home}/app.xml",     // User-specific overrides
    "file:/etc/app.xml"              // System-wide overrides (highest priority)
})
public interface MergedConfig extends Config {
    String host();
    int port();
}

```

```java
MergedConfig cfg = ConfigFactory.create(MergedConfig.class);
// Returns value from /etc/app.xml if present, 
// otherwise ${user.home}/app.xml, otherwise defaults.xml
System.out.println(cfg.host());

```

### Processing Custom Hierarchical XML

For XML files with nested elements and attributes:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
    <mail smtp="smtp.example.com">
        <username>user</username>
        <password>secret</password>
    </mail>
</config>

```

Map using dot notation for elements and attributes:

```java
import org.aeonbits.owner.Config.Key;

@Sources("file:custom.xml")
public interface MailConfig extends Config {
    @Key("mail.smtp")      
    String smtpHost();   // Maps to smtp attribute value
    
    @Key("mail.username")  
    String username();   // Maps to username element text
    
    @Key("mail.password")  
    String password();
}

```

The resulting property map contains:
- `mail.smtp = smtp.example.com`
- `mail.username = user`
- `mail.password = secret`

## Summary

- **Automatic Detection**: `XMLLoader` automatically handles resources ending in `.xml` without requiring manual registration, as configured in `LoadersManager`.
- **Dual Format Support**: The `XmlToPropsHandler` class handles both standard Java XML properties (with `properties.dtd` resolution) and custom hierarchical XML structures.
- **Hierarchical Mapping**: Custom XML elements convert to dot-notation keys (e.g., `database.url`), while attributes become standalone properties prefixed by their element name.
- **Deterministic Merging**: Use `@LoadType(MERGE)` to combine multiple XML sources, with later files overriding earlier ones according to the implementation in `PropertiesManager.merge`.

## Frequently Asked Questions

### Does XMLLoader support XML schemas or validation?

`XMLLoader` uses a SAX-based parser that recognizes the standard Java properties DTD for validation of standard formats. For custom XML structures, it performs structural parsing without strict schema validation, building property keys from element hierarchies and attributes as implemented in the `XmlToPropsHandler` class at lines 86-119 of [`XMLLoader.java`](https://github.com/matteobaccan/owner/blob/main/XMLLoader.java).

### How do I override XML properties with system properties?

Since `XMLLoader` is registered alongside `SystemLoader` in `LoadersManager`, you can combine `@Sources` pointing to XML files with the `system:properties` source. System properties will override XML values when using appropriate load strategies or when explicitly importing system properties in your configuration interface.

### Can I mix XML property files with standard .properties files?

Yes. Owner's `LoadersManager` registers both `XMLLoader` and `PropertiesLoader` simultaneously at initialization. You can declare both `.xml` and `.properties` files in your `@Sources` annotation, and the framework automatically selects the appropriate loader for each URI based on file extensions, merging them seamlessly when `@LoadType(MERGE)` is specified.

### What happens if two XML files define the same property key?

When using `@LoadType(MERGE)`, the `PropertiesManager.merge` method processes sources sequentially in the order they appear in the `@Sources` annotation. Later entries overwrite earlier ones, so the value from the last XML file in the list takes precedence according to the merge logic at lines 42-45 of [`PropertiesManager.java`](https://github.com/matteobaccan/owner/blob/main/PropertiesManager.java).