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..96ff4ae 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,33 +45,61 @@ 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 categoryValue = generateCategoryValue(categories); + addNotNullAttribute(outlineElement, "category", categoryValue); + + return outlineElement; + + } + + private String generateCategoryValue(final Collection categories) { + + final StringBuilder builder = new StringBuilder(); + + boolean first = true; + for (final String category : categories) { + if (category != null && !category.trim().isEmpty()) { + if (first) { + first = false; + } else { + builder.append(","); + } + builder.append(category.trim()); + } + } + + if (builder.length() > 0) { + return builder.toString(); + } else { + return null; + } } 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..28dd3d1 --- /dev/null +++ b/src/test/java/com/rometools/opml/io/impl/OPML20GeneratorTest.java @@ -0,0 +1,73 @@ +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.util.Arrays; + +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; + +import com.rometools.opml.feed.opml.Opml; +import com.rometools.opml.feed.opml.Outline; +import com.rometools.rome.io.WireFeedOutput; + +public class OPML20GeneratorTest { + + @Test + public void testOutputOfNullCategory() { + assertThat(categoryOf((String) null).getLength(), is(equalTo(0))); + } + + @Test + public void testOutputOfEmptyCategory() { + assertThat(categoryOf("").getLength(), is(equalTo(0))); + } + + @Test + public void testOutputOfBlankCategory() { + assertThat(categoryOf(" ").getLength(), is(equalTo(0))); + } + + @Test + public void testOutputOfOneCategory() { + assertThat(categoryValueOf("category1"), is(equalTo("category1"))); + } + + @Test + public void testOutputOfMultipleCategories() { + assertThat(categoryValueOf("category1", "category2"), is(equalTo("category1,category2"))); + } + + private NodeList categoryOf(final String... categories) { + + try { + + final Outline outline = new Outline("outline1", null); + outline.setCategories(Arrays.asList(categories)); + + final Opml opml = new Opml(); + opml.setFeedType("opml_2.0"); + opml.setTitle("title"); + opml.setOutlines(Arrays.asList(outline)); + + final WireFeedOutput output = new WireFeedOutput(); + final String xml = output.outputString(opml); + + final Document document = XMLUnit.buildControlDocument(xml); + return XMLUnit.newXpathEngine().getMatchingNodes("/opml/body/outline/@category", document); + + } catch (final Exception e) { + throw new RuntimeException(e); + } + + } + + private String categoryValueOf(final String... categories) { + return categoryOf(categories).item(0).getNodeValue(); + } + +}