Replies: 9 comments 1 reply
-
This is supported through the policy. For the default policy you can set it using the |
Beta Was this translation helpful? Give feedback.
-
@pdvrieze Thank you. I am actually struggling in general with polymorphism. I've re-read the README many times and can not wrap my head around it. How do we solve this simple case? private fun testFullCircle(
xml: String,
expected: RootObject
) {
val format = XML {
defaultPolicy {
autoPolymorphic = true
typeDiscriminatorName = QName("species")
}
}
val root = format.decodeFromString<RootObject>(xml)
assertEquals(expected, root)
val encoded = format.encodeToString(root)
val root2 = format.decodeFromString<RootObject>(encoded)
assertEquals(expected, root2)
}
@Test
fun decodePolymorphic() {
testFullCircle(
xml = """
<?xml version='1.0' encoding='UTF-8'?>
<root>
<animal>
<species>spider</species>
<numberOfEyes>10</numberOfEyes>
</animal>
</root>
""".trimIndent(),
expected = RootObject(Spider(numberOfEyes = 10))
)
testFullCircle(
xml = """
<?xml version='1.0' encoding='UTF-8'?>
<root>
<animal>
<species>cat</species>
<numberOfWhiskers>12</numberOfWhiskers>
</animal>
</root>
""".trimIndent(),
expected = RootObject(Cat(numberOfWhiskers = 12))
)
}
@XmlSerialName("root")
@Serializable
data class RootObject(
@XmlSerialName("animal")
@XmlElement val animal: Animal,
)
@Serializable
@XmlSerialName("animal")
sealed interface Animal
@Serializable
@SerialName("spider")
data class Spider(@XmlElement val numberOfEyes: Int) : Animal
@Serializable
@SerialName("cat")
data class Cat(@XmlElement val numberOfWhiskers: Int) : Animal
How do we decode this? I am trying many different things, but cannot figure it out. |
Beta Was this translation helpful? Give feedback.
-
I am totally confused about where I should be trying to do this with |
Beta Was this translation helpful? Give feedback.
-
Either way I get errors. I cannot pass this test. |
Beta Was this translation helpful? Give feedback.
-
Note I've edited the test code in the comment above many times. It should be good now as it is. |
Beta Was this translation helpful? Give feedback.
-
For context, I am working with a dataset that has polymorphism like this. I currently only need to decode this database, so encoding with this format is optional for me. |
Beta Was this translation helpful? Give feedback.
-
I haven't seen this particular case before, the type discriminator has to be an attribute as there is an order issue. Probably the best way to do this is to transform the xml (possibly using DOM that you then feed into a delegate (de)serializer) |
Beta Was this translation helpful? Give feedback.
-
Ok! I got this working for the simple case as you suggested. fun String.transformXMLTagToAttribute(
tagName: String
): String {
/*Parse the input XML string into a DOM document*/
val factory = DocumentBuilderFactory.newInstance()
val builder = factory.newDocumentBuilder()
val doc = builder.parse(InputSource(StringReader(this)))
/*Get a list of elements with the given tagName*/
val elements = doc.getElementsByTagName(tagName)
/*Iterate through the elements and perform the transformation*/
for (i in 0 until elements.length) {
val element = elements.item(i) as Element
val textContent = element.textContent
val parent = element.parentNode as Element
/*Remove the element*/
parent.removeChild(element)
/*Add an attribute to the parent element*/
parent.setAttribute(tagName, textContent)
}
/*Serialize the modified DOM document back to an XML string*/
val transformerFactory = TransformerFactory.newInstance()
val transformer = transformerFactory.newTransformer()
val writer = StringWriter()
transformer.transform(DOMSource(doc), StreamResult(writer))
return writer.toString()
} testFullCircle(
xml = """
<root>
<animal>
<species>spider</species>
<numberOfEyes>10</numberOfEyes>
</animal>
</root>
""".transformXMLTagToAttribute("species"),
expected = RootObject(Spider(numberOfEyes = 10))
) |
Beta Was this translation helpful? Give feedback.
-
The tests all pass. However, in the real world the XML files are gigantic. Each file multiple megabytes and there are thousands of files. Can I ask your advice for how I can apply this transformation only in a specific location in the document tree so that it doesn't parse the rest of the tree twice? I am looking at https://github.com/pdvrieze/xmlutil/blob/master/examples/DYNAMIC_TAG_NAMES.md . If I understand correctly, this is the most relevant documentation for what I am trying to do. The code there seems very complex relative to what I am trying to do, and also that code doesn't seem to be for polymorphic types which I think might have some different rules. What are your thoughts? Is the best I can do to try to adapt that guide to my use case? |
Beta Was this translation helpful? Give feedback.
-
@JsonClassDiscriminator allows for a custom type discriminator for one type hierarchy. Is there an equivalent feature for Xml? If not, I suggest it.
Beta Was this translation helpful? Give feedback.
All reactions