Overview of XmlUtil
masterkotlinx.serialization, allowing for automatic object serialization using Kotlin's standard serialization plugin. It supports all Kotlin platforms, though Native support is currently at beta quality.repository·master·Indexed 19 days ago
https://github.com/pdvrieze/xmlutilA multiplatform Kotlin library for XML serialization and parsing designed for the kotlinx.serialization ecosystem. It provides a platform-independent core with optional platform-specific implementations for JVM (STAX), Android (XmlPullParser), and JS (DOM). The library includes a serialization module for automatic object mapping, various format presets (recommended, compact, fast), and integration with kotlinx.io.
kotlinx.serialization, allowing for automatic object serialization using Kotlin's standard serialization plugin. It supports all Kotlin platforms, though Native support is currently at beta quality.serialutil module is a component of the xmlutil project that provides utility functionality specifically designed to assist with serialization tasks.nl.adaptivity.xmlutil.core.kxio package provides core generic functions designed to integrate the xmlutil.core library with kotlinx.io. Use this module when you need to perform XML operations using kotlinx.io source or sink abstractions.serialization module of xmlutil provides support for XML serialization by leveraging the kotlinx.serialization framework. This allows you to define your data structures using standard @Serializable annotations and convert them to and from XML formats.XmlUtil is organized into several modules depending on your platform and serialization needs:
| Module | Description |
|---|---|
core | The core library containing platform-independent XML functionality. |
core-io | Provides kotlinx.io bindings for the core XML library. |
core-jdk | Provides access to JDK-specific types (STaX) and the platform parser. Use this only if you require integration with JDK STaX. |
serialization | The kotlinx.serialization format implementation for XML. |
serialization-io | Shortcut bindings providing direct access to kotlinx.io based streams (wraps core-io). |
serialutil | An auxiliary library providing utility functions for serialization (not XML-specific). |
core-android | Deprecated. Android-specific parsing; generic implementations are now preferred. |
The xmlserializable module provides mechanisms for type-based serialization and factory-based deserialization. This module is primarily intended for legacy purposes and allows for automatic serialization/deserialization based on interfaces.
Note: This module is distinct from kotlinx.serialization and is not related to it.
The library is organized into several packages to facilitate different tasks:
nl.adaptivity.xmlutil: The core package for XML pull parsing access (via XmlStreaming).nl.adaptivity.js.util: Contains extension functions designed to simplify working with DOM nodes.nl.adaptivity.xmlutil.util: Contains various utility types intended to make the library more convenient to use.A DynamicTagWriter is a custom XmlDelegatingWriter used during serialization to transform static tag names into dynamic ones (e.g., converting <TestElement> with id=1 into <Test_1>).
startTag and endTag to write the dynamic string (e.g., "Test_" + idValue) instead of the standard tag name.id attribute during the attribute() call so it doesn't appear twice).internal class DynamicTagWriter(private val writer: XmlWriter, descriptor: XmlDescriptor, private val idValue: String) :
XmlDelegatingWriter(writer) {
override fun startTag(namespace: String?, localName: String, prefix: String?) {
when (filterDepth) {
0 -> super.startTag("", "Test_$idValue", "")
else -> super.startTag(namespace, localName, prefix)
}
}
override fun endTag(namespace: String?, localName: String, prefix: String?) {
when (filterDepth) {
1 -> super.endTag("", "Test_$idValue", "")
else -> super.endTag(namespace, localName, prefix)
}
}
}To implement a SOAP-compliant structure, use the @XmlSerialName annotation to define the namespace and the preferred prefix for the Envelope and Body elements.
In the provided pattern, the Envelope class acts as a generic wrapper. It uses a private Body class to ensure the SOAP standard requirement of a single wrapping element is met. The Envelope provides a public constructor that accepts the payload directly, hiding the internal Body implementation.
Key annotations:
@XmlSerialName(name, namespace, prefix): Used on the Envelope class to set the SOAP envelope namespace (e.g., http://schemas.xmlsoap.org/soap/envelope/) and prefix (e.g., S).@Polymorphic: Used within the Body class to allow the content of the SOAP message to vary.@Serializable
@XmlSerialName("Envelope", "http://schemas.xmlsoap.org/soap/envelope/", "S")
class Envelope<BODYTYPE> private constructor(
private val body: Body<BODYTYPE>
) {
constructor(data: BODYTYPE) : this(Body(data))
val data: BODYTYPE get() = body.data
@Serializable
private data class Body<BODYTYPE>(@Polymorphic val data: BODYTYPE)
}The XmlSerializationPolicy defines how Kotlin/Java types are mapped to XML structures (tags, attributes, text, or mixed content). While the default policy provides a 'best attempt' at structuring XML, you can implement or replace it to control:
Commonly used customization points in the policy include effectiveOutputKind, effectiveName, and polymorphicDiscriminatorName.
When defining the actual message content (the payload inside the SOAP Body), you can control namespaces at different levels:
@XmlSerialName on your result class (e.g., GeResult) to define its specific namespace and prefix (e.g., ns2).code field) should reside in the empty/default namespace rather than inheriting the parent's namespace, use @XmlSerialName with empty strings for the namespace and prefix, and pair it with @XmlElement(true) to ensure it is serialized as an element.@XmlSerialName to ensure they match the expected XML schema.@Serializable
@XmlSerialName("Ge", "http://www.gxtlink.com/webservice/", "ns2")
data class GeResult<out T>(
@XmlSerialName("code", "", "")
@XmlElement(true)
val code: Int,
val data: T
)
@Serializable
@XmlSerialName("data", "", "")
data class GeResultData(
@XmlElement(true)
val project: String,
@XmlElement(true)
val unit: String
)A DynamicTagReader is a custom XmlDelegatingReader used during deserialization to transform dynamic tag names (like Test_123) into a static, structured format that the serialization framework understands.
localName, namespaceURI, and prefix at the target depth to return the expected static name from the XmlDescriptor instead of the dynamic name found in the XML.id attribute) into the stream. For example, it can intercept the dynamic part of the tag name (the 123 in Test_123) and present it as a standard attribute value.filterDepth calculation to ensure transformations only apply to the specific level of the XML hierarchy being handled, preventing accidental corruption of parent or child elements.internal class DynamicTagReader(reader: XmlReader, descriptor: XmlDescriptor) : XmlDelegatingReader(reader) {
// ... implementation details for normalizing localName, namespaceURI, and injecting attributes
override val localName: String
get() = when (filterDepth) {
0 -> elementName.localPart
else -> super.localName
}
}