From 505ebc8a4e571cbc50eb5a5939b82fc7b0d83d6f Mon Sep 17 00:00:00 2001 From: Mitchell Skaggs Date: Sun, 25 Feb 2018 15:58:38 -0600 Subject: [PATCH 1/6] Added sample feed and namespace --- .../rss/namespaces/atom/elements/AtomRss.kt | 3 ++ .../github/magneticflux/rss/sample_atom.xml | 45 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomRss.kt create mode 100644 src/test/resources/com/github/magneticflux/rss/sample_atom.xml diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomRss.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomRss.kt new file mode 100644 index 0000000..d27106f --- /dev/null +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomRss.kt @@ -0,0 +1,3 @@ +package com.github.magneticflux.rss.namespaces.atom.elements + +const val ATOM_REFERENCE = "http://www.w3.org/2005/Atom" diff --git a/src/test/resources/com/github/magneticflux/rss/sample_atom.xml b/src/test/resources/com/github/magneticflux/rss/sample_atom.xml new file mode 100644 index 0000000..38a1d6b --- /dev/null +++ b/src/test/resources/com/github/magneticflux/rss/sample_atom.xml @@ -0,0 +1,45 @@ + + + dive into mark + + A <em>lot</em> of effort + went into making this effortless + + 2005-07-31T12:29:29Z + tag:example.org,2003:3 + + + Copyright (c) 2003, Mark Pilgrim + + Example Toolkit + + + Atom draft-07 snapshot + + + tag:example.org,2003:3.2397 + 2005-07-31T12:29:29Z + 2003-12-13T08:29:29-04:00 + + Mark Pilgrim + http://example.org/ + f8dy@example.com + + + Sam Ruby + + + Joe Gregorio + + +
+

+ [Update: The Atom draft is finished.] +

+
+
+
+
From 3f233c5c61790dcbceab5bcde015dbf3f531239c Mon Sep 17 00:00:00 2001 From: Mitchell Skaggs Date: Sun, 25 Feb 2018 16:49:45 -0600 Subject: [PATCH 2/6] Added atom:author element parsing --- .../com/github/magneticflux/rss/Converters.kt | 10 +++- .../com/github/magneticflux/rss/Persisters.kt | 10 +++- .../atom/converters/AtomAuthorConverter.kt | 40 +++++++++++++++ .../atom/converters/AtomFeedConverter.kt | 34 +++++++++++++ .../namespaces/atom/elements/AtomAuthor.kt | 50 +++++++++++++++++++ .../rss/namespaces/atom/elements/AtomFeed.kt | 46 +++++++++++++++++ .../com/github/magneticflux/rss/RssTest.kt | 25 ++++++++++ .../github/magneticflux/rss/sample_atom.xml | 5 ++ 8 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomAuthorConverter.kt create mode 100644 src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomFeedConverter.kt create mode 100644 src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomAuthor.kt create mode 100644 src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomFeed.kt diff --git a/src/main/kotlin/com/github/magneticflux/rss/Converters.kt b/src/main/kotlin/com/github/magneticflux/rss/Converters.kt index 12690b9..96eb1e7 100644 --- a/src/main/kotlin/com/github/magneticflux/rss/Converters.kt +++ b/src/main/kotlin/com/github/magneticflux/rss/Converters.kt @@ -14,8 +14,16 @@ internal val fallbackPersister = createRssPersister() */ internal val InputNode.fullName: String get() { - val prefix = this.prefix + var prefix = this.prefix val name = this.name + + if (prefix.isEmpty()) + prefix = when (this.reference) { + "http://www.w3.org/1999/xhtml" -> "xhtml" + "http://www.w3.org/2005/Atom" -> "atom" + else -> prefix + } + return if (prefix.isEmpty()) name else "$prefix:$name" } diff --git a/src/main/kotlin/com/github/magneticflux/rss/Persisters.kt b/src/main/kotlin/com/github/magneticflux/rss/Persisters.kt index 708cb66..89d6ec1 100644 --- a/src/main/kotlin/com/github/magneticflux/rss/Persisters.kt +++ b/src/main/kotlin/com/github/magneticflux/rss/Persisters.kt @@ -1,5 +1,9 @@ package com.github.magneticflux.rss +import com.github.magneticflux.rss.namespaces.atom.converters.AtomAuthorConverter +import com.github.magneticflux.rss.namespaces.atom.converters.AtomFeedConverter +import com.github.magneticflux.rss.namespaces.atom.elements.AtomAuthor +import com.github.magneticflux.rss.namespaces.atom.elements.AtomFeed import com.github.magneticflux.rss.namespaces.itunes.converters.ITunesImageConverter import com.github.magneticflux.rss.namespaces.itunes.converters.ITunesSubCategoryConverter import com.github.magneticflux.rss.namespaces.itunes.converters.ITunesTopLevelCategoryConverter @@ -62,9 +66,13 @@ fun createRssStrategy(): Strategy { this.bind(Enclosure::class.java, EnclosureConverter) this.bind(Guid::class.java, GuidConverter) this.bind(Source::class.java, SourceConverter) + this.bind(ITunesTopLevelCategory::class.java, ITunesTopLevelCategoryConverter) this.bind(ITunesSubCategory::class.java, ITunesSubCategoryConverter) this.bind(ITunesImage::class.java, ITunesImageConverter) + + this.bind(AtomFeed::class.java, AtomFeedConverter) + this.bind(AtomAuthor::class.java, AtomAuthorConverter) }) } @@ -80,4 +88,4 @@ fun createRssMatcher(): Matcher { this.bind(Locale::class.java, LocaleLanguageTransform) this.bind(URL::class.java, URLTransform) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomAuthorConverter.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomAuthorConverter.kt new file mode 100644 index 0000000..8d28c6d --- /dev/null +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomAuthorConverter.kt @@ -0,0 +1,40 @@ +package com.github.magneticflux.rss.namespaces.atom.converters + +import com.github.magneticflux.rss.children +import com.github.magneticflux.rss.createChild +import com.github.magneticflux.rss.fullName +import com.github.magneticflux.rss.namespaces.atom.elements.ATOM_REFERENCE +import com.github.magneticflux.rss.namespaces.atom.elements.AtomAuthor +import org.simpleframework.xml.convert.Converter +import org.simpleframework.xml.stream.InputNode +import org.simpleframework.xml.stream.OutputNode + +/** + * @author Mitchell Skaggs + * @since 1.2.0 + */ +object AtomAuthorConverter : Converter { + override fun read(node: InputNode): AtomAuthor { + lateinit var name: String + var uri: String? = null + var email: String? = null + + node.children.forEach { + when (it.fullName) { + "atom:name" -> name = it.value + "atom:uri" -> uri = it.value + "atom:email" -> email = it.value + } + } + + return AtomAuthor(name, uri, email) + } + + override fun write(node: OutputNode, value: AtomAuthor) { + val writable = value.toWritable() + + node.createChild(ATOM_REFERENCE, "name", writable.name) + writable.uri?.let { node.createChild(ATOM_REFERENCE, "uri", it) } + writable.email?.let { node.createChild(ATOM_REFERENCE, "email", it) } + } +} diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomFeedConverter.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomFeedConverter.kt new file mode 100644 index 0000000..f7fc39a --- /dev/null +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomFeedConverter.kt @@ -0,0 +1,34 @@ +package com.github.magneticflux.rss.namespaces.atom.converters + +import com.github.magneticflux.rss.children +import com.github.magneticflux.rss.fallbackPersister +import com.github.magneticflux.rss.fullName +import com.github.magneticflux.rss.namespaces.atom.elements.AtomAuthor +import com.github.magneticflux.rss.namespaces.atom.elements.AtomFeed +import org.simpleframework.xml.convert.Converter +import org.simpleframework.xml.stream.InputNode +import org.simpleframework.xml.stream.OutputNode + +/** + * @author Mitchell Skaggs + * @since 1.2.0 + */ +object AtomFeedConverter : Converter { + override fun read(node: InputNode): AtomFeed { + var author: AtomAuthor? = null + + node.children.forEach { + when (it.fullName) { + "atom:author" -> author = fallbackPersister.read(AtomAuthor::class.java, it) + } + } + + return AtomFeed(author) + } + + override fun write(node: OutputNode, value: AtomFeed) { + val writable = value.toWritable() + + writable.author?.let { fallbackPersister.write(it, node) } + } +} diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomAuthor.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomAuthor.kt new file mode 100644 index 0000000..d65db17 --- /dev/null +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomAuthor.kt @@ -0,0 +1,50 @@ +package com.github.magneticflux.rss.namespaces.atom.elements + +import com.github.magneticflux.rss.namespaces.atom.converters.AtomAuthorConverter +import com.github.magneticflux.rss.namespaces.standard.elements.HasReadWrite +import org.simpleframework.xml.Namespace +import org.simpleframework.xml.Root + +/** + * Properties common to all representations of a `` element. + * + * @since 1.2.0 + */ +interface ICommonAtomPerson : HasReadWrite { + val name: String + val uri: String? + val email: String? +} + +/** + * The final RSS view of a `` element. Defaults are used if applicable. + * + * @since 1.2.0 + */ +interface IAtomPerson : ICommonAtomPerson { + override fun toReadOnly(): IAtomPerson = this +} + +/** + * The literal contents of a `` element. Elements with defaults may be omitted or invalid. + * + * @since 1.2.0 + */ +interface IWritableAtomPerson : ICommonAtomPerson { + override fun toWritable(): IWritableAtomPerson = this +} + +/** + * This class represents an Author object in a [AtomFeed]. + * + * @author Mitchell Skaggs + * @since 1.2.0 + * @see AtomAuthorConverter + */ +@Root(name = "author") +@Namespace(reference = ATOM_REFERENCE) +data class AtomAuthor( + override val name: String, + override val uri: String?, + override val email: String? +) : IAtomPerson, IWritableAtomPerson diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomFeed.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomFeed.kt new file mode 100644 index 0000000..1a9be87 --- /dev/null +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomFeed.kt @@ -0,0 +1,46 @@ +package com.github.magneticflux.rss.namespaces.atom.elements + +import com.github.magneticflux.rss.namespaces.atom.converters.AtomFeedConverter +import com.github.magneticflux.rss.namespaces.standard.elements.HasReadWrite +import org.simpleframework.xml.Namespace +import org.simpleframework.xml.Root + +/** + * Properties common to all representations of a `` element. + * + * @since 1.2.0 + */ +interface ICommonAtomFeed : HasReadWrite { + val author: AtomAuthor? +} + +/** + * The final RSS view of a `` element. Defaults are used if applicable. + * + * @since 1.2.0 + */ +interface IAtomFeed : ICommonAtomFeed { + override fun toReadOnly(): IAtomFeed = this +} + +/** + * The literal contents of a `` element. Elements with defaults may be omitted or invalid. + * + * @since 1.2.0 + */ +interface IWritableAtomFeed : ICommonAtomFeed { + override fun toWritable(): IWritableAtomFeed = this +} + +/** + * This class represents an atom:feed. + * + * @author Mitchell Skaggs + * @since 1.2.0 + * @see AtomFeedConverter + */ +@Root(name = "feed") +@Namespace(reference = ATOM_REFERENCE) +data class AtomFeed( + override val author: AtomAuthor? +) : IAtomFeed, IWritableAtomFeed diff --git a/src/test/kotlin/com/github/magneticflux/rss/RssTest.kt b/src/test/kotlin/com/github/magneticflux/rss/RssTest.kt index b1030cc..cd6d1f4 100644 --- a/src/test/kotlin/com/github/magneticflux/rss/RssTest.kt +++ b/src/test/kotlin/com/github/magneticflux/rss/RssTest.kt @@ -1,6 +1,7 @@ package com.github.magneticflux.rss import com.github.magneticflux.rss.SampleUtils.getSample +import com.github.magneticflux.rss.namespaces.atom.elements.AtomFeed import com.github.magneticflux.rss.namespaces.itunes.elements.ITunesSubCategory import com.github.magneticflux.rss.namespaces.itunes.elements.ITunesTopLevelCategory import com.github.magneticflux.rss.namespaces.standard.elements.Category @@ -392,5 +393,29 @@ class RssTest : Spek({ } } } + + given("sample_atom", { "$it RSS feed" }) { + val rssFeed = persister.read(AtomFeed::class.java, getSample("$it.xml")) + + on("feed reread") { + val rssText = persister.write(rssFeed) + + println(rssText) + + val rereadRssFeed = persister.read(AtomFeed::class.java, rssText) + + it("should equal original RSS feed read") { + assertThat(rereadRssFeed, equalTo(rssFeed)) + } + + it("should have the same hashCode as original RSS feed read") { + assertThat(rereadRssFeed.hashCode(), equalTo(rssFeed.hashCode())) + } + + it("should have the same String representation as original RSS feed read") { + assertThat(rereadRssFeed.toString(), equalTo(rssFeed.toString())) + } + } + } } }) diff --git a/src/test/resources/com/github/magneticflux/rss/sample_atom.xml b/src/test/resources/com/github/magneticflux/rss/sample_atom.xml index 38a1d6b..ea27743 100644 --- a/src/test/resources/com/github/magneticflux/rss/sample_atom.xml +++ b/src/test/resources/com/github/magneticflux/rss/sample_atom.xml @@ -1,5 +1,10 @@ + + Mark Pilgrim + http://example.org/ + f8dy@example.com + dive into mark A <em>lot</em> of effort From 3edb1684974f7930a9ec36ad4a5daba8b32b5a69 Mon Sep 17 00:00:00 2001 From: Mitchell Skaggs Date: Mon, 26 Feb 2018 16:15:33 -0600 Subject: [PATCH 3/6] Added CommonAttributes interfaces and support for explicit 'xml' namespace --- .../com/github/magneticflux/rss/Converters.kt | 35 ++++++++++-- .../com/github/magneticflux/rss/Transforms.kt | 15 +++++ .../magneticflux/rss/namespaces/Namespace.kt | 4 ++ .../atom/converters/AtomAuthorConverter.kt | 17 +++++- .../atom/converters/AtomFeedConverter.kt | 27 +++++++-- .../namespaces/atom/elements/AtomAuthor.kt | 8 +-- .../atom/elements/AtomCommonAttributes.kt | 55 +++++++++++++++++++ .../atom/elements/AtomDateConstruct.kt | 13 +++++ .../rss/namespaces/atom/elements/AtomFeed.kt | 8 ++- .../atom/elements/AtomPersonConstruct.kt | 13 +++++ .../github/magneticflux/rss/sample_atom.xml | 2 +- 11 files changed, 179 insertions(+), 18 deletions(-) create mode 100644 src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomCommonAttributes.kt create mode 100644 src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomDateConstruct.kt create mode 100644 src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomPersonConstruct.kt diff --git a/src/main/kotlin/com/github/magneticflux/rss/Converters.kt b/src/main/kotlin/com/github/magneticflux/rss/Converters.kt index 430c9d0..3e50c01 100644 --- a/src/main/kotlin/com/github/magneticflux/rss/Converters.kt +++ b/src/main/kotlin/com/github/magneticflux/rss/Converters.kt @@ -1,6 +1,10 @@ package com.github.magneticflux.rss import com.github.magneticflux.rss.namespaces.Namespace +import com.github.magneticflux.rss.namespaces.Namespace.ATOM +import com.github.magneticflux.rss.namespaces.Namespace.DEFAULT +import com.github.magneticflux.rss.namespaces.Namespace.ITUNES +import com.github.magneticflux.rss.namespaces.Namespace.XML import org.simpleframework.xml.convert.Converter import org.simpleframework.xml.stream.InputNode import org.simpleframework.xml.stream.OutputNode @@ -15,10 +19,11 @@ internal val fallbackPersister = createRssPersister() */ internal val InputNode.namespace: Namespace? get() { - return when (reference.toLowerCase()) { - Namespace.DEFAULT.reference -> Namespace.DEFAULT - Namespace.ITUNES.reference -> Namespace.ITUNES - Namespace.ATOM.reference -> Namespace.ATOM + return when { + reference.equals(DEFAULT.reference, true) -> DEFAULT + reference.equals(ITUNES.reference, true) -> ITUNES + reference.equals(ATOM.reference, true) -> ATOM + reference.equals(XML.reference, true) -> XML else -> null } } @@ -30,6 +35,13 @@ internal val InputNode.children: Iterator get() { return InputNodeChildIterator(this) } +/** + * Creates an iterator over an InputNode's attributes. + */ +internal val InputNode.allAttributes: Iterator + get() { + return this.attributes.asSequence().map { this.attributes[it] }.iterator() + } /** * Create a child node containing only the given String with the specified namespace. @@ -40,6 +52,21 @@ internal fun OutputNode.createChild(reference: String = "", name: String, value: child.reference = reference } +/** + * Create a child node containing only the given String with the specified namespace. + */ +internal fun OutputNode.createAttribute( + reference: String = "", + name: String, + value: String, + prefix: String? = null +) { + val child = this.setAttribute(name, value) + child.reference = reference + if (prefix != null) + child.namespaces.setReference(reference, prefix) +} + /** * An iterator that iterates over children of an [InputNode]. */ diff --git a/src/main/kotlin/com/github/magneticflux/rss/Transforms.kt b/src/main/kotlin/com/github/magneticflux/rss/Transforms.kt index 38067e5..a4c689d 100644 --- a/src/main/kotlin/com/github/magneticflux/rss/Transforms.kt +++ b/src/main/kotlin/com/github/magneticflux/rss/Transforms.kt @@ -2,6 +2,7 @@ package com.github.magneticflux.rss import org.simpleframework.xml.transform.Transform import org.threeten.bp.DayOfWeek +import org.threeten.bp.Instant import org.threeten.bp.ZonedDateTime import org.threeten.bp.format.DateTimeFormatter import org.threeten.bp.format.DateTimeFormatterBuilder @@ -52,6 +53,20 @@ object ZonedDateTimeTransform : Transform { } } +/** + * @author Mitchell Skaggs + * @since 1.2.0 + */ +object ISODateTimeTransform : Transform { + override fun write(value: Instant): String { + return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(value) + } + + override fun read(value: String): Instant { + return Instant.FROM.queryFrom(DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(value)) + } +} + /** * @author Mitchell Skaggs * @since 1.0.1 diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/Namespace.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/Namespace.kt index 7892468..07173fd 100644 --- a/src/main/kotlin/com/github/magneticflux/rss/namespaces/Namespace.kt +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/Namespace.kt @@ -16,4 +16,8 @@ sealed class Namespace { object ATOM : Namespace() { const val reference: String = "http://www.w3.org/2005/Atom" } + + object XML : Namespace() { + const val reference: String = "http://www.w3.org/XML/1998/namespace" + } } diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomAuthorConverter.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomAuthorConverter.kt index 21e10d8..8b04100 100644 --- a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomAuthorConverter.kt +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomAuthorConverter.kt @@ -1,5 +1,6 @@ package com.github.magneticflux.rss.namespaces.atom.converters +import com.github.magneticflux.rss.allAttributes import com.github.magneticflux.rss.children import com.github.magneticflux.rss.createChild import com.github.magneticflux.rss.namespace @@ -15,10 +16,24 @@ import org.simpleframework.xml.stream.OutputNode */ object AtomAuthorConverter : Converter { override fun read(node: InputNode): AtomAuthor { + var base: String? = null + var lang: String? = null + lateinit var name: String var uri: String? = null var email: String? = null + node.allAttributes.forEach { + when (it.namespace) { + Namespace.XML -> { + when (it.name) { + "base" -> base = it.value + "lang" -> lang = it.value + } + } + } + } + node.children.forEach { when (it.namespace) { Namespace.ATOM -> { @@ -31,7 +46,7 @@ object AtomAuthorConverter : Converter { } } - return AtomAuthor(name, uri, email) + return AtomAuthor(base, lang, name, uri, email) } override fun write(node: OutputNode, value: AtomAuthor) { diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomFeedConverter.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomFeedConverter.kt index 39c1db3..ab25c49 100644 --- a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomFeedConverter.kt +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomFeedConverter.kt @@ -1,6 +1,8 @@ package com.github.magneticflux.rss.namespaces.atom.converters +import com.github.magneticflux.rss.allAttributes import com.github.magneticflux.rss.children +import com.github.magneticflux.rss.createAttribute import com.github.magneticflux.rss.fallbackPersister import com.github.magneticflux.rss.namespace import com.github.magneticflux.rss.namespaces.Namespace @@ -16,24 +18,41 @@ import org.simpleframework.xml.stream.OutputNode */ object AtomFeedConverter : Converter { override fun read(node: InputNode): AtomFeed { - var author: AtomAuthor? = null + var xmlBase: String? = null + var xmlLang: String? = null + + val author: MutableList = mutableListOf() + + node.allAttributes.forEach { + when (it.namespace) { + Namespace.XML -> { + when (it.name) { + "base" -> xmlBase = it.value + "lang" -> xmlLang = it.value + } + } + } + } node.children.forEach { when (it.namespace) { Namespace.ATOM -> { when (it.name) { - "author" -> author = fallbackPersister.read(AtomAuthor::class.java, it) + "author" -> author += fallbackPersister.read(AtomAuthor::class.java, it) } } } } - return AtomFeed(author) + return AtomFeed(xmlBase, xmlLang, author) } override fun write(node: OutputNode, value: AtomFeed) { val writable = value.toWritable() - writable.author?.let { fallbackPersister.write(it, node) } + writable.base?.let { node.createAttribute(Namespace.XML.reference, "base", it, "xml") } + writable.lang?.let { node.createAttribute(Namespace.XML.reference, "lang", it, "xml") } + + writable.author.forEach { fallbackPersister.write(it, node) } } } diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomAuthor.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomAuthor.kt index 70ed095..94372f8 100644 --- a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomAuthor.kt +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomAuthor.kt @@ -11,11 +11,7 @@ import org.simpleframework.xml.Root * * @since 1.2.0 */ -interface ICommonAtomPerson : HasReadWrite { - val name: String - val uri: String? - val email: String? -} +interface ICommonAtomPerson : HasReadWrite, AtomPersonConstruct /** * The final RSS view of a `` element. Defaults are used if applicable. @@ -45,6 +41,8 @@ interface IWritableAtomPerson : ICommonAtomPerson { @Root(name = "author") @Namespace(reference = ATOM.reference) data class AtomAuthor( + override val base: String?, + override val lang: String?, override val name: String, override val uri: String?, override val email: String? diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomCommonAttributes.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomCommonAttributes.kt new file mode 100644 index 0000000..ba1ac7e --- /dev/null +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomCommonAttributes.kt @@ -0,0 +1,55 @@ +package com.github.magneticflux.rss.namespaces.atom.elements + +/** + * Corresponds to `atomCommonAttributes` in RFC4287. + * + * @author Mitchell Skaggs + * @since 1.2.0 + */ +interface AtomCommonAttributes { + val base: String? + val lang: String? +} + +/** + * Corresponds to `atomTextConstruct` in RFC4287. + * + * @author Mitchell Skaggs + * @since 1.2.0 + */ +interface AtomTextConstruct : AtomCommonAttributes { + val type: AtomTextType? +} + +/** + * Corresponds to `atomPlainTextConstruct` in RFC4287. + * + * @author Mitchell Skaggs + * @since 1.2.0 + */ +interface AtomPlainTextConstruct : AtomTextConstruct { + override val type: AtomPlainTextType? + val text: String +} + +/** + * Corresponds to `atomXHTMLTextConstruct` in RFC4287. + * + * @author Mitchell Skaggs + * @since 1.2.0 + */ +interface AtomXHTMLTextConstruct : AtomTextConstruct { + override val type: AtomXHTMLTextType + val text: String +} + +sealed class AtomTextType + +sealed class AtomPlainTextType : AtomTextType() { + object TEXT : AtomPlainTextType() + object HTML : AtomPlainTextType() +} + +sealed class AtomXHTMLTextType : AtomTextType() { + object XHTML : AtomXHTMLTextType() +} diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomDateConstruct.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomDateConstruct.kt new file mode 100644 index 0000000..e6484f9 --- /dev/null +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomDateConstruct.kt @@ -0,0 +1,13 @@ +package com.github.magneticflux.rss.namespaces.atom.elements + +import org.threeten.bp.Instant + +/** + * Corresponds to `atomPersonConstruct` in RFC4287. + * + * @author Mitchell Skaggs + * @since 1.2.0 + */ +interface AtomDateConstruct : AtomCommonAttributes { + val dateTime: Instant +} diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomFeed.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomFeed.kt index 3df1d06..b257bfb 100644 --- a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomFeed.kt +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomFeed.kt @@ -11,8 +11,8 @@ import org.simpleframework.xml.Root * * @since 1.2.0 */ -interface ICommonAtomFeed : HasReadWrite { - val author: AtomAuthor? +interface ICommonAtomFeed : HasReadWrite, AtomCommonAttributes { + val author: List } /** @@ -43,5 +43,7 @@ interface IWritableAtomFeed : ICommonAtomFeed { @Root(name = "feed") @Namespace(reference = ATOM.reference) data class AtomFeed( - override val author: AtomAuthor? + override val base: String?, + override val lang: String?, + override val author: List ) : IAtomFeed, IWritableAtomFeed diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomPersonConstruct.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomPersonConstruct.kt new file mode 100644 index 0000000..9b6480d --- /dev/null +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomPersonConstruct.kt @@ -0,0 +1,13 @@ +package com.github.magneticflux.rss.namespaces.atom.elements + +/** + * Corresponds to `atomPersonConstruct` in RFC4287. + * + * @author Mitchell Skaggs + * @since 1.2.0 + */ +interface AtomPersonConstruct : AtomCommonAttributes { + val name: String + val uri: String? + val email: String? +} diff --git a/src/test/resources/com/github/magneticflux/rss/sample_atom.xml b/src/test/resources/com/github/magneticflux/rss/sample_atom.xml index ea27743..cb02e2f 100644 --- a/src/test/resources/com/github/magneticflux/rss/sample_atom.xml +++ b/src/test/resources/com/github/magneticflux/rss/sample_atom.xml @@ -1,5 +1,5 @@ - + Mark Pilgrim http://example.org/ From 8a97db708c4bcd276ee6bc7fdfd12377c2c7d492 Mon Sep 17 00:00:00 2001 From: Mitchell Skaggs Date: Tue, 27 Feb 2018 09:58:47 -0600 Subject: [PATCH 4/6] Added documentation about special treatment of `XML` namespace and prefix --- .../kotlin/com/github/magneticflux/rss/namespaces/Namespace.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/Namespace.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/Namespace.kt index 07173fd..a05d7ba 100644 --- a/src/main/kotlin/com/github/magneticflux/rss/namespaces/Namespace.kt +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/Namespace.kt @@ -17,6 +17,9 @@ sealed class Namespace { const val reference: String = "http://www.w3.org/2005/Atom" } + /** + * "Note that unlike all other XML namespaces, both the name and the prefix are specified; i.e., if you want XML 1.0 processors to recognize this namespace, you must use the reserved prefix `xml:`." + */ object XML : Namespace() { const val reference: String = "http://www.w3.org/XML/1998/namespace" } From d3d2ef8e6fe829eec7e07e7ecc37590a78c009a6 Mon Sep 17 00:00:00 2001 From: Mitchell Skaggs Date: Fri, 9 Mar 2018 09:40:03 -0600 Subject: [PATCH 5/6] Added atom contributor element --- .../com/github/magneticflux/rss/Persisters.kt | 3 + .../converters/AtomContributorConverter.kt | 59 +++++++++++++++++++ .../atom/converters/AtomFeedConverter.kt | 12 +++- .../namespaces/atom/elements/AtomAuthor.kt | 18 +++--- .../atom/elements/AtomContributor.kt | 50 ++++++++++++++++ 5 files changed, 130 insertions(+), 12 deletions(-) create mode 100644 src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomContributorConverter.kt create mode 100644 src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomContributor.kt diff --git a/src/main/kotlin/com/github/magneticflux/rss/Persisters.kt b/src/main/kotlin/com/github/magneticflux/rss/Persisters.kt index 89d6ec1..a897949 100644 --- a/src/main/kotlin/com/github/magneticflux/rss/Persisters.kt +++ b/src/main/kotlin/com/github/magneticflux/rss/Persisters.kt @@ -1,8 +1,10 @@ package com.github.magneticflux.rss import com.github.magneticflux.rss.namespaces.atom.converters.AtomAuthorConverter +import com.github.magneticflux.rss.namespaces.atom.converters.AtomContributorConverter import com.github.magneticflux.rss.namespaces.atom.converters.AtomFeedConverter import com.github.magneticflux.rss.namespaces.atom.elements.AtomAuthor +import com.github.magneticflux.rss.namespaces.atom.elements.AtomContributor import com.github.magneticflux.rss.namespaces.atom.elements.AtomFeed import com.github.magneticflux.rss.namespaces.itunes.converters.ITunesImageConverter import com.github.magneticflux.rss.namespaces.itunes.converters.ITunesSubCategoryConverter @@ -73,6 +75,7 @@ fun createRssStrategy(): Strategy { this.bind(AtomFeed::class.java, AtomFeedConverter) this.bind(AtomAuthor::class.java, AtomAuthorConverter) + this.bind(AtomContributor::class.java, AtomContributorConverter) }) } diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomContributorConverter.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomContributorConverter.kt new file mode 100644 index 0000000..cd8e529 --- /dev/null +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomContributorConverter.kt @@ -0,0 +1,59 @@ +package com.github.magneticflux.rss.namespaces.atom.converters + +import com.github.magneticflux.rss.allAttributes +import com.github.magneticflux.rss.children +import com.github.magneticflux.rss.createChild +import com.github.magneticflux.rss.namespace +import com.github.magneticflux.rss.namespaces.Namespace +import com.github.magneticflux.rss.namespaces.atom.elements.AtomContributor +import org.simpleframework.xml.convert.Converter +import org.simpleframework.xml.stream.InputNode +import org.simpleframework.xml.stream.OutputNode + +/** + * @author Mitchell Skaggs + * @since 1.2.0 + */ +object AtomContributorConverter : Converter { + override fun read(node: InputNode): AtomContributor { + var base: String? = null + var lang: String? = null + + lateinit var name: String + var uri: String? = null + var email: String? = null + + node.allAttributes.forEach { + when (it.namespace) { + Namespace.XML -> { + when (it.name) { + "base" -> base = it.value + "lang" -> lang = it.value + } + } + } + } + + node.children.forEach { + when (it.namespace) { + Namespace.ATOM -> { + when (it.name) { + "name" -> name = it.value + "uri" -> uri = it.value + "email" -> email = it.value + } + } + } + } + + return AtomContributor(base, lang, name, uri, email) + } + + override fun write(node: OutputNode, value: AtomContributor) { + val writable = value.toWritable() + + node.createChild(Namespace.ATOM.reference, "name", writable.name) + writable.uri?.let { node.createChild(Namespace.ATOM.reference, "uri", it) } + writable.email?.let { node.createChild(Namespace.ATOM.reference, "email", it) } + } +} diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomFeedConverter.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomFeedConverter.kt index ab25c49..bba3761 100644 --- a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomFeedConverter.kt +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/converters/AtomFeedConverter.kt @@ -7,6 +7,7 @@ import com.github.magneticflux.rss.fallbackPersister import com.github.magneticflux.rss.namespace import com.github.magneticflux.rss.namespaces.Namespace import com.github.magneticflux.rss.namespaces.atom.elements.AtomAuthor +import com.github.magneticflux.rss.namespaces.atom.elements.AtomContributor import com.github.magneticflux.rss.namespaces.atom.elements.AtomFeed import org.simpleframework.xml.convert.Converter import org.simpleframework.xml.stream.InputNode @@ -21,7 +22,8 @@ object AtomFeedConverter : Converter { var xmlBase: String? = null var xmlLang: String? = null - val author: MutableList = mutableListOf() + val authors: MutableList = mutableListOf() + val contributors: MutableList = mutableListOf() node.allAttributes.forEach { when (it.namespace) { @@ -38,13 +40,17 @@ object AtomFeedConverter : Converter { when (it.namespace) { Namespace.ATOM -> { when (it.name) { - "author" -> author += fallbackPersister.read(AtomAuthor::class.java, it) + "author" -> authors += fallbackPersister.read(AtomAuthor::class.java, it) + "contributor" -> contributors += fallbackPersister.read( + AtomContributor::class.java, + it + ) } } } } - return AtomFeed(xmlBase, xmlLang, author) + return AtomFeed(xmlBase, xmlLang, authors) } override fun write(node: OutputNode, value: AtomFeed) { diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomAuthor.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomAuthor.kt index 94372f8..a079ead 100644 --- a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomAuthor.kt +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomAuthor.kt @@ -7,28 +7,28 @@ import org.simpleframework.xml.Namespace import org.simpleframework.xml.Root /** - * Properties common to all representations of a `` element. + * Properties common to all representations of an `` element. * * @since 1.2.0 */ -interface ICommonAtomPerson : HasReadWrite, AtomPersonConstruct +interface ICommonAtomAuthor : HasReadWrite, AtomPersonConstruct /** - * The final RSS view of a `` element. Defaults are used if applicable. + * The final RSS view of an `` element. Defaults are used if applicable. * * @since 1.2.0 */ -interface IAtomPerson : ICommonAtomPerson { - override fun toReadOnly(): IAtomPerson = this +interface IAtomAuthor : ICommonAtomAuthor { + override fun toReadOnly(): IAtomAuthor = this } /** - * The literal contents of a `` element. Elements with defaults may be omitted or invalid. + * The literal contents of an `` element. Elements with defaults may be omitted or invalid. * * @since 1.2.0 */ -interface IWritableAtomPerson : ICommonAtomPerson { - override fun toWritable(): IWritableAtomPerson = this +interface IWritableAtomAuthor : ICommonAtomAuthor { + override fun toWritable(): IWritableAtomAuthor = this } /** @@ -46,4 +46,4 @@ data class AtomAuthor( override val name: String, override val uri: String?, override val email: String? -) : IAtomPerson, IWritableAtomPerson +) : IAtomAuthor, IWritableAtomAuthor diff --git a/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomContributor.kt b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomContributor.kt new file mode 100644 index 0000000..6a02a06 --- /dev/null +++ b/src/main/kotlin/com/github/magneticflux/rss/namespaces/atom/elements/AtomContributor.kt @@ -0,0 +1,50 @@ +package com.github.magneticflux.rss.namespaces.atom.elements + +import com.github.magneticflux.rss.namespaces.Namespace.ATOM +import com.github.magneticflux.rss.namespaces.atom.converters.AtomAuthorConverter +import com.github.magneticflux.rss.namespaces.standard.elements.HasReadWrite +import org.simpleframework.xml.Namespace +import org.simpleframework.xml.Root + +/** + * Properties common to all representations of a `` element. + * + * @since 1.2.0 + */ +interface ICommonAtomContributor : HasReadWrite, + AtomPersonConstruct + +/** + * The final RSS view of a `` element. Defaults are used if applicable. + * + * @since 1.2.0 + */ +interface IAtomContributor : ICommonAtomContributor { + override fun toReadOnly(): IAtomContributor = this +} + +/** + * The literal contents of a `` element. Elements with defaults may be omitted or invalid. + * + * @since 1.2.0 + */ +interface IWritableAtomContributor : ICommonAtomContributor { + override fun toWritable(): IWritableAtomContributor = this +} + +/** + * This class represents an Author object in a [AtomFeed]. + * + * @author Mitchell Skaggs + * @since 1.2.0 + * @see AtomAuthorConverter + */ +@Root(name = "contributor") +@Namespace(reference = ATOM.reference) +data class AtomContributor( + override val base: String?, + override val lang: String?, + override val name: String, + override val uri: String?, + override val email: String? +) : IAtomContributor, IWritableAtomContributor From 23dadd80ead2ebd66b136eecf33f78fc0d15abe3 Mon Sep 17 00:00:00 2001 From: Mitchell Skaggs Date: Fri, 9 Mar 2018 09:41:33 -0600 Subject: [PATCH 6/6] Clarified internal publication name --- build.gradle | 2 +- gradle/shipkit.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index f58f226..70fbe68 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ test { publishing { publications { - myPublication(MavenPublication) { + kotlinSimpleXmlRss(MavenPublication) { from components.java //noinspection GroovyAssignabilityCheck artifact sourcesJar diff --git a/gradle/shipkit.gradle b/gradle/shipkit.gradle index 9257f47..a69cc56 100644 --- a/gradle/shipkit.gradle +++ b/gradle/shipkit.gradle @@ -15,7 +15,7 @@ allprojects { user = 'magneticflux' key = System.getenv("BINTRAY_API_KEY") - publications = ['myPublication'] + publications = ['kotlinSimpleXmlRss'] pkg { repo = 'kotlin-simplexml-rss'