diff --git a/pom.xml b/pom.xml
index e58c56b..b8d6cc4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -76,6 +76,10 @@
junit
test
+
+ org.hamcrest
+ hamcrest-library
+
xmlunit
xmlunit
diff --git a/src/main/java/com/rometools/opml/io/impl/OPML20Generator.java b/src/main/java/com/rometools/opml/io/impl/OPML20Generator.java
index dfc4137..a774291 100644
--- a/src/main/java/com/rometools/opml/io/impl/OPML20Generator.java
+++ b/src/main/java/com/rometools/opml/io/impl/OPML20Generator.java
@@ -1,5 +1,7 @@
package com.rometools.opml.io.impl;
+import java.util.Collection;
+import java.util.List;
import java.util.Locale;
import org.jdom2.Document;
@@ -12,7 +14,9 @@ import com.rometools.rome.io.FeedException;
import com.rometools.rome.io.impl.DateParser;
/**
- * @author cooper
+ * Generator for OPML 2.0 documents.
+ *
+ * @see http://dev.opml.org/spec2.html
*/
public class OPML20Generator extends OPML10Generator {
@@ -41,34 +45,54 @@ public class OPML20Generator extends OPML10Generator {
*/
@Override
public Document generate(final WireFeed feed) throws IllegalArgumentException, FeedException {
- final Document retValue = super.generate(feed);
- retValue.getRootElement().setAttribute("version", "2.0");
- return retValue;
+ final Document document = super.generate(feed);
+ document.getRootElement().setAttribute("version", "2.0");
+ return document;
}
@Override
protected Element generateHead(final Opml opml) {
- final Element docs = new Element("docs");
- docs.setText(opml.getDocs());
+ final Element docsElement = new Element("docs");
+ docsElement.setText(opml.getDocs());
- final Element retValue = super.generateHead(opml);
- retValue.addContent(docs);
- return retValue;
+ final Element headElement = super.generateHead(opml);
+ headElement.addContent(docsElement);
+ return headElement;
}
@Override
protected Element generateOutline(final Outline outline) {
- final Element retValue = super.generateOutline(outline);
+ final Element outlineElement = super.generateOutline(outline);
if (outline.getCreated() != null) {
- retValue.setAttribute("created", DateParser.formatRFC822(outline.getCreated(), Locale.US));
+ outlineElement.setAttribute("created", DateParser.formatRFC822(outline.getCreated(), Locale.US));
}
- return retValue;
+ final List categories = outline.getCategories();
+ final String categoriesValue = generateCategoriesValue(categories);
+ addNotNullAttribute(outlineElement, "category", categoriesValue);
+
+ return outlineElement;
}
+ private String generateCategoriesValue(final Collection categories) {
+ final StringBuilder builder = new StringBuilder();
+ for (final String category : categories) {
+ if (category != null && !category.trim().isEmpty()) {
+ builder.append("/");
+ builder.append(category.trim());
+ }
+ }
+ final String categoryString = builder.toString();
+ if (categoryString == null || categoryString.trim().isEmpty()) {
+ return null;
+ } else {
+ return categoryString;
+ }
+ }
+
}
diff --git a/src/test/java/com/rometools/opml/io/impl/OPML20GeneratorTest.java b/src/test/java/com/rometools/opml/io/impl/OPML20GeneratorTest.java
new file mode 100644
index 0000000..d4359b8
--- /dev/null
+++ b/src/test/java/com/rometools/opml/io/impl/OPML20GeneratorTest.java
@@ -0,0 +1,52 @@
+package com.rometools.opml.io.impl;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.custommonkey.xmlunit.XMLUnit;
+import org.custommonkey.xmlunit.exceptions.XpathException;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import com.rometools.opml.feed.opml.Opml;
+import com.rometools.opml.feed.opml.Outline;
+import com.rometools.rome.io.FeedException;
+import com.rometools.rome.io.WireFeedOutput;
+
+public class OPML20GeneratorTest {
+
+ @Test
+ public void testCategoryOutput() throws IllegalArgumentException, FeedException, SAXException, IOException, XpathException {
+ checkCategoryOutput(null, "");
+ checkCategoryOutput(Arrays.asList("category1"), "/category1");
+ checkCategoryOutput(Arrays.asList("category1", "category2"), "/category1/category2");
+ }
+
+ private void checkCategoryOutput(final List categories, final String asserted)
+ throws IllegalArgumentException, FeedException, SAXException, IOException, XpathException {
+
+ final Outline outline = new Outline("outline1", null);
+ outline.setCategories(categories);
+ final List outlines = Arrays.asList(outline);
+
+ final Opml opml = new Opml();
+ opml.setFeedType("opml_2.0");
+ opml.setTitle("title");
+ opml.setOutlines(outlines);
+
+ final WireFeedOutput output = new WireFeedOutput();
+ final String xml = output.outputString(opml);
+
+ final Document document = XMLUnit.buildControlDocument(xml);
+ final String categoryValue = XMLUnit.newXpathEngine().evaluate("/opml/body/outline/@category", document);
+ assertThat(categoryValue, is(equalTo(asserted)));
+
+ }
+
+}