android - Kotlin - 使用 simpleXML 解析 xml 内联列表

标签 android kotlin retrofit2 simple-framework

我正在尝试使用 kotlin 中的 simplexml 解析 rss 提要。

提要是 top podcasts feed from itunes

返回的数据具有以下结构:

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Top Audio Podcasts</title>
    <link>https://rss.itunes.apple.com/api/v1/us/podcasts/top-podcasts/all/10/explicit.rss</link>
    <lastBuildDate>Fri, 13 Jul 2018 01:36:19 -0700</lastBuildDate>
    <atom:link rel="self" type="application/rss+xml" href="https://rss.itunes.apple.com/api/v1/us/podcasts/top-podcasts/all/10/explicit.rss"/>
    <atom:link rel="alternate" type="text/html" href="https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewTop?genreId=26&amp;popId=28"/>
    <description>iTunes Store : Top Audio Podcasts</description>
    <category>iTunes Store</category>
    <copyright>Copyright © 2018 Apple Inc. All rights reserved.</copyright>
    <item>
      <title>The Wilderness - Crooked Media</title>
      <category domain="">Crooked Media</category>
      <link>https://itunes.apple.com/us/podcast/the-wilderness/id1408796715?mt=2</link>
      <guid>https://itunes.apple.com/us/podcast/the-wilderness/id1408796715?mt=2</guid>
      <description>The Wilderness</description>
      <category>podcast</category>
      <category>News &amp; Politics</category>
      <category>Podcasts</category>
      <category>Society &amp; Culture</category>
      <category>History</category>
      <pubDate>Fri, 6 Jul 2018 00:00:00 +0000</pubDate>
    </item>
    <item>
      <title>Aaron Mahnke's Cabinet of Curiosities - HowStuffWorks &amp; Aaron Mahnke</title>
      <category domain="https://itunes.apple.com/us/artist/howstuffworks-aaron-mahnke/284341002?mt=2">HowStuffWorks &amp; Aaron Mahnke</category>
      <link>https://itunes.apple.com/us/podcast/aaron-mahnkes-cabinet-of-curiosities/id1396546917?mt=2</link>
      <guid>https://itunes.apple.com/us/podcast/aaron-mahnkes-cabinet-of-curiosities/id1396546917?mt=2</guid>
      <description>Aaron Mahnke's Cabinet of Curiosities</description>
      <category>podcast</category>
      <category>History</category>
      <category>Podcasts</category>
      <category>Society &amp; Culture</category>
      <pubDate>Tue, 10 Jul 2018 00:00:00 +0000</pubDate>
    </item>
  </channel>
</rss>

我关心的部分是项目标签包含的播客列表。

我的模型类是这样的:

@Root(name = "channel", strict = false)
data class Chart @JvmOverloads constructor(
        @field:ElementList(entry = "item", inline = true)
        @param:ElementList(entry = "item", inline = true)
        val podcasts: List<Entry>? = null)

@Root(name = "item", strict = false)
data class Entry @JvmOverloads constructor(
        @field:Element(name = "description")
        @param:Element(name = "description")
        val title: String? = null,

        @field:Element(name = "category")
        @param:Element(name = "category")
        val artist: String? = null,

        @field:Element(name = "guid")
        @param:Element(name = "guid")
        val guid: String? = null)

我有一个简单的单元测试,它从文件加载 xml,将其传递给 simplexml 反序列化器,然后将输出与某些预期模型进行比较。

在我运行测试时出现异常:

org.simpleframework.xml.core.ValueRequiredException: Unable to satisfy @org.simpleframework.xml.ElementList(entry=item, inline=true, data=false, name=, type=void, required=true, empty=true) on field 'podcasts' private final java.util.List Chart.podcasts for class Chart at line 2

将 required = false 添加到 @ElementList 注释可消除此错误,但反序列化器会为列表返回 null。

我最好的猜测是反序列化器无法找到项目列表,尽管根据我对@ElementList 的理解,使用输入字段应该允许它找到标签。

此代码的用例是形成依赖 Retrofit2 进行 REST 调用的 Android 应用的网络层。

感谢您对此提供的任何帮助。

注意:@Param 和@Field 声明的使用是为了对抗不同的异常,I got the idea from this question

最佳答案

我找到了解决方案。

所以第一个问题是我的根元素不是代表 channel 标签的图表,我需要一个包装类,我称之为 ChartFeed 来代表 rss 标签。

我通过在同样无法找到的图表对象上为标题标签添加一个元素来实现这一点。

我完成的数据类如下所示:

@Root(name = "rss", strict = false)
data class ChartFeed(
        @field:Element(name = "channel")
        @param:Element(name = "channel")
        val chart: Chart? = null)

@Root(name = "channel", strict = false)
data class Chart @JvmOverloads constructor(
        @field:ElementList(entry = "item", inline = true)
        @param:ElementList(entry = "item", inline = true)
        val podcasts: List<Entry>? = null)

@Root(name = "item", strict = false)
data class Entry @JvmOverloads constructor(
        @field:Path("description")
        @field:Text(required = false)
        @param:Path("description")
        @param:Text(required = false)
        val title: String? = null,

        @field:Path("category")
        @field:Text(required = false)
        @param:Path("category")
        @param:Text(required = false)
        val artist: String? = null,

        @field:Element(name = "guid")
        @param:Element(name = "guid")
        val guid: String? = null)

我已经将一些字段/参数的@Element 标记更改为@Path 和@Text 的组合,这是因为 channel 和项目 xml 对象重用了导致此异常的相同标记:

org.simpleframework.xml.core.PersistenceException: Element 'category' is already used with @org.simpleframework.xml.Element(name=category, type=void, data=false, required=true) on field 'artist' private final java.lang.String Entry.artist at line 18

我用的方案很详细here

关于android - Kotlin - 使用 simpleXML 解析 xml 内联列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51336777/

相关文章:

android - 使Google Api level 10项目在android 2.3.4/6上运行

android - 如何在 Kotlin 中将 ArrayList 转换为 JSONArray()

android - 改造第一个请求需要精确的 OkHttpClient 超时

android - 发布于改造

java - setContentView 抛出错误 NoClassDefFoundError

android - ViewPager 不显示任何内容

android - 在 Android 上的数据库中存储资源 ID 的最佳方式

android - kotlin Lateinit 与计算属性

java - 链接 Activity 会导致 OOM

android - 在 Retrofit 2 中传递 API key - Android Studio