redundent / kotlin-xml-builder

A lightweight type safe builder to build xml documents in Kotlin
Apache License 2.0
155 stars 19 forks source link

CI Download

Kotlin XML Builder

This library can be used to build xml documents from Kotlin code. It is based on the HTML builder described in the Kotlin docs

It is designed to be lightweight and fast. There isn't any validation except to escape text to not violate xml standards.

License

Apache 2.0

Usage

To use in Gradle, simply add the Maven Central repository and then add the following dependency.

repositories {
    mavenCentral()
}

dependencies {
    compile("org.redundent:kotlin-xml-builder:[VERSION]")
}

Similarly in Maven:

<dependencies>
    <dependency>
        <groupId>org.redundent</groupId>
        <artifactId>kotlin-xml-builder</artifactId>
        <version>[VERSION]</version>
    </dependency>
</dependencies>

Example

val people = xml("people") {
    xmlns = "http://example.com/people"
    "person" {
        attribute("id", 1)
        "firstName" {
            -"John"
        }
        "lastName" {
            -"Doe"
        }
        "phone" {
            -"555-555-5555"
        }
    }
}

val asString = people.toString()

produces

<people xmlns="http://example.com/people">
    <person id="1">
        <firstName>
            John
        </firstName>
        <lastName>
            Doe
        </lastName>
        <phone>
            555-555-5555
        </phone>
    </person>
</people>
class Person(val id: Long, val firstName: String, val lastName: String, val phone: String)

val listOfPeople = listOf(
    Person(1, "John", "Doe", "555-555-5555"),
    Person(2, "Jane", "Doe", "555-555-6666")
)

val people = xml("people") {
    xmlns = "http://example.com/people"
    for (person in listOfPeople) {
        "person" {
            attribute("id", person.id)
            "firstName" {
                -person.firstName
            }
            "lastName" {
                -person.lastName
            }
            "phone" {
                -person.phone
            }
        }
    }    
}

val asString = people.toString()

produces

<people xmlns="http://example.com/people">
    <person id="1">
        <firstName>
            John
        </firstName>
        <lastName
            >Doe
        </lastName>
        <phone>
            555-555-5555
        </phone>
    </person>
    <person id="2">
        <firstName>
            Jane
        </firstName>
        <lastName>
            Doe
        </lastName>
        <phone>
            555-555-6666
        </phone>
    </person>
</people>

Namespaces

Version 1.8.0 added more precise control over how namespaces are used. You can add a namespace to any element or attribute and the correct node/attribute name will be used automatically. When using the new namespace aware methods, you no longer need to manually add the namespace to the element.

See examples of < 1.8.0 and >= 1.8.0 below to produce the following xml

<t:root xmlns:t="https://ns.org">
    <t:element t:key="value"/>
</t:root>

< 1.8.0

xml("t:root") {
    namespace("t", "https://ns.org")
    "t:element"("t:key" to "value")
}

>= 1.8.0

val ns = Namespace("t", "https://ns.org")
xml("root", ns) {
    "element"(ns, Attribute("key", "value", ns))
}

You can also use the Namespace("https://ns.org") constructor to create a Namespace object that represents the default xmlns.

Things to be aware of

Processing Instructions

You can add processing instructions to any element by using the processingInstruction method.

xml("root") {
    processingInstruction("instruction")
}
<root>
    <?instruction?>
</root>

Global Instructions

Similarly you can add a global (top-level) instruction by call globalProcessingInstruction on the root node. This method only applies to the root. If it is called on any other element, it will be ignored.

xml("root") {
    globalProcessingInstruction("xml-stylesheet", "type" to "text/xsl", "href" to "style.xsl")
}
<?xml-stylesheet type="text/xsl" href="https://github.com/redundent/kotlin-xml-builder/blob/main/style.xsl"?>
<root/>

DOCTYPE

As of version 1.7.4, you can specify a DTD (Document Type Declaration).

xml("root") {
    doctype(systemId = "mydtd.dtd")
}
<!DOCTYPE root SYSTEM "mydtd.dtd">
<root/>

Limitations with DTD

Complex DTDs are not supported.

Unsafe

You can now use unsafe text for element and attribute values.

xml("root") {
    unsafeText("<xml/>")
}

produces

<root>
    <xml/>
</root>
xml("root") {
    attribute("attr", unsafe("&#123;"))
}

produces

<root attr="&amp;#123;"/>

Print Options

You can now control how your xml will look when rendered by passing the new PrintOptions class as an argument to toString.

pretty - This is the default and will produce the xml you see above.

singleLineTextElements - This will render single text element nodes on a single line if pretty is true

<root>
    <element>value</element>
</root>

as opposed to:

<root>
    <element>
        value
    </element>
</root>

useSelfClosingTags - Use <element/> instead of <element></element> for empty tags

useCharacterReference - Use character references instead of escaped characters. i.e. &#39; instead of &apos;

Reading XML

You can also read xml documents using the parse methods. They provide basic xml parsing and will build a Node element to build upon.

For more advanced consuming, check out konsume-xml. It includes many more features for consuming documents.

Release Notes

Version 1.9.1

Version 1.9.0

BREAKING CHANGES

Version 1.8.0

Version 1.7.4

Version 1.7.3

Version 1.7.2

Version 1.7.1

Version 1.7

POTENTIAL BREAKING CHANGES

Version 1.6.1

Version 1.6.0

BREAKING CHANGES

Version 1.5.4

Version 1.5.3

Version 1.5.2

Version 1.5.1

Version 1.5.0

BREAKING CHANGES

Version 1.4.5

Version 1.4.4

Version 1.4.3

BREAKING CHANGES

Version 1.4.2

Version 1.4.1

Version 1.4

BREAKING CHANGES

Version 1.3

Version 1.2

Version 1.1