pdvrieze / xmlutil

XML Serialization library for Kotlin

Home Page:https://pdvrieze.github.io/xmlutil/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Deserializing object with variable XmlValue

jonapoul opened this issue · comments

Honestly I'm not sure what the proper wording is for the problem I'm trying to solve, this may already be somewhere in the issues but I don't know what I'm looking for. Basically, I have some XML objects like:

<entries>
  <entry key="foo">bar</entry>
  <entry key="bar">
    <sub-element>baz</sub-element>
    <sub-element>qux</sub-element>
  </entry>
</entries>

So I have an "entry" object with multiple possible values as the wrapped value - either some primitive data or a set of some other simple XML object. How would I go about deserializing this? I tried using polymorphism with a custom serializer, where each subclass has a @SerialName("entry") annotation, but it would only give me errors about each subclass having the same key.

I also tried using a data class like

@Serializable
@SerialName("entry")
public data class EntryModel(
  @SerialName("key") val key: String,
  @XmlValue val value: String,
)

Which I hoped would treat the array as a raw string, which I could handle separately. But this gave me an error like:

nl.adaptivity.xmlutil.serialization.XmlSerialException: Missing end tag after text only content (found: START_ELEMENT - {}:element (Line number = 2
Column number = 12
System Id = null
Public Id = null
Location Uri= null
CharacterOffset = 61
))

Any help is appreciated!

There is some special magic that supports what you want. It relies on special serializers that handle this (you could write your own - btw. note that the dev branch has a redesigned approach to this that makes it easier to write your own custom serializers to support it)

In any case there are a number of options (different types for value):

  • CompactFragment: This will store the xml subdocument of the tag as text inside the fragment (together with relevant namespace declarations from the parent)
  • List<CompactFragment>: Does the same, but each child tag becomes its own content (this might include whitespace)
  • Node: Serializes the content as a DOM node (text or element)
  • List<Node>: A list of dom nodes
  • Element: Only allows elements.

If your children are actually known (rather than arbitrary xml) you can follow the example from this test:
https://github.com/pdvrieze/xmlutil/blob/master/serialization/src/commonTest/kotlin/nl/adaptivity/xml/serialization/TestMixedTypesafe.kt - this uses the MixedContent class from the serialutil module (you can reuse that).