Kotlin-使用SimpleXml分析带有列表的Xml响应

问题描述 投票:0回答:1

我正在尝试从API解析XML响应,并且“字段”元素列表有问题。我正在尝试在元素内部创建属性和文本的Field对象,例如该对象的属性,并且找不到要用于元素文本的注释。我尝试使用

  @get:Text
  @set:Text

@field:Text

但有相同的错误

java.lang.RuntimeException: org.simpleframework.xml.core.PersistenceException: Constructor not matched for class NetworkTestContainer$Field

有人可以为此情况给我一个适当的注释吗?

具有XML结构:

<response>
<commands>
    <command>
        <nick>QUEUECAUSES_LIST</nick>
        <result>
            <DATASET Version="1.0" Class="TQueryAdv" Name="">
                <Row Index="1">
                    <Field Name="SHOPID" Type="6" Size="0">-1</Field>
                    <Field Name="IDCODE" Type="6" Size="0">3000000000001</Field>
                    <Field Name="CAPTION" Type="1" Size="255">Консультация</Field>
                    <Field Name="PRIORITY" Type="6" Size="0">0</Field>
                </Row>
                <Row Index="2">
                    <Field Name="SHOPID" Type="6" Size="0">-1</Field>
                    <Field Name="IDCODE" Type="6" Size="0">3000000000021</Field>
                    <Field Name="CAPTION" Type="1" Size="255">Очередь</Field>
                    <Field Name="PRIORITY" Type="6" Size="0">1</Field>
                </Row>
            </DATASET>
        </result>
    </command>
</commands>
</response>

这里是模特

@Root(name = "response", strict = false)
data class NetworkTestContainer(
    @field:ElementList(name = "commands")
    val commands : List<Command>
) {
    @Root(name = "command", strict = false)
    data class Command(
        @field:Element
        val nick : String,
        @field:Element(name = "result")
        val result : Result
    )

    @Root(name = "result", strict = false)
    data class Result(
        @field:Element(name = "DATASET")
        val dataSet: DataSet
    )

    @Root(name = "DATASET", strict = false)
    data class DataSet(
        @field:Attribute(name = "Version")
        val version : String,

        @field:Attribute(name = "Class")
        val className : String,

        @field:Attribute(name = "Name")
        val Name : String,

        @field:ElementList(inline = true)
        val rows : List<Row>
    )

    @Root(name = "Row", strict = false)
    data class Row(
        @field:Attribute(name = "Index")
        val index : Int,

        @field:ElementList(inline = true, entry = "Field")
        val fields: List<Field>

//        @field:ElementMap(attribute = true, entry = "Field", key = "Name", inline = true)
//        val fields : Map<String, String>
    )

    @Root(name = "Field", strict = false)
    data class Field (
        @field:Attribute(name = "Name", required = false)
        val key : String,

        @field:Attribute(name = "Type", required = false)
        val type : Int,

        @field:Attribute(name = "Size", required = false)
        val size : Int,

        @get:Text
        @set:Text
        var text : String
    )
}
kotlin retrofit simplexml
1个回答
0
投票

我对这个库不熟悉,但是我尝试调试它,这是我的发现。

根据the documentation,该库通过使用带有字段/获取器/设置器注释的空构造函数或通过使用构造函数注入+吸收器注释来工作。

在第一种情况下,在创建对象时,您需要摆脱data修饰符并使用@field:批注,再加上lateinit var或其他方法来初始化所有字段。示例:

import org.simpleframework.xml.Attribute
import org.simpleframework.xml.Element
import org.simpleframework.xml.ElementList
import org.simpleframework.xml.Root
import org.simpleframework.xml.core.Persister


@Root(name = "response", strict = false)
class NetworkTestContainer {
    @field:ElementList(name = "commands")
    lateinit var commands: List<Command>
    override fun toString(): String {
        return "NetworkTestContainer(commands=$commands)"
    }

}

@Root(name = "command", strict = false)
class Command {
    @field:Element(name = "nick")
    lateinit var nick: String

    @field:Element(name = "result")
    lateinit var result: Result
    override fun toString(): String {
        return "Command(nick='$nick', result=$result)"
    }


}

@Root(name = "result", strict = false)
class Result {
    @field:Element(name = "DATASET")
    lateinit var dataSet: DataSet
    override fun toString(): String {
        return "Result(dataSet=$dataSet)"
    }


}

@Root(name = "DATASET", strict = false)
class DataSet {
    @field:Attribute(name = "Version")
    lateinit var version: String

    @field:Attribute(name = "Class")
    lateinit var className: String

    @field:Attribute(name = "Name")
    lateinit var name: String

    @field:ElementList(inline = true)
    lateinit var rows: List<Row>
    override fun toString(): String {
        return "DataSet(version='$version', className='$className', name='$name', rows=$rows)"
    }


}

@Root(name = "Row", strict = false)
class Row {
    @field:Attribute(name = "Index")
    var index: Int = 0

    @field:ElementList(inline = true, entry = "Field")
    lateinit var fields: List<Field>
    override fun toString(): String {
        return "Row(index=$index, fields=$fields)"
    }

//        @field:ElementMap(attribute = true, entry = "Field", key = "Name", inline = true)
//        val fields : Map<String, String>


}

@Root(name = "Field", strict = false)
class Field {
    @field:Attribute(name = "Name", required = false)
    lateinit var key: String

    @field:Attribute(name = "Type", required = false)
    var type: Int = 0

    @field:Attribute(name = "Size", required = false)
    var size: Int = 0
    override fun toString(): String {
        return "Field(key='$key', type=$type, size=$size)"
    }


}


object Main {

    @JvmStatic
    fun main(args: Array<String>) {
        val deserializer = Persister()
        val file = Main::class.java.getResourceAsStream("input.xml")
        val container = deserializer.read(NetworkTestContainer::class.java, file)
        println(container)
    }
}

此打印:

NetworkTestContainer(commands=[Command(nick='QUEUECAUSES_LIST', result=Result(dataSet=DataSet(version='1.0', className='TQueryAdv', name='', rows=[Row(index=1, fields=[Field(key='SHOPID', type=6, size=0), Field(key='IDCODE', type=6, size=0), Field(key='CAPTION', type=1, size=255), Field(key='PRIORITY', type=6, size=0)]), Row(index=2, fields=[Field(key='SHOPID', type=6, size=0), Field(key='IDCODE', type=6, size=0), Field(key='CAPTION', type=1, size=255), Field(key='PRIORITY', type=6, size=0)])])))])

如您所见,这并不理想,但是可以。

一种可能更好的方法涉及使用构造函数注入,这也需要带注释的getter或字段(如上面链接的文档中所指定)。

为了做到这一点,您需要使用@param:批注(因为您需要注释构造函数参数)和@get:批注(因为您需要注释getter)。示例:

import org.simpleframework.xml.Attribute
import org.simpleframework.xml.Element
import org.simpleframework.xml.ElementList
import org.simpleframework.xml.Root
import org.simpleframework.xml.Text
import org.simpleframework.xml.core.Persister


@Root(name = "response", strict = false)
data class NetworkTestContainer(
        @param:ElementList(name = "commands")
        @get:ElementList(name = "commands")
        val commands: List<Command>
) {
    @Root(name = "command", strict = false)
    data class Command(
            @param:Element(name="nick")
            @get:Element(name="nick")
            val nick: String,
            @param:Element(name = "result")
            @get:Element(name = "result")
            val result: Result
    )

    @Root(name = "result", strict = false)
    data class Result(
            @param:Element(name = "DATASET")
            @get:Element(name = "DATASET")
            val dataSet: DataSet
    )

    @Root(name = "DATASET", strict = false)
    data class DataSet(
            @param:Attribute(name = "Version")
            @get:Attribute(name = "Version")
            val version: String,

            @param:Attribute(name = "Class")
            @get:Attribute(name = "Class")
            val className: String,

            @param:Attribute(name = "Name")
            @get:Attribute(name = "Name")
            val Name: String,

            @param:ElementList(inline = true)
            @get:ElementList(inline = true)
            val rows: List<Row>
    )

    @Root(name = "Row", strict = false)
    data class Row(
            @param:Attribute(name = "Index")
            @get:Attribute(name = "Index")
            val index: Int,

            @param:ElementList(inline = true, entry = "Field")
            @get:ElementList(inline = true, entry = "Field")
            val fields: List<Field>

//        @field:ElementMap(attribute = true, entry = "Field", key = "Name", inline = true)
//        val fields : Map<String, String>
    )

    @Root(name = "Field", strict = false)
    data class Field(
            @param:Attribute(name = "Name", required = false)
            @get:Attribute(name = "Name", required = false)
            val key: String,

            @param:Attribute(name = "Type", required = false)
            @get:Attribute(name = "Type", required = false)
            val type: Int,

            @param:Attribute(name = "Size", required = false)
            @get:Attribute(name = "Size", required = false)
            val size: Int
    )
}

object Main {

    @JvmStatic
    fun main(args: Array<String>) {
        val deserializer = Persister()
        val file = Main::class.java.getResourceAsStream("input.xml")
        val container = deserializer.read(NetworkTestContainer::class.java, file)
        println(container)
    }
}

这将打印出与上述相同的内容(除了字符串的某些样式差异之外:]

NetworkTestContainer(commands=[Command(nick=QUEUECAUSES_LIST, result=Result(dataSet=DataSet(version=1.0, className=TQueryAdv, Name=, rows=[Row(index=1, fields=[Field(key=SHOPID, type=6, size=0), Field(key=IDCODE, type=6, size=0), Field(key=CAPTION, type=1, size=255), Field(key=PRIORITY, type=6, size=0)]), Row(index=2, fields=[Field(key=SHOPID, type=6, size=0), Field(key=IDCODE, type=6, size=0), Field(key=CAPTION, type=1, size=255), Field(key=PRIORITY, type=6, size=0)])])))])
© www.soinside.com 2019 - 2024. All rights reserved.