+ There are three classes here that are relevant. Opml
,
+ which represents the root document and head
information,
+ Outline
which represents a single node on an Opml
+ outline tree, and provides convenience methods for commonly used
+ attributes such as xmlUrl
. Finally, the
+ Attribute
class, which represents a specific attribute
+ on an Outline object. Since OPML supports free-form attribute
+ assignments, this is a very multi-purpose class.
+
Sample Usage:
+ To use this parser, simply include the jar file in your classpath
+ as you are using ROME. Be sure it exists at the same level as ROME,
+ such that, if ROME is in the common classpath of an application server,
+ don't include this jar in your webapps WEB-INF/lib.
+
+
+ WireFeedInput input = new WireFeedInput();
+ Opml feed = (Opml) input.build( new File("myOpml.xml") );
+ List<Outline> outlines = (List<Outline>) feed.getOutlines();
+
+ * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. ++ + diff --git a/src/main/java/org/rometools/feed/synd/impl/ConverterForOPML10.java b/src/main/java/org/rometools/feed/synd/impl/ConverterForOPML10.java new file mode 100644 index 0000000..efb6725 --- /dev/null +++ b/src/main/java/org/rometools/feed/synd/impl/ConverterForOPML10.java @@ -0,0 +1,374 @@ +/* + * ConverterForOPML10.java + * + * Created on April 25, 2006, 1:26 AM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.rometools.feed.synd.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Stack; +import java.util.logging.Logger; + +import com.sun.syndication.feed.WireFeed; +import org.rometools.feed.opml.Attribute; +import org.rometools.feed.opml.Opml; +import org.rometools.feed.opml.Outline; +import com.sun.syndication.feed.synd.Converter; +import com.sun.syndication.feed.synd.SyndCategory; +import com.sun.syndication.feed.synd.SyndCategoryImpl; +import com.sun.syndication.feed.synd.SyndContent; +import com.sun.syndication.feed.synd.SyndContentImpl; +import com.sun.syndication.feed.synd.SyndEntry; +import com.sun.syndication.feed.synd.SyndEntryImpl; +import com.sun.syndication.feed.synd.SyndFeed; +import com.sun.syndication.feed.synd.SyndLink; +import com.sun.syndication.feed.synd.SyndLinkImpl; +import com.sun.syndication.feed.synd.SyndPerson; +import com.sun.syndication.feed.synd.SyndPersonImpl; + + +/** + * + * @author cooper + */ +public class ConverterForOPML10 implements Converter { + private static final Logger LOG = Logger.getLogger(ConverterForOPML10.class.getName() + .toString()); + public static final String URI_TREE = "urn:rome.tree"; + public static final String URI_ATTRIBUTE = "urn:rome.attribute#"; + + /** Creates a new instance of ConverterForOPML10 */ + public ConverterForOPML10() { + super(); + } + + protected void addOwner(Opml opml, SyndFeed syndFeed) { + if((opml.getOwnerEmail() != null) || (opml.getOwnerName() != null)) { + List authors = new ArrayList(); + SyndPerson person = new SyndPersonImpl(); + person.setEmail(opml.getOwnerEmail()); + person.setName(opml.getOwnerName()); + authors.add(person); + syndFeed.setAuthors(authors); + } + } + + /** + * Makes a deep copy/conversion of the values of a real feed into a SyndFeedImpl. + *
+ * It assumes the given SyndFeedImpl has no properties set. + *
+ * + * @param feed real feed to copy/convert. + * @param syndFeed the SyndFeedImpl that will contain the copied/converted values of the real feed. + */ + public void copyInto(WireFeed feed, SyndFeed syndFeed) { + Opml opml = (Opml) feed; + syndFeed.setTitle(opml.getTitle()); + addOwner(opml, syndFeed); + syndFeed.setPublishedDate((opml.getModified() != null) + ? opml.getModified() : opml.getCreated()); + syndFeed.setFeedType(opml.getFeedType()); + syndFeed.setModules(opml.getModules()); + syndFeed.setFeedType(this.getType()); + + ArrayList entries = new ArrayList(); + createEntries(new TreeContext(), syndFeed.getEntries(), + opml.getOutlines()); + } + + protected void createEntries(TreeContext context, List allEntries, + List outlines) { + List so = Collections.synchronizedList(outlines); + + for(int i = 0; i < so.size(); i++) { + createEntry(context, allEntries, (Outline) so.get(i)); + } + } + + protected SyndEntry createEntry(TreeContext context, List allEntries, + Outline outline) { + SyndEntry entry = new SyndEntryImpl(); + + if((outline.getType() != null) && outline.getType().equals("rss")) { + entry.setLink((outline.getHtmlUrl() != null) ? outline.getHtmlUrl() + : outline.getXmlUrl()); + } else if((outline.getType() != null) && + outline.getType().equals("link")) { + entry.setLink(outline.getUrl()); + } + + if(outline.getHtmlUrl() != null) { + SyndLink link = new SyndLinkImpl(); + link.setRel("alternate"); + link.setType("text/html"); + link.setHref(outline.getHtmlUrl()); + entry.getLinks().add(link); + entry.setLink(outline.getHtmlUrl()); + } + + if((outline.getXmlUrl() != null) && (outline.getType() != null) && + outline.getType().equalsIgnoreCase("rss")) { + SyndLink link = new SyndLinkImpl(); + link.setRel("alternate"); + link.setType("application/rss+xml"); + link.setHref(outline.getXmlUrl()); + entry.getLinks().add(link); + + if(entry.getLink() == null) { + entry.setLink(outline.getXmlUrl()); + } + } + + if((outline.getXmlUrl() != null) && (outline.getType() != null) && + outline.getType().equalsIgnoreCase("atom")) { + SyndLink link = new SyndLinkImpl(); + link.setRel("alternate"); + link.setType("application/atom+xml"); + link.setHref(outline.getXmlUrl()); + entry.getLinks().add(link); + + if(entry.getLink() == null) { + entry.setLink(outline.getXmlUrl()); + } + } + + if((outline.getType() != null) && outline.getType().equals("rss")) { + entry.setTitle(outline.getTitle()); + } else { + entry.setTitle(outline.getText()); + } + + if((outline.getText() == null) && (entry.getTitle() != null)) { + SyndContent c = new SyndContentImpl(); + c.setValue(outline.getText()); + entry.setDescription(c); + } + + entry.setPublishedDate(outline.getCreated()); + + String nodeName = "node." + outline.hashCode(); + + SyndCategory cat = new TreeCategoryImpl(); + cat.setTaxonomyUri(URI_TREE); + cat.setName(nodeName); + entry.getCategories().add(cat); + + if(context.size() > 0) { + Integer parent = (Integer) context.peek(); + SyndCategory pcat = new TreeCategoryImpl(); + pcat.setTaxonomyUri(URI_TREE); + pcat.setName("parent." + parent); + entry.getCategories().add(pcat); + } + + List attributes = Collections.synchronizedList(outline.getAttributes()); + + for(int i = 0; i < attributes.size(); i++) { + Attribute a = (Attribute) attributes.get(i); + SyndCategory acat = new SyndCategoryImpl(); + acat.setName(a.getValue()); + acat.setTaxonomyUri(URI_ATTRIBUTE + a.getName()); + entry.getCategories().add(acat); + } + + entry.setModules(outline.getModules()); + allEntries.add(entry); + context.push(new Integer(outline.hashCode())); + createEntries(context, allEntries, outline.getChildren()); + context.pop(); + + return entry; + } + + /** + * Creates real feed with a deep copy/conversion of the values of a SyndFeedImpl. + *
+ * + * @param syndFeed SyndFeedImpl to copy/convert value from. + * @return a real feed with copied/converted values of the SyndFeedImpl. + * + */ + public WireFeed createRealFeed(SyndFeed syndFeed) { + List entries = Collections.synchronizedList(syndFeed.getEntries()); + + HashMap entriesByNode = new HashMap(); + ArrayList doAfterPass = new ArrayList(); // this will hold entries that we can't parent the first time. + ArrayList root = new ArrayList(); // this holds root level outlines; + + for(int i = 0; i < entries.size(); i++) { + SyndEntry entry = (SyndEntry) entries.get(i); + Outline o = new Outline(); + + List cats = Collections.synchronizedList(entry.getCategories()); + boolean parentFound = false; + StringBuffer category = new StringBuffer(); + + for(int j = 0; j < cats.size(); j++) { + SyndCategory cat = (SyndCategory) cats.get(j); + + if((cat.getTaxonomyUri() != null) && + cat.getTaxonomyUri().equals(URI_TREE)) { + String nodeVal = cat.getName() + .substring(cat.getName().lastIndexOf("."), + cat.getName().length()); + + if(cat.getName().startsWith("node.")) { + entriesByNode.put(nodeVal, o); + } else if(cat.getName().startsWith("parent.")) { + parentFound = true; + + Outline parent = (Outline) entriesByNode.get(nodeVal); + + if(parent != null) { + parent.getChildren().add(o); + } else { + doAfterPass.add(new OutlineHolder(o, nodeVal)); + } + } + } else if((cat.getTaxonomyUri() != null) && + cat.getTaxonomyUri().startsWith(URI_ATTRIBUTE)) { + String name = cat.getTaxonomyUri() + .substring(cat.getTaxonomyUri().indexOf("#") + + 1, cat.getTaxonomyUri().length()); + o.getAttributes().add(new Attribute(name, cat.getName())); + } else { + if(category.length() > 0) { + category.append(", "); + } + + category.append(cat.getName()); + } + } + + if(!parentFound) { + root.add(o); + } + + if(category.length() > 0) { + o.getAttributes() + .add(new Attribute("category", category.toString())); + } + + List links = Collections.synchronizedList(entry.getLinks()); + String entryLink = entry.getLink(); + + for(int j = 0; j < links.size(); j++) { + SyndLink link = (SyndLink) links.get(j); + + //if(link.getHref().equals(entryLink)) { + if(((link.getType() != null) && (link.getRel() != null) && + link.getRel().equals("alternate")) && + (link.getType().equals("application/rss+xml") || + link.getType().equals("application/atom+xml"))) { + o.setType("rss"); + + if(o.getXmlUrl() == null) { + o.getAttributes() + .add(new Attribute("xmlUrl", link.getHref())); + } + } else if((link.getType() != null) && + (link.getType().equals("text/html"))) { + if(o.getHtmlUrl() == null) { + o.getAttributes() + .add(new Attribute("htmlUrl", link.getHref())); + } + } else { + o.setType(link.getType()); + } + + //} + } + + if((o.getType() == null) || o.getType().equals("link")) { + o.setText(entry.getTitle()); + + + } else { + o.setTitle(entry.getTitle()); + } + + if((o.getText() == null) && (entry.getDescription() != null)) { + o.setText(entry.getDescription().getValue()); + } + } + + // Do back and parenting for things we missed. + for(int i = 0; i < doAfterPass.size(); i++) { + OutlineHolder o = (OutlineHolder) doAfterPass.get(i); + Outline parent = (Outline) entriesByNode.get(o.parent); + + if(parent == null) { + root.add(o.outline); + LOG.warning("Unable to find parent node :" + o.parent); + } else { + parent.getChildren().add(o.outline); + } + } + + Opml opml = new Opml(); + opml.setFeedType(this.getType()); + opml.setCreated(syndFeed.getPublishedDate()); + opml.setTitle(syndFeed.getTitle()); + + List authors = Collections.synchronizedList(syndFeed.getAuthors()); + + for(int i = 0; i < authors.size(); i++) { + SyndPerson p = (SyndPerson) authors.get(i); + + if((syndFeed.getAuthor() == null) || + syndFeed.getAuthor().equals(p.getName())) { + opml.setOwnerName(p.getName()); + opml.setOwnerEmail(p.getEmail()); + opml.setOwnerId(p.getUri()); + } + } + + opml.setOutlines(root); + + return opml; + } + + /** + * Returns the type (version) of the real feed this converter handles. + *
+ * + * @return the real feed type. + * @see WireFeed for details on the format of this string. + *
+ */ + public String getType() { + return "opml_1.0"; + } + + private static class OutlineHolder { + Outline outline; + String parent; + + public OutlineHolder(Outline outline, String parent) { + this.outline = outline; + this.parent = parent; + } + } + + private static class TreeContext extends Stack { + TreeContext() { + super(); + } + } +} diff --git a/src/main/java/org/rometools/feed/synd/impl/ConverterForOPML20.java b/src/main/java/org/rometools/feed/synd/impl/ConverterForOPML20.java new file mode 100644 index 0000000..25a4e45 --- /dev/null +++ b/src/main/java/org/rometools/feed/synd/impl/ConverterForOPML20.java @@ -0,0 +1,64 @@ +/* + * ConverterForOPML20.java + * + * Created on April 25, 2006, 5:29 PM + * + * To change this template, choose Tools | Template Manager + * and open the template in the editor. + */ +package org.rometools.feed.synd.impl; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.synd.SyndFeed; + + +/** + * + * @author cooper + */ +public class ConverterForOPML20 extends ConverterForOPML10 { + /** Creates a new instance of ConverterForOPML20 */ + public ConverterForOPML20() { + super(); + } + + /** + * Returns the type (version) of the real feed this converter handles. + *
+ * + * @return the real feed type. + * @see WireFeed for details on the format of this string. + *
+ */ + public String getType() { + return "opml_2.0"; + } + + /** + * Makes a deep copy/conversion of the values of a real feed into a SyndFeedImpl. + *
+ * It assumes the given SyndFeedImpl has no properties set. + *
+ * + * @param feed real feed to copy/convert. + * @param syndFeed the SyndFeedImpl that will contain the copied/converted values of the real feed. + */ + public void copyInto(WireFeed feed, SyndFeed syndFeed) { + super.copyInto(feed, syndFeed); + } + + /** + * Creates real feed with a deep copy/conversion of the values of a SyndFeedImpl. + *
+ * + * @param syndFeed SyndFeedImpl to copy/convert value from. + * @return a real feed with copied/converted values of the SyndFeedImpl. + */ + public WireFeed createRealFeed(SyndFeed syndFeed) { + WireFeed retValue; + + retValue = super.createRealFeed(syndFeed); + + return retValue; + } +} diff --git a/src/main/java/org/rometools/feed/synd/impl/TreeCategoryImpl.java b/src/main/java/org/rometools/feed/synd/impl/TreeCategoryImpl.java new file mode 100644 index 0000000..8bb8ac0 --- /dev/null +++ b/src/main/java/org/rometools/feed/synd/impl/TreeCategoryImpl.java @@ -0,0 +1,34 @@ +/* + * TreeCategoryImpl.java + * + * Created on April 27, 2006, 3:44 AM + * + * To change this template, choose Tools | Template Manager + * and open the template in the editor. + */ + +package org.rometools.feed.synd.impl; + +import com.sun.syndication.feed.synd.SyndCategory; +import com.sun.syndication.feed.synd.SyndCategoryImpl; + +/** + * + * @author cooper + */ +public class TreeCategoryImpl extends SyndCategoryImpl { + + /** Creates a new instance of TreeCategoryImpl */ + public TreeCategoryImpl() { + super(); + } + + public boolean equals(Object o) { + SyndCategory c = (SyndCategory) o; + if( c.getTaxonomyUri() != null && c.getTaxonomyUri().equals( this.getTaxonomyUri() ) ) + return true; + else + return false; + } + +} diff --git a/src/main/java/org/rometools/feed/synd/impl/package.html b/src/main/java/org/rometools/feed/synd/impl/package.html new file mode 100644 index 0000000..40f63ad --- /dev/null +++ b/src/main/java/org/rometools/feed/synd/impl/package.html @@ -0,0 +1,30 @@ + + + +
++ * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. ++ + + diff --git a/src/main/java/org/rometools/io/impl/OPML10Generator.java b/src/main/java/org/rometools/io/impl/OPML10Generator.java new file mode 100644 index 0000000..09255ef --- /dev/null +++ b/src/main/java/org/rometools/io/impl/OPML10Generator.java @@ -0,0 +1,189 @@ +/* + * Opml10Generator.java + * + * Created on April 24, 2006, 11:35 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.rometools.io.impl; + +import com.sun.syndication.feed.WireFeed; +import org.rometools.feed.opml.Attribute; +import org.rometools.feed.opml.Opml; +import org.rometools.feed.opml.Outline; +import com.sun.syndication.io.FeedException; +import com.sun.syndication.io.WireFeedGenerator; +import com.sun.syndication.io.impl.BaseWireFeedGenerator; +import com.sun.syndication.io.impl.DateParser; + +import org.jdom.Document; +import org.jdom.Element; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + + +/** + * + * @author Robert "kebernet" Cooper + */ +public class OPML10Generator extends BaseWireFeedGenerator implements WireFeedGenerator { + /** Creates a new instance of Opml10Generator */ + public OPML10Generator() { + super("opml_1.0"); + } + + public OPML10Generator(String type) { + super(type); + } + + /** + * Creates an XML document (JDOM) for the given feed bean. + *
+ * + * @param feed the feed bean to generate the XML document from. + * @return the generated XML document (JDOM). + * @throws IllegalArgumentException thrown if the type of the given feed bean does not + * match with the type of the WireFeedGenerator. + * @throws FeedException thrown if the XML Document could not be created. + */ + public Document generate(WireFeed feed) throws IllegalArgumentException, FeedException { + if (!(feed instanceof Opml)) { + throw new IllegalArgumentException("Not an OPML file"); + } + + Opml opml = (Opml) feed; + Document doc = new Document(); + Element root = new Element("opml"); + doc.addContent(root); + + Element head = generateHead(opml); + + if (head != null) { + root.addContent(head); + } + + Element body = new Element("body"); + root.addContent(body); + super.generateFeedModules(opml.getModules(), root); + body.addContent(generateOutlines(opml.getOutlines())); + + return doc; + } + + protected boolean addNotNullAttribute(Element target, String name, Object value) { + if ((target == null) || (name == null) || (value == null)) { + return false; + } + + target.setAttribute(name, value.toString()); + + return true; + } + + protected boolean addNotNullSimpleElement(Element target, String name, Object value) { + if ((target == null) || (name == null) || (value == null)) { + return false; + } + + Element e = new Element(name); + e.addContent(value.toString()); + target.addContent(e); + + return true; + } + + protected Element generateHead(Opml opml) { + Element head = new Element("head"); + boolean hasHead = false; + + if (opml.getCreated() != null) { + hasHead = addNotNullSimpleElement(head, "dateCreated", DateParser.formatRFC822(opml.getCreated())); + } + + hasHead = addNotNullSimpleElement(head, "expansionState", intArrayToCsvString(opml.getExpansionState())); + + if (opml.getModified() != null) { + hasHead = addNotNullSimpleElement(head, "dateModified", DateParser.formatRFC822(opml.getModified())); + } + + hasHead = addNotNullSimpleElement(head, "ownerEmail", opml.getOwnerEmail()); + hasHead = addNotNullSimpleElement(head, "ownerName", opml.getOwnerName()); + hasHead = addNotNullSimpleElement(head, "title", opml.getTitle()); + hasHead = addNotNullSimpleElement(head, "vertScrollState", opml.getVerticalScrollState()); + hasHead = addNotNullSimpleElement(head, "windowBottom", opml.getWindowBottom()); + hasHead = addNotNullSimpleElement(head, "windowLeft", opml.getWindowLeft()); + hasHead = addNotNullSimpleElement(head, "windowRight", opml.getWindowRight()); + hasHead = addNotNullSimpleElement(head, "windowTop", opml.getWindowTop()); + + if (hasHead) { + return head; + } else { + return null; + } + } + + protected Element generateOutline(Outline outline) { + Element e = new Element("outline"); + addNotNullAttribute(e, "text", outline.getText()); + addNotNullAttribute(e, "type", outline.getType()); + addNotNullAttribute(e, "title", outline.getTitle()); + + if (outline.isBreakpoint()) { + addNotNullAttribute(e, "isBreakpoint", "true"); + } + + if (outline.isComment()) { + addNotNullAttribute(e, "isComment", "true"); + } + + List atts = Collections.synchronizedList(outline.getAttributes()); + + for (int i = 0; i < atts.size(); i++) { + Attribute att = (Attribute) atts.get(i); + addNotNullAttribute(e, att.getName(), att.getValue()); + } + + super.generateItemModules(outline.getModules(), e); + e.addContent(generateOutlines(outline.getChildren())); + + return e; + } + + protected List generateOutlines(List outlines) { + ArrayList elements = new ArrayList(); + + for (int i = 0; (outlines != null) && (i < outlines.size()); i++) { + elements.add(generateOutline((Outline) outlines.get(i))); + } + + return elements; + } + + protected String intArrayToCsvString(int[] value) { + if ((value == null) || (value.length == 0)) { + return null; + } + + StringBuffer sb = new StringBuffer(); + sb.append(value[0]); + + for (int i = 1; i < value.length; i++) { + sb.append(","); + sb.append(value[i]); + } + + return sb.toString(); + } +} diff --git a/src/main/java/org/rometools/io/impl/OPML10Parser.java b/src/main/java/org/rometools/io/impl/OPML10Parser.java new file mode 100644 index 0000000..9935e40 --- /dev/null +++ b/src/main/java/org/rometools/io/impl/OPML10Parser.java @@ -0,0 +1,263 @@ +/* + * Opml10Parser.java + * + * Created on April 24, 2006, 11:34 PM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.rometools.io.impl; + +import com.sun.syndication.feed.WireFeed; +import org.rometools.feed.opml.Attribute; +import org.rometools.feed.opml.Opml; +import org.rometools.feed.opml.Outline; +import com.sun.syndication.io.FeedException; +import com.sun.syndication.io.WireFeedParser; +import com.sun.syndication.io.impl.BaseWireFeedParser; +import com.sun.syndication.io.impl.DateParser; + +import org.jdom.Document; +import org.jdom.Element; + +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * + * @author Robert "kebernet" Cooper + */ +public class OPML10Parser extends BaseWireFeedParser implements WireFeedParser { + private static Logger LOG = Logger.getLogger(OPML10Parser.class.getName()); + + /** Creates a new instance of Opml10Parser */ + public OPML10Parser() { + super("opml_1.0", null); + } + + public OPML10Parser(String type) { + super(type, null); + } + + /** + * Inspects an XML Document (JDOM) to check if it can parse it. + *
+ * It checks if the given document if the type of feeds the parser understands. + *
+ * + * @param document XML Document (JDOM) to check if it can be parsed by this parser. + * @return true if the parser know how to parser this feed, false otherwise. + */ + public boolean isMyType(Document document) { + Element e = document.getRootElement(); + + if (e.getName().equals("opml") + && ( e.getChild("head") == null || e.getChild("head").getChild("docs") == null) + && (e.getAttributeValue("version") == null || e.getAttributeValue("version").equals("1.0"))) { + return true; + } + + return false; + } + + /** + * Parses an XML document (JDOM Document) into a feed bean. + *
+ * + * @param document XML document (JDOM) to parse. + * @param validate indicates if the feed should be strictly validated (NOT YET IMPLEMENTED). + * @return the resulting feed bean. + * @throws IllegalArgumentException thrown if the parser cannot handle the given feed type. + * @throws FeedException thrown if a feed bean cannot be created out of the XML document (JDOM). + */ + public WireFeed parse(Document document, boolean validate) throws IllegalArgumentException, FeedException { + Opml opml = new Opml(); + opml.setFeedType("opml_1.0"); + + Element root = document.getRootElement(); + Element head = root.getChild("head"); + + if (head != null) { + opml.setTitle(head.getChildText("title")); + + if (head.getChildText("dateCreated") != null) { + opml.setCreated(DateParser.parseRFC822(head.getChildText("dateCreated"))); + } + + if (head.getChildText("dateModified") != null) { + opml.setModified(DateParser.parseRFC822(head.getChildText("dateModified"))); + } + + opml.setOwnerName(head.getChildTextTrim("ownerName")); + opml.setOwnerEmail(head.getChildTextTrim("ownerEmail")); + opml.setVerticalScrollState(readInteger(head.getChildText("vertScrollState"))); + } + + try { + opml.setWindowBottom(readInteger(head.getChildText("windowBottom"))); + } catch (NumberFormatException nfe) { + LOG.log(Level.WARNING, "Unable to parse windowBottom", nfe); + + if (validate) { + throw new FeedException("Unable to parse windowBottom", nfe); + } + } + + try { + opml.setWindowLeft(readInteger(head.getChildText("windowLeft"))); + } catch (NumberFormatException nfe) { + LOG.log(Level.WARNING, "Unable to parse windowLeft", nfe); + } + + try { + opml.setWindowRight(readInteger(head.getChildText("windowRight"))); + } catch (NumberFormatException nfe) { + LOG.log(Level.WARNING, "Unable to parse windowRight", nfe); + + if (validate) { + throw new FeedException("Unable to parse windowRight", nfe); + } + } + + try { + opml.setWindowLeft(readInteger(head.getChildText("windowLeft"))); + } catch (NumberFormatException nfe) { + LOG.log(Level.WARNING, "Unable to parse windowLeft", nfe); + + if (validate) { + throw new FeedException("Unable to parse windowLeft", nfe); + } + } + + try { + opml.setWindowTop(readInteger(head.getChildText("windowTop"))); + } catch (NumberFormatException nfe) { + LOG.log(Level.WARNING, "Unable to parse windowTop", nfe); + + if (validate) { + throw new FeedException("Unable to parse windowTop", nfe); + } + } + + try { + opml.setExpansionState(readIntArray(head.getChildText("expansionState"))); + } catch (NumberFormatException nfe) { + LOG.log(Level.WARNING, "Unable to parse expansionState", nfe); + + if (validate) { + throw new FeedException("Unable to parse expansionState", nfe); + } + } + + opml.setOutlines(parseOutlines(root.getChild("body").getChildren("outline"), validate)); + opml.setModules(this.parseFeedModules(root)); + + return opml; + } + + protected Outline parseOutline(Element e, boolean validate) throws FeedException { + if (!e.getName().equals("outline")) { + throw new RuntimeException("Not an outline element."); + } + + Outline outline = new Outline(); + outline.setText(e.getAttributeValue("text")); + outline.setType(e.getAttributeValue("type")); + outline.setTitle(e.getAttributeValue("title")); + + List jAttributes = e.getAttributes(); + ArrayList attributes = new ArrayList(); + + for (int i = 0; i < jAttributes.size(); i++) { + org.jdom.Attribute a = (org.jdom.Attribute) jAttributes.get(i); + + if (!a.getName().equals("isBreakpoint") && !a.getName().equals("isComment") && !a.getName().equals("title") && !a.getName().equals("text") && !a.getName().equals("type")) { + attributes.add(new Attribute(a.getName(), a.getValue())); + } + } + + outline.setAttributes(attributes); + + try { + outline.setBreakpoint(readBoolean(e.getAttributeValue("isBreakpoint"))); + } catch (Exception ex) { + LOG.log(Level.WARNING, "Unable to parse isBreakpoint value", ex); + + if (validate) { + throw new FeedException("Unable to parse isBreakpoint value", ex); + } + } + + try { + outline.setComment(readBoolean(e.getAttributeValue("isComment"))); + } catch (Exception ex) { + LOG.log(Level.WARNING, "Unable to parse isComment value", ex); + + if (validate) { + throw new FeedException("Unable to parse isComment value", ex); + } + } + + List children = e.getChildren("outline"); + outline.setModules(this.parseItemModules(e)); + outline.setChildren(parseOutlines(children, validate)); + + return outline; + } + + protected List parseOutlines(List elements, boolean validate) throws FeedException { + ArrayList results = new ArrayList(); + + for (int i = 0; i < elements.size(); i++) { + results.add(parseOutline((Element) elements.get(i), validate)); + } + + return results; + } + + protected boolean readBoolean(String value) { + if (value == null) { + return false; + } else { + return Boolean.getBoolean(value.trim()); + } + } + + protected int[] readIntArray(String value) { + if (value == null) { + return null; + } else { + StringTokenizer tok = new StringTokenizer(value, ","); + int[] result = new int[tok.countTokens()]; + int count = 0; + + while (tok.hasMoreElements()) { + result[count] = Integer.parseInt(tok.nextToken().trim()); + count++; + } + + return result; + } + } + + protected Integer readInteger(String value) { + if (value != null) { + return new Integer(value); + } else { + return null; + } + } +} diff --git a/src/main/java/org/rometools/io/impl/OPML20Generator.java b/src/main/java/org/rometools/io/impl/OPML20Generator.java new file mode 100644 index 0000000..7793ee8 --- /dev/null +++ b/src/main/java/org/rometools/io/impl/OPML20Generator.java @@ -0,0 +1,83 @@ +/* + * OPML20Generator.java + * + * Created on April 25, 2006, 5:31 PM + * + * To change this template, choose Tools | Template Manager + * and open the template in the editor. + */ +package org.rometools.io.impl; + +import com.sun.syndication.feed.WireFeed; +import org.rometools.feed.opml.Opml; +import org.rometools.feed.opml.Outline; +import com.sun.syndication.io.FeedException; +import com.sun.syndication.io.impl.DateParser; + +import org.jdom.Document; +import org.jdom.Element; + + +/** + * + * @author cooper + */ +public class OPML20Generator extends OPML10Generator { + /** Creates a new instance of OPML20Generator */ + public OPML20Generator() { + } + + /** + * Returns the type of feed the generator creates. + *
+ * + * @return the type of feed the generator creates. + * @see WireFeed for details on the format of this string. + *
+ */ + public String getType() { + return "opml_2.0"; + } + + /** + * Creates an XML document (JDOM) for the given feed bean. + *
+ * + * @param feed the feed bean to generate the XML document from. + * @return the generated XML document (JDOM). + * @throws IllegalArgumentException thrown if the type of the given feed bean does not + * match with the type of the WireFeedGenerator. + * @throws FeedException thrown if the XML Document could not be created. + */ + public Document generate(WireFeed feed) throws IllegalArgumentException, FeedException { + Document retValue; + + retValue = super.generate(feed); + retValue.getRootElement().setAttribute("version", "2.0"); + + return retValue; + } + + protected Element generateHead(Opml opml) { + Element retValue; + + retValue = super.generateHead(opml); + + Element docs = new Element("docs", opml.getDocs()); + retValue.addContent(docs); + + return retValue; + } + + protected Element generateOutline(Outline outline) { + Element retValue; + + retValue = super.generateOutline(outline); + + if (outline.getCreated() != null) { + retValue.setAttribute("created", DateParser.formatRFC822(outline.getCreated())); + } + + return retValue; + } +} diff --git a/src/main/java/org/rometools/io/impl/OPML20Parser.java b/src/main/java/org/rometools/io/impl/OPML20Parser.java new file mode 100644 index 0000000..5aaabff --- /dev/null +++ b/src/main/java/org/rometools/io/impl/OPML20Parser.java @@ -0,0 +1,117 @@ +/* + * Opml20Parser.java + * + * Created on April 25, 2006, 1:04 AM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.rometools.io.impl; + +import com.sun.syndication.feed.WireFeed; +import org.rometools.feed.opml.Attribute; +import org.rometools.feed.opml.Opml; +import org.rometools.feed.opml.Outline; +import com.sun.syndication.io.FeedException; +import com.sun.syndication.io.impl.DateParser; + +import org.jdom.Document; +import org.jdom.Element; + +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + + +/** + * + * @author cooper + */ +public class OPML20Parser extends OPML10Parser { + /** Creates a new instance of Opml20Parser */ + public OPML20Parser() { + super("opml_2.0"); + } + + /** + * Inspects an XML Document (JDOM) to check if it can parse it. + *
+ * It checks if the given document if the type of feeds the parser understands. + *
+ * + * @param document XML Document (JDOM) to check if it can be parsed by this parser. + * @return true if the parser know how to parser this feed, false otherwise. + */ + public boolean isMyType(Document document) { + Element e = document.getRootElement(); + + if (e.getName().equals("opml") && (((e.getChild("head") != null) && (e.getChild("head").getChild("docs") != null)) || ((e.getAttributeValue("version") != null) && e.getAttributeValue("version").equals("2.0")) || ((e.getChild("head") != null) && (e.getChild("head").getChild("ownerId") != null)))) { + return true; + } + + return false; + } + + /** + * Parses an XML document (JDOM Document) into a feed bean. + *
+ * + * @param document XML document (JDOM) to parse. + * @param validate indicates if the feed should be strictly validated (NOT YET IMPLEMENTED). + * @return the resulting feed bean. + * @throws IllegalArgumentException thrown if the parser cannot handle the given feed type. + * @throws FeedException thrown if a feed bean cannot be created out of the XML document (JDOM). + */ + public WireFeed parse(Document document, boolean validate) throws IllegalArgumentException, FeedException { + Opml opml; + opml = (Opml) super.parse(document, validate); + + Element head = document.getRootElement().getChild("head"); + + if (head != null) { + opml.setOwnerId(head.getChildTextTrim("ownerId")); + opml.setDocs(head.getChildTextTrim("docs")); + + if (opml.getDocs() == null) { + opml.setDocs("http://www.opml.org/spec2"); + } + } + + opml.setFeedType("opml_2.0"); + + return opml; + } + + protected Outline parseOutline(Element e, boolean validate) throws FeedException { + Outline retValue; + + retValue = super.parseOutline(e, validate); + + if (e.getAttributeValue("created") != null) { + retValue.setCreated(DateParser.parseRFC822(e.getAttributeValue("created"))); + } + + List atts = retValue.getAttributes(); + + for (int i = 0; i < atts.size(); i++) { + Attribute a = (Attribute) atts.get(i); + + if (a.getName().equals("created")) { + retValue.getAttributes().remove(a); + + break; + } + } + + return retValue; + } +} diff --git a/src/main/java/org/rometools/io/impl/package.html b/src/main/java/org/rometools/io/impl/package.html new file mode 100644 index 0000000..64d1989 --- /dev/null +++ b/src/main/java/org/rometools/io/impl/package.html @@ -0,0 +1,28 @@ + + + +
++ * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. ++ + + diff --git a/src/test/java/org/rometools/unittest/FeedOpsTest.java b/src/test/java/org/rometools/unittest/FeedOpsTest.java new file mode 100644 index 0000000..36b88ac --- /dev/null +++ b/src/test/java/org/rometools/unittest/FeedOpsTest.java @@ -0,0 +1,114 @@ +package org.rometools.unittest; + +import com.sun.syndication.feed.WireFeed; +import com.sun.syndication.feed.synd.SyndFeed; +import com.sun.syndication.feed.synd.SyndFeedImpl; + +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.ObjectInputStream; + +/** + * + *
+ * @author Alejandro Abdelnur
+ *
+ */
+public abstract class FeedOpsTest extends FeedTest {
+
+ protected FeedOpsTest(String feedType) {
+ super(feedType+".xml");
+ System.out.println("Testing "+feedType+".xml");
+ new File("target/test-reports").mkdirs();
+ }
+
+ //1.2a
+ public void testWireFeedEquals() throws Exception {
+ WireFeed feed1 = getCachedWireFeed();
+ WireFeed feed2 = getWireFeed();
+ assertTrue(feed1.equals(feed2));
+ }
+
+ //1.2b
+ public void testWireFeedNotEqual() throws Exception {
+ WireFeed feed1 = getCachedWireFeed();
+ WireFeed feed2 = getWireFeed();
+ feed2.setFeedType("dummy");
+ assertFalse(feed1.equals(feed2));
+ }
+
+ //1.3
+ public void testWireFeedCloning() throws Exception {
+ WireFeed feed1 = getCachedWireFeed();
+ WireFeed feed2 = (WireFeed) feed1.clone();;
+ assertTrue(feed1.equals(feed2));
+ }
+
+ // 1.4
+ public void testWireFeedSerialization() throws Exception {
+ WireFeed feed1 = getCachedWireFeed();
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(feed1);
+ oos.close();
+
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ ObjectInputStream ois = new ObjectInputStream(bais);
+ WireFeed feed2 = (WireFeed) ois.readObject();
+ ois.close();
+
+ assertTrue(feed1.equals(feed2));
+ }
+
+ // 1.6
+ public void testWireFeedSyndFeedConversion() throws Exception {
+ SyndFeed sFeed1 = getCachedSyndFeed();
+ WireFeed wFeed1 = sFeed1.createWireFeed();
+ SyndFeed sFeed2 = new SyndFeedImpl(wFeed1);
+
+ assertEquals(sFeed1, sFeed2 );
+ }
+
+ //1.7a
+ public void testSyndFeedEquals() throws Exception {
+ SyndFeed feed1 = getCachedSyndFeed();
+ SyndFeed feed2 = getSyndFeed();
+ assertTrue(feed1.equals(feed2));
+ }
+
+ //1.7b
+ public void testSyndFeedNotEqual() throws Exception {
+ SyndFeed feed1 = getCachedSyndFeed();
+ SyndFeed feed2 = getSyndFeed();
+ feed2.setFeedType("dummy");
+ assertFalse(feed1.equals(feed2));
+ }
+
+ //1.8
+ public void testSyndFeedCloning() throws Exception {
+ SyndFeed feed1 = getCachedSyndFeed();
+ SyndFeed feed2 = (SyndFeed) feed1.clone();;
+ assertTrue(feed1.equals(feed2));
+ }
+
+ //1.9
+ public void testSyndFeedSerialization() throws Exception {
+ SyndFeed feed1 = getCachedSyndFeed();
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(feed1);
+ oos.close();
+
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ ObjectInputStream ois = new ObjectInputStream(bais);
+ SyndFeed feed2 = (SyndFeed) ois.readObject();
+ ois.close();
+
+ assertTrue(feed1.equals(feed2));
+ }
+
+}
diff --git a/src/test/java/org/rometools/unittest/FeedTest.java b/src/test/java/org/rometools/unittest/FeedTest.java
new file mode 100644
index 0000000..676cd93
--- /dev/null
+++ b/src/test/java/org/rometools/unittest/FeedTest.java
@@ -0,0 +1,78 @@
+package org.rometools.unittest;
+
+import junit.framework.TestCase;
+
+import com.sun.syndication.feed.synd.SyndFeed;
+import com.sun.syndication.feed.WireFeed;
+import com.sun.syndication.io.SyndFeedInput;
+import com.sun.syndication.io.WireFeedInput;
+
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.InputStream;
+
+import org.jdom.Document;
+import org.jdom.input.SAXBuilder;
+
+/**
+ * @author pat, tucu
+ *
+ */
+public abstract class FeedTest extends TestCase {
+ private String _feedFileName;
+ private Document _jDomDoc = null;
+ private WireFeed _wireFeed = null;
+ private SyndFeed _syndFeed = null;
+
+ protected FeedTest(String feedFileName) {
+ _feedFileName = feedFileName;
+ }
+
+ protected String getFeedFileName() {
+ return _feedFileName;
+ }
+
+ protected Reader getFeedReader() throws Exception {
+ InputStream resource = Thread.currentThread().
+ getContextClassLoader().getResourceAsStream(getFeedFileName());
+ assertNotNull("Could not find resource " + getFeedFileName(), resource);
+ return new InputStreamReader(resource);
+ }
+
+ protected Document getJDomDoc() throws Exception {
+ SAXBuilder saxBuilder = new SAXBuilder(false);
+ return saxBuilder.build(getFeedReader());
+ }
+
+ protected WireFeed getWireFeed() throws Exception {
+ WireFeedInput in = new WireFeedInput();
+ return in.build(getFeedReader());
+ }
+
+ protected SyndFeed getSyndFeed() throws Exception {
+ SyndFeedInput in = new SyndFeedInput();
+ return in.build(getFeedReader());
+ }
+
+ protected Document getCachedJDomDoc() throws Exception {
+ if (_jDomDoc==null) {
+ _jDomDoc = getJDomDoc();
+ }
+ return _jDomDoc;
+ }
+
+ protected WireFeed getCachedWireFeed() throws Exception {
+ if (_wireFeed==null) {
+ _wireFeed = getWireFeed();
+ }
+ return _wireFeed;
+ }
+
+ protected SyndFeed getCachedSyndFeed() throws Exception {
+ if (_syndFeed==null) {
+ _syndFeed = getSyndFeed();
+ }
+ return _syndFeed;
+ }
+
+}
diff --git a/src/test/java/org/rometools/unittest/SyndFeedTest.java b/src/test/java/org/rometools/unittest/SyndFeedTest.java
new file mode 100644
index 0000000..8bdddde
--- /dev/null
+++ b/src/test/java/org/rometools/unittest/SyndFeedTest.java
@@ -0,0 +1,267 @@
+/*
+ * Created on Jun 22, 2004
+ *
+ * TODO To change the template for this generated file go to
+ * Window - Preferences - Java - Code Generation - Code and Comments
+ */
+package org.rometools.unittest;
+
+
+
+
+/**
+ * @author pat
+ *
+ */
+public abstract class SyndFeedTest extends FeedTest {
+ private String _prefix = null;
+
+ protected SyndFeedTest(String feedType) {
+ this(feedType,feedType+".xml");
+ }
+
+ protected SyndFeedTest(String feedType,String feedFileName) {
+ super(feedFileName);
+ _prefix = feedType;
+ }
+
+ protected String getPrefix() {
+ return _prefix;
+ }
+
+ protected void assertProperty(String property, String value) {
+ assertEquals(property,getPrefix() + "." + value);
+ }
+
+ public void testType() throws Exception {
+ assertEquals(getCachedSyndFeed().getFeedType(),getPrefix());
+ }
+
+
+/*
+ public void testType() throws Exception {
+ assertEquals(getPrefix(), getCachedSyndFeed().getFeedType());
+ }
+
+ public void testTitle() throws Exception {
+ assertEqualsStr("channel.title", getCachedSyndFeed().getTitle());
+ }
+
+ public void testLink() throws Exception {
+ assertEqualsStr("channel.link", getCachedSyndFeed().getLink());
+ }
+
+ public void testDescription() throws Exception {
+ assertEqualsStr("channel.description", getCachedSyndFeed().getDescription());
+ }
+
+ public void testLanguage() throws Exception {
+ assertEqualsStr("channel.language", getCachedSyndFeed().getLanguage());
+ }
+
+ public void testCategories() throws Exception {
+ List catlist = getCachedSyndFeed().getCategories();
+ //don't understand why this one fails
+ assertEquals(2, catlist.size());
+ SyndCategory cat = (SyndCategory)catlist.get(0);
+ assertEqualsStr("channel.category[0]", cat.getName());
+ assertEqualsStr("channel.category[0]^domain", cat.getTaxonomyUri());
+ cat = (SyndCategory)catlist.get(1);
+ assertEqualsStr("channel.category[1]", cat.getName());
+ assertEqualsStr("channel.category[1]^domain", cat.getTaxonomyUri());
+ }
+
+ public void testPublishedDate() throws Exception {
+ assertEquals(DateParser.parseRFC822("Mon, 01 Jan 2001 00:00:00 GMT"), getCachedSyndFeed().getPublishedDate());
+ }
+
+ //how do i get height and width?
+ public void testImage() throws Exception {
+ SyndImage img = getCachedSyndFeed().getImage();
+ assertEqualsStr("channel.image.description", img.getDescription());
+ assertEqualsStr("channel.image.link", img.getLink());
+ assertEqualsStr("channel.image.title", img.getTitle());
+ assertEqualsStr("channel.image.url", img.getUrl());
+ }
+
+ public void testEntries() throws Exception {
+ List entrylist = getCachedSyndFeed().getEntries();
+ assertEquals(2, entrylist.size());
+ }
+
+ public void testEntryTitle() throws Exception {
+ assertEqualsStr("channel.item[0].title", getEntryTitle(getCachedSyndFeed().getEntries().get(0)));
+ assertEqualsStr("channel.item[1].title", getEntryTitle(getCachedSyndFeed().getEntries().get(1)));
+ }
+
+ public String getEntryTitle(Object o) throws Exception {
+ SyndEntry e = (SyndEntry) o;
+ return e.getTitle();
+ }
+
+ public void testEntryDescription() throws Exception {
+ assertEqualsStr("channel.item[0].description", getEntryDescription(getCachedSyndFeed().getEntries().get(0)));
+ assertEqualsStr("channel.item[1].description", getEntryDescription(getCachedSyndFeed().getEntries().get(1)));
+ }
+
+ public String getEntryDescription(Object o) throws Exception {
+ SyndEntry e = (SyndEntry) o;
+ return e.getDescription().getValue();
+ }
+
+ public void testEntryLink() throws Exception {
+ assertEqualsStr("channel.item[0].link", getEntryLink(getCachedSyndFeed().getEntries().get(0)));
+ assertEqualsStr("channel.item[1].link", getEntryLink(getCachedSyndFeed().getEntries().get(1)));
+ }
+
+ public String getEntryLink(Object o) {
+ SyndEntry e = (SyndEntry) o;
+ return e.getLink();
+ }
+
+ public void testEntryPublishedDate() throws Exception {
+ assertEquals(DateParser.parseRFC822("Mon, 01 Jan 2001 00:00:00 GMT"), getEntryPublishedDate(getCachedSyndFeed().getEntries().get(0)));
+ assertEquals(DateParser.parseRFC822("Mon, 01 Jan 2001 00:00:00 GMT"), getEntryPublishedDate(getCachedSyndFeed().getEntries().get(1)));
+ }
+
+ public Date getEntryPublishedDate(Object o) {
+ SyndEntry e = (SyndEntry) o;
+ return e.getPublishedDate();
+ }
+
+ public void testEntryCategories() throws Exception {
+ SyndEntry e = (SyndEntry)getCachedSyndFeed().getEntries().get(0);
+ List catlist = e.getCategories();
+ //don't understand why this one fails
+ assertEquals(2, catlist.size());
+ SyndCategory cat = (SyndCategory)catlist.get(0);
+ assertEqualsStr("channel.item[0].category[0]", cat.getName());
+ assertEqualsStr("channel.item[0].category[0]^domain", cat.getTaxonomyUri());
+ cat = (SyndCategory)catlist.get(1);
+ assertEqualsStr("channel.item[0].category[1]", cat.getName());
+ assertEqualsStr("channel.item[0].category[1]^domain", cat.getTaxonomyUri());
+ //DO 2nd set of items
+ }
+
+ public void testEntryAuthor() throws Exception {
+ assertEqualsStr("channel.item[0].author", getEntryAuthor(getCachedSyndFeed().getEntries().get(0)));
+ assertEqualsStr("channel.item[1].author", getEntryAuthor(getCachedSyndFeed().getEntries().get(1)));
+ }
+
+ public String getEntryAuthor(Object o) {
+ SyndEntry e = (SyndEntry) o;
+ return e.getAuthor();
+ }
+
+*/
+/*
+//things you cannot get from SyndEntryImpl
+//