diff options
Diffstat (limited to 'app/src/main/java/org/terst/feedreader/data')
| -rw-r--r-- | app/src/main/java/org/terst/feedreader/data/FeedParser.kt | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/app/src/main/java/org/terst/feedreader/data/FeedParser.kt b/app/src/main/java/org/terst/feedreader/data/FeedParser.kt index 8b37e55..7a3ce93 100644 --- a/app/src/main/java/org/terst/feedreader/data/FeedParser.kt +++ b/app/src/main/java/org/terst/feedreader/data/FeedParser.kt @@ -43,6 +43,37 @@ object FeedParser { private fun decodeTitleEntities(text: String): String = Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY).toString() + // Atom's <content type="xhtml">/<summary type="xhtml"> wrap real nested markup + // (spec-legal: <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"> + // ...actual HTML...</div></content>) instead of a plain text leaf. XmlPullParser's + // nextText() requires the element to be text-only and throws XmlPullParserException + // the instant it hits that nested <div> -- uncaught, that aborted parsing of the + // ENTIRE feed over one xhtml-typed field, not just that one entry. Manually walks and + // reconstructs the inner markup as an HTML string instead, tracking depth against the + // parser's own getDepth() (not a separately-maintained counter) so it can't drift out + // of sync with what nextText() would have consumed. + private fun readElementAsHtml(parser: XmlPullParser): String { + val startDepth = parser.depth + val sb = StringBuilder() + var event = parser.next() + while (!(event == XmlPullParser.END_TAG && parser.depth == startDepth)) { + when (event) { + XmlPullParser.START_TAG -> { + sb.append('<').append(parser.name) + for (i in 0 until parser.attributeCount) { + sb.append(' ').append(parser.getAttributeName(i)).append("=\"") + .append(parser.getAttributeValue(i).replace("\"", """)).append('"') + } + sb.append('>') + } + XmlPullParser.END_TAG -> sb.append("</").append(parser.name).append('>') + XmlPullParser.TEXT, XmlPullParser.CDSECT -> sb.append(parser.text) + } + event = parser.next() + } + return sb.toString().trim() + } + fun parse(input: InputStream): ParsedFeed { val parser = Xml.newPullParser() parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false) @@ -187,8 +218,20 @@ object FeedParser { "name" -> if (inEntry && entryAuthor == null) entryAuthor = parser.nextText() "updated" -> if (inEntry) entryDate = parseIso8601Date(parser.nextText()) "published" -> if (inEntry) entryDate = parseIso8601Date(parser.nextText()) ?: entryDate - "content" -> if (inEntry) entryContent = parser.nextText() - "summary" -> if (inEntry) entrySummary = parser.nextText() + "content" -> if (inEntry) { + entryContent = if (parser.getAttributeValue(null, "type") == "xhtml") { + readElementAsHtml(parser) + } else { + parser.nextText() + } + } + "summary" -> if (inEntry) { + entrySummary = if (parser.getAttributeValue(null, "type") == "xhtml") { + readElementAsHtml(parser) + } else { + parser.nextText() + } + } "media:thumbnail" -> if (inEntry && entryImageUrl == null) { entryImageUrl = parser.getAttributeValue(null, "url") } |
