xmlutil
xmlutil copied to clipboard
Multiple element attributes
My goal is to build something similar to this:
<MyXml
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:OECD:MyXmlFile"
xsi:schemaLocation="urn:OECD:MyXmlFile.xsd">
</MyXml>
But with XmlSerialName
annotation I can only have 1 namespace. How can I add more than one? I don't see an option to add custom attributes to an element, that would solve the issue too.
The way the system works is that namespaces are handled automatically (although not necessarily optimally - it doesn't look at what other namespaces may be used by child tags - but will use prefixes found in the document). What you can do is have a custom serializer for the outer tag and in that serializer (if you find that the encoder implements Xml.XmlOutput
you can then use the target property to get the xml writer. Write the container using the regular encoder beginStructure... functions, write the additional attributes, and serialize the children using the encoder. Of course you can set the namespace on the schemaLocation attribute and then it should work automatically.
Can you make an example of both scenarios? I understand the idea, but having some issues putting it in place.
I've just pushed an example to dev to show how it works (note that it uses the @XmlBefore
annotation (that is not released yet) - but merely as an example for how to fine-tune things. It works fine without, but the order could be different for the attributes.
https://github.com/pdvrieze/xmlutil/blob/dev/examples/src/main/kotlin/net/devrieze/serialization/examples/customserializer/MyXmlManual.kt
To be honest it's quite dirty solution imo. It would be great if we could somehow provide multiple namespaces through an annotation, without a need to implement whole serializer 🤔
At this moment I'm playing around something like this, as I can't achieve it though annotations:
@Serializable
@SerialName("metadata")
internal data class Metadata(
@XmlElement(false)
val xmlns: String = "http://maven.apache.org/METADATA/1.1.0",
@XmlElement(false)
@SerialName("xmlns:xsi")
val xmlnsXsi: String = "http://www.w3.org/2001/XMLSchema-instance",
@XmlElement(false)
@SerialName("xsi:schemaLocation")
val xsiSchemaLocation: String = "http://maven.apache.org/METADATA/1.1.0 http://maven.apache.org/xsd/metadata-1.1.0.xsd",
)
The output is correct:
<?xml version='1.0' encoding='UTF-8'?>
<metadata xmlns="http://maven.apache.org/METADATA/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/METADATA/1.1.0 http://maven.apache.org/xsd/metadata-1.1.0.xsd">
</metadata>
But unfortunately I'm not able to load this:
Could not find a field for name {http://www.w3.org/2001/XMLSchema-instance}schemaLocation
candidates: xmlns, xmlns:xsi, xsi:schemaLocation, groupId, artifactId, version, versioning at position [row,col {unknown-source}]: [2,1]
nl.adaptivity.xmlutil.serialization.UnknownXmlFieldException: Could not find a field for name {http://www.w3.org/2001/XMLSchema-instance}schemaLocation
candidates: xmlns, xmlns:xsi, xsi:schemaLocation, groupId, artifactId, version, versioning at position [row,col {unknown-source}]: [2,1]
at nl.adaptivity.xmlutil.serialization.XmlConfig$Companion$DEFAULT_UNKNOWN_CHILD_HANDLER$1.invoke(XmlConfig.kt:191)
at nl.adaptivity.xmlutil.serialization.XmlConfig$Companion$DEFAULT_UNKNOWN_CHILD_HANDLER$1.invoke(XmlConfig.kt:187)
at nl.adaptivity.xmlutil.serialization.DefaultXmlSerializationPolicy.handleUnknownContent(XmlSerializationPolicy.kt:217)
at nl.adaptivity.xmlutil.serialization.XmlConfig$unknownChildHandler$1.invoke(XmlConfig.kt:100)
at nl.adaptivity.xmlutil.serialization.XmlConfig$unknownChildHandler$1.invoke(XmlConfig.kt:47)
at nl.adaptivity.xmlutil.serialization.XmlDecoderBase$TagDecoder.indexOf(XMLDecoder.kt:474)
at nl.adaptivity.xmlutil.serialization.XmlDecoderBase$TagDecoder.decodeElementIndex(XMLDecoder.kt:513)
I'm also not able to use it as a final fields outside of the constructor. Do you think I can somehow do something like this, even a little dirty, without implementing custom serializer?
The example would be better when using the following:
@Serializable
@XmlSerialName("metadata", "http://maven.apache.org/METADATA/1.1.0", "")
internal data class Metadata(
@XmlElement(false)
@XmlSerialName("schemaLocation", "http://www.w3.org/2001/XMLSchema-instance", "xsi")
val xsiSchemaLocation: String = "http://maven.apache.org/METADATA/1.1.0 http://maven.apache.org/xsd/metadata-1.1.0.xsd",
)
You shouldn't specify namespaces (or prefixes) using @SerialName
as that will not work correctly. The way namespaces work is that the parsing doesn't/shouldn't care about the prefix used. This format is designed with namespaces, so ignoring namespaces is not likely to work. Specifying a namespace as a property cannot be correct as namespaces should not be variable.