summaryrefslogtreecommitdiff
path: root/app/src/main/java/org/terst/feedreader/opml/Opml.kt
blob: 65510fb3da2cbf842083ace3f31b8a04337f28d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package org.terst.feedreader.opml

import android.util.Xml
import org.terst.feedreader.data.FeedEntity
import org.xmlpull.v1.XmlPullParser
import java.io.InputStream
import java.io.OutputStream

data class OpmlFeed(val title: String, val xmlUrl: String, val htmlUrl: String?)

/**
 * OPML import/export. Any folder nesting (<outline> containing other
 * <outline> elements instead of an xmlUrl) is flattened -- this app has no
 * folder concept, per the "simple design" scope, so a folder's contents
 * are just imported as a flat list of feeds.
 */
object Opml {

    fun parse(input: InputStream): List<OpmlFeed> {
        val parser = Xml.newPullParser()
        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false)
        parser.setInput(input, null)

        val feeds = mutableListOf<OpmlFeed>()
        var eventType = parser.eventType
        while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG && parser.name.equals("outline", ignoreCase = true)) {
                val xmlUrl = parser.getAttributeValue(null, "xmlUrl")
                if (xmlUrl != null) {
                    val title = parser.getAttributeValue(null, "title")
                        ?: parser.getAttributeValue(null, "text")
                        ?: xmlUrl
                    val htmlUrl = parser.getAttributeValue(null, "htmlUrl")
                    feeds += OpmlFeed(title, xmlUrl, htmlUrl)
                }
            }
            eventType = parser.next()
        }
        return feeds
    }

    fun write(feeds: List<FeedEntity>, output: OutputStream) {
        val serializer = Xml.newSerializer()
        serializer.setOutput(output, "UTF-8")
        serializer.startDocument("UTF-8", true)
        serializer.startTag(null, "opml")
        serializer.attribute(null, "version", "2.0")

        serializer.startTag(null, "head")
        serializer.startTag(null, "title")
        serializer.text("Feeds subscriptions")
        serializer.endTag(null, "title")
        serializer.endTag(null, "head")

        serializer.startTag(null, "body")
        for (feed in feeds) {
            serializer.startTag(null, "outline")
            serializer.attribute(null, "text", feed.title)
            serializer.attribute(null, "title", feed.title)
            serializer.attribute(null, "type", "rss")
            serializer.attribute(null, "xmlUrl", feed.id)
            feed.siteUrl?.let { serializer.attribute(null, "htmlUrl", it) }
            serializer.endTag(null, "outline")
        }
        serializer.endTag(null, "body")

        serializer.endTag(null, "opml")
        serializer.endDocument()
        serializer.flush()
    }
}