pdvrieze / xmlutil

XML Serialization library for Kotlin
https://pdvrieze.github.io/xmlutil/
Apache License 2.0
363 stars 30 forks source link

XML NameSpace Prefix is incorrect for Non-Null Attribute #179

Closed LogeswaranRamasamy closed 6 months ago

LogeswaranRamasamy commented 10 months ago

When we try to add Namespace for an non-nullable Xml attribute it doesn't update properly. For instance, whenever I try to add namespace attribute for the below non-nullable xml Attribute, namespace is missing in the serialised xml.

Sample Xml using which XML Data classes were Defined:

<ns:breakfast_menu xmlns:ns="https://schema.restaurant.info">
<ns:food ns:istasty="false">
<name>Belgian Waffles</name>
<price>$5.95</price>
<description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
<calories>650</calories>
</ns:food>
<ns:food ns:istasty="false">
<name>Strawberry Belgian Waffles</name>
<price>$7.95</price>
<description>Light Belgian waffles covered with strawberries and whipped cream</description>
<calories>900</calories>
</ns:food>
</ns:breakfast_menu>

Code containing Data Classes & Xml serialization Logic:

import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import nl.adaptivity.xmlutil.ExperimentalXmlUtilApi
import nl.adaptivity.xmlutil.XmlDeclMode
import nl.adaptivity.xmlutil.serialization.*

class NameSpaceSerialiserIssue {

    val resourceDir = "src/files/testfiles/"
    val outputDir = "src/files/outputfiles/"

    @OptIn(ExperimentalXmlUtilApi::class)
    val xmlpolicy = DefaultXmlSerializationPolicy(false, unknownChildHandler = XmlConfig.IGNORING_UNKNOWN_CHILD_HANDLER)

    @OptIn(ExperimentalXmlUtilApi::class)
    fun getXmlConfig() = XML() {
        xmlDeclMode = XmlDeclMode.Charset
        autoPolymorphic = true
        repairNamespaces = true
        indentString = "    "
        indent = 1
        policy = xmlpolicy
    }

    @Serializable
    @XmlSerialName("breakfast_menu", "https://schema.restaurant.info", "ns")
    data class FoodMenu (
        @XmlSerialName("food", "https://schema.restaurant.info", "ns" )
        var foodList : MutableList<Food> ?= null
    )

    data class ExampleJson2KtKotlin (
        @XmlSerialName("breakfast_menu", "", "")
        var breakfastMenu : FoodMenu
    )

    @Serializable
    @XmlSerialName("food", "https://schema.restaurant.info", "ns" )
    data class Food (
        @XmlElement(false)
        @XmlSerialName("istasty", "https://schema.restaurant.info", "ns" )
        var istasty : String,
        @XmlElement(true)
        @XmlSerialName("name", "", "")
        var name : String? = null,
        @XmlElement(true)
        @XmlSerialName("price", "", "")
        var price : String? = null,
        @XmlElement(true)
        @XmlSerialName("description", "", "")
        var description : String? = null,
        @XmlElement(true)
        @XmlSerialName("calories","", "")
        var calories : Int?= null
    )

    fun createNewFood() : ByteArray{
        var newFood :Food = Food(istasty = "true")
        newFood.istasty="true"
        var foodList :  MutableList<Food> =  mutableListOf<Food>(newFood)
        var foodRoot : FoodMenu = FoodMenu(foodList)

        val foodMenu = getXmlConfig().encodeToString<FoodMenu>(foodRoot)
        return foodMenu.toByteArray(Charsets.UTF_8)
    }
}

Main function:

@Test
    fun xmlNameSpaceIssueSerialiser() = runBlocking {       
        val bytes= NameSpaceSerialiserIssue().createNewFood()
        createFile(bytes, name = "xmlNameSpaceIssue", extension = "xml")        
    }

Output XML generated:

<?xml version="1.1" encoding="UTF-8"?>
<ns:breakfast_menu xmlns:ns="https://schema.restaurant.info">
 <ns:food istasty="true"/>
</ns:breakfast_menu>

As u can see the "istasty" attribute doesn't contain the namespace which I had denoted in my data class. But if try to give a wrong(i.e Different namespace) compared to it's element "ns:food", then the prefix "ns:istasty" is appearing fine in generated xml.

Change in Data Class:

@Serializable
    @XmlSerialName("food", "https://schema.restaurant.info", "ns" )
    data class Food (
        @XmlElement(false)
        @XmlSerialName("istasty", "https://schema.restaurant.info", "wrongnamespacePrefix" )
        var istasty : String,
        @XmlElement(true)
        @XmlSerialName("name", "", "")
        var name : String? = null,
        @XmlElement(true)
        @XmlSerialName("price", "", "")
        var price : String? = null,
        @XmlElement(true)
        @XmlSerialName("description", "", "")
        var description : String? = null,
        @XmlElement(true)
        @XmlSerialName("calories","", "")
        var calories : Int?= null
    )

Generated output with the correct namespace for "istasty" attribute:

<?xml version="1.1" encoding="UTF-8"?>
<ns:breakfast_menu xmlns:ns="https://schema.restaurant.info">
 <ns:food ns:istasty="true"/>
</ns:breakfast_menu>

Kindly can u provide fix for the same.

pdvrieze commented 10 months ago

Could you have a look at the snapshot release. There were some errors in attribute namespace handling (attributes without prefix are always in the null namespace per the standard). The snapshot should have (already) fixed that.

pdvrieze commented 6 months ago

This should now have been fixed in 0.86.3