Parsing xml kotlin android

2019-02-28 04:06发布

问题:

I have xml like this:

<horo>
<aries>
<today>
Сегодня вас могут здорово огорчить. Если от расстройства все начнет валится из рук, просто спокойно сядьте и тихонько подождите хорошей новости.
</today>
</aries>
<taurus>
<today>
Сегодня у вас могут возникнуть проблемы на личном фронте. Спасти вас от перспективы оказаться не у дел может сухой, рациональный и в высшей степени объективный подход к проблеме.
</today>
</taurus>
</horo>

And now i learning kotlin whith retrofit. I include libraries for parse xml, and not i cant understand how create object for parsing this xml. I have object:

@Root(name = "horo", strict = false)
open class DailyHoroscope{
    @get : Element(name = "aries") var aries : Aries? = null
}

@Root(name = "aries", strict = false)
open class Aries{
    @get : Element(name = "today") var today : String? = null
}

but i have error:

rg.simpleframework.xml.core.ConstructorException: Default constructor can not accept read only @org.simpleframework.xml.Element(data=false, name=aries, required=true, type=void) on method 'aries' in class ac.kotlintest.model.

upd

i writed code in java:

@Root(name = "horo", strict = false)
public class DailyHoroscopeJ {
    @Element(name = "aries")
    public Aries aries;

    public Aries getAries() {
        return aries;
    }

    public void setAries(Aries aries) {
        this.aries = aries;
    }
}

@Root(name = "aries", strict = false)
 class Aries{
    @Element(name = "today")
    public String today;

    public String getToday() {
        return today;
    }

    public void setToday(String today) {
        this.today = today;
    }
}

and it work fine, then i convert to kotlin

@Root(name = "horo", strict = false)
class DailyHoroscope {
    @get:Element(name = "aries")
    var aries:Aries? = null
}
@Root(name = "aries", strict = false) class Aries {
    @get:Element(name = "today")
    var today:String? = null
}

but i have same problem((((

回答1:

The answer of @daementus is almost perfect. If you want to use constructor injection with default parameters, you have to force Kotlin to generate constructor overloads:

data class Section @JvmOverloads constructor(

    @field:Element(name = "id")
    @param:Element(name = "id")
    val id: Long,

    @field:Attribute(name = "title", required = false)
    @param:Attribute(name = "title", required = false)
    val title: String = ""
)

Without it you will get Constructor not matched for class Section. By default Kotlin generates a constructor with all parameters and a special constructor.

Note: I would prefer to answer in the comments but I don't have enough points.



回答2:

Indeed, Simple XML Framework has a few problems with Kotlin attributes and it can be a little tricky to get things to work.

To be honest, I am not quite sure what is the problem in your specific case, but I'd guess that the annotation shouldn't be specified for the getter, but rather for the field.

Anyway, I am combining Simple XML and Kotlin data classes this way, and it seems to be working fine :)

data class Section (

    @field:Element(name = "id", required = false)
    @param:Element(name = "id", required = false)
    val id: Long? = null,

    @field:Attribute(name = "title", required = false)
    @param:Attribute(name = "title", required = false)
    val title: String? = null
)

Edit: If you don't want to use data classes (which I highly recommend, but you might have a reason), this should work without the "data" keyword just fine. If you don't wish to create a constructor, just move the attribute declarations directly into the class and get rid of the @param annotation (the @field must stay).