XML to Kotlin data classes
Kotlin projects on the JVM and Android still deal with XML: build and manifest files, feeds, SOAP responses and configuration. This XML to Kotlin generator writes immutable data class models from a sample document, so the XML can be mapped once and then used with Kotlin's null safety and copy() support.
Example: an Android-style manifest
<manifest package="com.example.app" versionCode="42">
<uses-permission name="android.permission.INTERNET"/>
<uses-permission name="android.permission.CAMERA"/>
<application label="Example" debuggable="false"/>
</manifest>
data class Manifest (
val usesPermission: List<UsesPermission>,
val application: Application,
val manifestPackage: String,
val versionCode: Long
)
data class Application (
val label: String,
val debuggable: Boolean
)
data class UsesPermission (
val name: String
)
Hyphenated element names such as uses-permission become camelCase (usesPermission), and the package attribute becomes manifestPackage because package is a Kotlin keyword. In real Android manifests these attributes carry the android: prefix; namespace prefixes are removed, so android:name maps to name.
Types inferred from text
XML stores everything as text, so types are inferred from what the values look like: versionCode="42" became Long, debuggable="false" became Boolean, and ISO 8601 timestamps with an offset become OffsetDateTime. Values with leading zeros or mixed digits and letters stay safer as String; change the type by hand when a field is an identifier rather than a number, because a leading zero is lost once the value is parsed as a number.
Binding XML to the data classes
- Jackson XML (
jackson-dataformat-xmlplusjackson-module-kotlin): annotate attributes with@JacksonXmlProperty(isAttribute = true, localName = "package"), repeated children with@JacksonXmlElementWrapper(useWrapping = false)and@JacksonXmlProperty(localName = "uses-permission"), then read withXmlMapper().registerKotlinModule().readValue<Manifest>(xml). - kotlinx.serialization with xmlutil: mark classes
@Serializable, use@XmlSerialNamefor element names and@XmlElement(false)for attributes; this also works in Kotlin Multiplatform. - Android's
XmlPullParser: read events manually and construct the data classes; no extra dependency.
Whichever you choose, map the renamed properties back to the original XML names with the library's annotations.
Making the classes tolerant with Jackson
Real documents rarely match the sample exactly. With Jackson and the Kotlin module, a few annotations and default values keep parsing from failing when attributes are added or omitted:
@JsonIgnoreProperties(ignoreUnknown = true)
data class Application(
@JacksonXmlProperty(isAttribute = true) val label: String,
@JacksonXmlProperty(isAttribute = true) val debuggable: Boolean = false,
@JacksonXmlProperty(isAttribute = true) val icon: String? = null,
)
ignoreUnknown skips attributes and elements your class does not declare, such as tool-specific extras. The Kotlin module uses a parameter's default value when the XML leaves it out, so debuggable becomes false and icon stays null instead of the whole read throwing an exception. Keep required fields without defaults, so that a genuinely broken document still fails loudly.
Things to check
- Properties are non-null when the sample always contains them; make them nullable with
= nulldefaults if real documents omit them. - Include at least two of each repeated element so it becomes a
List. - Replace the
quicktypepackage name with your own.
For JSON APIs use JSON to Kotlin. Check the XML with the XML Validator first. Generation runs in your browser.