Kotlin + SimpleXMLElement + 地图子列表元素

Kotlin + SimpleXMLElement + Map sublist element

我正在使用 Kotlin 开发 Android 应用程序。我需要消耗一个 API 一个 returns 一个 XML 到一个请求。

例如返回的XML是:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <ListaEmpresasResponse xmlns="http://example.com/">
         <ListaEmpresasResult>
            <IdEstado>001</IdEstado>
            <Mensaje/>
            <Empresas>
               <Empresa>
                  <IdEmpresas>1</IdEmpresas>
                  <Nombre>Test 1</Nombre>
               </Empresa>
               <Empresa>
                  <IdEmpresas>2</IdEmpresas>
                  <Nombre>Test2</Nombre>
               </Empresa>
               <Empresa>
                  <IdEmpresas>4</IdEmpresas>
                  <Nombre>Test 3</Nombre>
               </Empresa>
               <Empresa>
                  <IdEmpresas>5</IdEmpresas>
                  <Nombre>Test 4</Nombre>
               </Empresa>
            </Empresas>
         </ListaEmpresasResult>
      </ListaEmpresasResponse>
   </soap:Body>
</soap:Envelope>

我能够解析 IdEstado 和 Mensaje 字段,但我需要创建一个包含名为 "Empresa" 的元素的列表。

我有一个名为 mapper.kt

的文件
interface Mapper<in R, out T> {

    fun transform(input: R): T
    fun transformList(inputList: List<R>): List<T>

}

我有一个名为 DatosTrabajoResponseEmpresaEntityMapper.kt

的文件
import com.example.smt.data.model.datostrabajo.DatosTrabajoResponseEmpresaEntity
import com.example.smt.data.model.datostrabajo.DatosTrabajoResponseEmpresaEntityEmpresa
import com.example.smt.data.model.datostrabajo.DatosTrabajoResponseEmpresaEnvelope
import com.example.smt.data.model.datostrabajo.Empresa
import kotlinx.android.synthetic.main.activity_datostrabajo.view.*

class DatosTrabajoResponseEmpresaEntityMapper: Mapper<DatosTrabajoResponseEmpresaEnvelope, DatosTrabajoResponseEmpresaEntity> {

    override fun transform(input: DatosTrabajoResponseEmpresaEnvelope): DatosTrabajoResponseEmpresaEntity {
        return DatosTrabajoResponseEmpresaEntity(
            input.body!!.listaEmpresasResponse!!.listaEmpresasResult!!.resultCode,
            input.body!!.listaEmpresasResponse!!.listaEmpresasResult!!.message,
            null<-- This is where i should parse the sublist where i'm not able to.
        )
    }




    override fun transformList(inputList: List<DatosTrabajoResponseEmpresaEnvelope>): List<DatosTrabajoResponseEmpresaEntity> {
        return inputList.map { transform(it) }
    }

}

class DatosTrabajoResponseEmpresaEntityMapperEmpresa: Mapper<Empresa, DatosTrabajoResponseEmpresaEntityEmpresa>{
    override fun transform(input: Empresa): DatosTrabajoResponseEmpresaEntityEmpresa {
        return DatosTrabajoResponseEmpresaEntityEmpresa(
            input.idEmpresas,
            input.nombre
        )
    }

    override fun transformList(inputList: List<Empresa>): List<DatosTrabajoResponseEmpresaEntityEmpresa> {
        return inputList.map { transform(it) }
    }
}

我定义结构的响应文件 DatosTrabajoResponseEmpresa.kit 是:

import org.simpleframework.xml.Element
import org.simpleframework.xml.Namespace
import org.simpleframework.xml.NamespaceList
import org.simpleframework.xml.Root
import org.simpleframework.xml.ElementList



@Root(name = "soap:Envelope")
@NamespaceList(
    Namespace(prefix = "soap", reference = "http://schemas.xmlsoap.org/soap/envelope/"),
    Namespace(prefix = "xsi", reference = "http://www.w3.org/2001/XMLSchema-instance"),
    Namespace(prefix = "xsd", reference = "http://www.w3.org/2001/XMLSchema")
)
class DatosTrabajoResponseEmpresaEnvelope {
    @field:Element(name = "Body", required = false)
    var body: DatosTrabajoResponseEmpresaBody? = null
}

@Root(name = "soap:Body", strict = false)
class DatosTrabajoResponseEmpresaBody {
    @field:Element(name = "ListaEmpresasResponse", required = false)
    var listaEmpresasResponse: ListaEmpresasResponse? = null
}

@Root(name = "ListaEmpresasResponse", strict = false)
class ListaEmpresasResponse {
    @field:Element(name = "ListaEmpresasResult", required = false)
    var listaEmpresasResult: ListaEmpresasResult? = null
}

@Root(name = "ListaEmpresasResult", strict = false)
class ListaEmpresasResult {
    @field:Element(name = "IdEstado", required = false)
    var resultCode: String? = null

    @field:Element(name = "Mensaje", required = false)
    var message: String? = null

    @field:ElementList(name = "Empresas", required = false)
    var empresas: List<Empresa>? = null

}

@Root(name = "Empresa", strict = false)
class Empresa {
    @field:Element(name = "IdEmpresas", required = false)
    var idEmpresas: Int? = null

    @field:Element(name = "Nombre", required = false)
    var nombre: String? = null
}

最后这是我的实体文件 DatosTrabajoResponseEmpresaEntity.kt:

import android.annotation.SuppressLint
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize

@SuppressLint("ParcelCreator")
@Parcelize
data class DatosTrabajoResponseEmpresaEntityEmpresa(
    val idEmpresas: Int?,
    val nombre: String?
) : Parcelable

@SuppressLint("ParcelCreator")
@Parcelize
data class DatosTrabajoResponseEmpresaEntity(
    val resultCode: String?,
    val message: String?,
    val empresas: List<DatosTrabajoResponseEmpresaEntityEmpresa?>
) : Parcelable

最后我希望在我的实体中有一个属性列表列表我的问题是我试图解析它但无法解析。如果有任何帮助,我将不胜感激。

如果您有能力使用 beautifulsoup 代替 java/kotlin,那就容易多了。我用它以一种非常简单的方式解析来自 openstreetmaps 的 xml 文件,例如 python。库的名称是 Jsoup。

在此 link (https://jsoup.org/download) you can see how to add it by graddle, maven and the jar to download. The usage is pretty straight-forward. This is an example from this (http://www.gitshah.com/2018/02/using-jsoup-with-kotlin-to-parse-html.html) 教程中:

import org.jsoup.Jsoup
import org.junit.Test

class JsoupTest {

    @Test
    fun shouldParseHTML() {
        //1. Fetching the HTML from a given URL
        Jsoup.connect("https://www.google.co.in/search?q=this+is+a+test").get().run {
            //2. Parses and scrapes the HTML response
            select("div.rc").forEachIndexed { index, element ->
                val titleAnchor = element.select("h3 a")
                val title = titleAnchor.text()
                val url = titleAnchor.attr("href")
                //3. Dumping Search Index, Title and URL on the stdout.
                println("$index. $title ($url)")
            }
        }
    }
}

不要忘记声明您想要使用 xml 解析器,就像这里所说的那样 (http://tonyjunkes.com/blog/parsing-xml-with-jsoup-in-cfml/)。

doc = Jsoup.parse(rawXML, "", Parser.xmlParser());

您可以使用验证器和使用 javafx 的方案来验证 xml,就像这里 (https://turreta.com/2018/06/24/kotlin-validate-xml-against-xsds/) 一样。

val factory: SchemaFactory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema")

val schemaLocation = File("/somewhere/xsd/myschema.xsd")
val schema = factory.newSchema(schemaLocation)
val validator = schema.newValidator()
val source = StreamSource("/somewhere/test-data/myxml-test.xml")

println("Validation Starts now!")

val start = System.currentTimeMillis()
try {
    validator.validate(source)
    println(" XML is valid.")
} catch (ex: SAXException) {
    println(" XML not valid because " + ex.message)
}

println("Validation complete!")

println("Time (ms): " + (System.currentTimeMillis() - start))

您也可以按照此处所述使用 Jackson,作为奖励,您可以获得数据类中的所有内容 (https://medium.com/@foxjstephen/how-to-actually-parse-xml-in-java-kotlin-221a9309e6e8). This is the jackson's repository: https://github.com/FasterXML/jackson

我想我找到了解决方案:

input.body!!.listaEmpresasResponse!!.listaEmpresasResult!!.empresas!!.map { it  }.map{ DatosTrabajoResponseEmpresaEntityEmpresa(it.idEmpresas, it.nombre) }