Kotlin - 使用 SimpleXML 解析带有列表的 XML 响应



我正在尝试解析来自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
)
}

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

根据文档,该库通过使用带有 field/getter/setter 注释的空构造函数或使用构造函数注入 + getter 注释来工作。

在第一种情况下,您需要摆脱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)])])))])

最新更新