/* ********************************************************************** **
** Copyright notice **
** **
** (c) 2005-2009 RSSOwl Development Team **
** http://www.rssowl.org/ **
** **
** All rights reserved **
** **
** This program and the accompanying materials are made available under **
** the terms of the Eclipse Public License v1.0 which accompanies this **
** distribution, and is available at: **
** http://www.rssowl.org/legal/epl-v10.html **
** **
** A copy is found in the file epl-v10.html and important notices to the **
** license from the team is found in the textfile LICENSE.txt distributed **
** in this package. **
** **
** This copyright notice MUST APPEAR in all copies of the file! **
** **
** Contributors: **
** RSSOwl Development Team - initial API and implementation **
** **
** ********************************************************************** */
package org.rssowl.core.internal.interpreter;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.XMLOutputter;
import org.rssowl.core.Owl;
import org.rssowl.core.persist.IAttachment;
import org.rssowl.core.persist.ICategory;
import org.rssowl.core.persist.IEntity;
import org.rssowl.core.persist.IFeed;
import org.rssowl.core.persist.IGuid;
import org.rssowl.core.persist.IImage;
import org.rssowl.core.persist.INews;
import org.rssowl.core.persist.IPersistable;
import org.rssowl.core.persist.IPerson;
import org.rssowl.core.persist.ISource;
import org.rssowl.core.util.DateUtils;
import org.rssowl.core.util.StringUtils;
import org.rssowl.core.util.URIUtils;
import java.io.IOException;
import java.io.StringWriter;
import java.net.URI;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
/**
* Interpreter for all Atom Formats.
*
* @author bpasero
*/
public class AtomInterpreter extends BasicInterpreter {
private int fNewsCounter;
/*
* @see org.rssowl.core.interpreter.IFormatInterpreter#interpret(org.jdom.Document,
* org.rssowl.core.interpreter.types.IFeed)
*/
public void interpret(Document document, IFeed feed) {
Element root = document.getRootElement();
setDefaultNamespaceUri(root.getNamespace().getURI());
setRootElementName(root.getName());
feed.setFormat("Atom 1.0"); //$NON-NLS-1$
processFeed(root, feed);
}
private void processFeed(Element element, IFeed feed) {
/* Interpret Attributes */
List< ? > attributes = element.getAttributes();
for (Iterator< ? > iter = attributes.iterator(); iter.hasNext();) {
Attribute attribute = (Attribute) iter.next();
String name = attribute.getName();
/* Check wether this Attribute is to be processed by a Contribution */
if (processAttributeExtern(attribute, feed))
continue;
/* Version */
else if ("version".equals(name)) //$NON-NLS-1$
feed.setFormat(buildFormat("Atom", attribute.getValue())); //$NON-NLS-1$
/* Language */
else if ("lang".equals(name)) //$NON-NLS-1$
feed.setLanguage(attribute.getValue());
}
/* Interpret Children */
List< ? > channelChildren = element.getChildren();
for (Iterator< ? > iter = channelChildren.iterator(); iter.hasNext();) {
Element child = (Element) iter.next();
String name = child.getName().toLowerCase();
/* Check wether this Element is to be processed by a Contribution */
if (processElementExtern(child, feed))
continue;
/* Title */
else if ("title".equals(name)) { //$NON-NLS-1$
feed.setTitle(getContent(child));
processNamespaceAttributes(child, feed);
}
/* Tagline / Subtitle */
else if ("tagline".equals(name) || "subtitle".equals(name)) { //$NON-NLS-1$ //$NON-NLS-2$
feed.setDescription(getContent(child));
processNamespaceAttributes(child, feed);
}
/* Generator */
else if ("generator".equals(name)) { //$NON-NLS-1$
feed.setGenerator(getContent(child));
processNamespaceAttributes(child, feed);
}
/* Copyright / Rights */
else if ("copyright".equals(name) || "rights".equals(name)) { //$NON-NLS-1$ //$NON-NLS-2$
feed.setCopyright(getContent(child));
processNamespaceAttributes(child, feed);
}
/* Logo */
else if ("logo".equals(name)) { //$NON-NLS-1$
IImage image = Owl.getModelFactory().createImage(feed);
URI uri = URIUtils.createURI(child.getText());
if (uri != null)
image.setLink(uri);
processNamespaceAttributes(child, image);
}
/* Modified / Updated */
else if ("modified".equals(name) || "updated".equals(name)) { //$NON-NLS-1$ //$NON-NLS-2$
feed.setLastModifiedDate(DateUtils.parseDate(child.getText()));
processNamespaceAttributes(child, feed);
}
/* Link */
else if ("link".equals(name)) { //$NON-NLS-1$
String rel = child.getAttributeValue("rel"); //$NON-NLS-1$
if ("alternate".equals(rel)) { //$NON-NLS-1$
URI uri = URIUtils.createURI(child.getAttributeValue("href")); //$NON-NLS-1$
if (uri != null)
feed.setHomepage(uri);
}
processNamespaceAttributes(child, feed);
}
/* Entry */
else if ("entry".equals(name)) //$NON-NLS-1$
processEntry(child, feed);
/* Category */
else if ("category".equals(name)) //$NON-NLS-1$
processCategory(child, feed);
/* Author */
else if ("author".equals(name)) //$NON-NLS-1$
processAuthor(child, feed);
}
}
private void processEntry(Element element, IFeed feed) {
INews news = Owl.getModelFactory().createNews(null, feed, new Date(System.currentTimeMillis() - (fNewsCounter++ * 1)));
news.setBase(feed.getBase());
/* Check whether the Attributes are to be processed by a Contribution */
processNamespaceAttributes(element, news);
/* Interpret Children */
List< ? > newsChilds = element.getChildren();
for (Iterator< ? > iter = newsChilds.iterator(); iter.hasNext();) {
Element child = (Element) iter.next();
String name = child.getName().toLowerCase();
/* Check whether this Element is to be processed by a Contribution */
if (processElementExtern(child, news))
continue;
/* Title */
else if ("title".equals(name)) { //$NON-NLS-1$
news.setTitle(getContent(child));
processNamespaceAttributes(child, news);
}
/* Content / Summary */
else if ("content".equals(name) || "summary".equals(name)) { //$NON-NLS-1$ //$NON-NLS-2$
news.setDescription(getContent(child));
processNamespaceAttributes(child, news);
}
/* Modified / Updated */
else if ("modified".equals(name) || "updated".equals(name)) { //$NON-NLS-1$ //$NON-NLS-2$
news.setModifiedDate(DateUtils.parseDate(child.getText()));
processNamespaceAttributes(child, news);
}
/* Issued / Created / Published */
else if ("issued".equals(name) || "created".equals(name) || "published".equals(name)) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
news.setPublishDate(DateUtils.parseDate(child.getText()));
processNamespaceAttributes(child, news);
}
/* Id */
else if ("id".equals(name)) { //$NON-NLS-1$
IGuid guid = Owl.getModelFactory().createGuid(news, child.getText(), null);
processNamespaceAttributes(child, guid);
}
/* Link */
else if ("link".equals(name)) { //$NON-NLS-1$
String rel = child.getAttributeValue("rel"); //$NON-NLS-1$
/* News Link */
if (rel == null || "alternate".equals(rel)) {//$NON-NLS-1$
URI uri = URIUtils.createURI(child.getAttributeValue("href")); //$NON-NLS-1$
if (uri != null)
news.setLink(uri);
processNamespaceAttributes(child, news);
}
/* Enclosure */
else if ("enclosure".equals(rel)) { //$NON-NLS-1$
IAttachment attachment = Owl.getModelFactory().createAttachment(null, news);
URI uri = URIUtils.createURI(child.getAttributeValue("href")); //$NON-NLS-1$
if (uri != null)
attachment.setLink(uri);
attachment.setType(child.getAttributeValue("type")); //$NON-NLS-1$
attachment.setLength(StringUtils.stringToInt(child.getAttributeValue("length"))); //$NON-NLS-1$
processNamespaceAttributes(child, attachment);
}
}
/* Category */
else if ("category".equals(name)) //$NON-NLS-1$
processCategory(child, news);
/* Source */
else if ("source".equals(name)) //$NON-NLS-1$
processSource(child, news);
/* Author */
else if ("author".equals(name)) //$NON-NLS-1$
processAuthor(child, news);
}
}
private String getContent(Element element) {
String type = element.getAttributeValue("type"); //$NON-NLS-1$
/* XHTML Type makes use of a single <DIV> to surround the XHTML */
if ("xhtml".equals(type) || "application/xhtml+xml".equals(type)) { //$NON-NLS-1$ //$NON-NLS-2$
List< ? > children = element.getChildren();
for (Iterator< ? > iter = children.iterator(); iter.hasNext();) {
Element contentChild = (Element) iter.next();
String name = contentChild.getName();
/* Expected DIV Child */
if ("div".equals(name)) { //$NON-NLS-1$
XMLOutputter out = new XMLOutputter();
StringWriter writer = new StringWriter();
try {
out.output(contentChild.getContent(), writer);
writer.close();
} catch (IOException e) {
/* This should not happen */
}
/* Get Text */
String content = writer.toString();
/*
* Problem: This Method of writing the content of the xmlDiv into the
* StringWriter is not taking care of any CDATA-Constructs inside, as
* no XML-parsing is done. The workaround is to manually remove the
* CDATA-Tags. This has the same effect as parsing, since CDATA is to
* be taken as is, with no element or entitiy processing.
*/
if (content.contains("<![CDATA[")) { //$NON-NLS-1$
content = StringUtils.replaceAll(content, "<![CDATA[", ""); //$NON-NLS-1$ //$NON-NLS-2$
content = StringUtils.replaceAll(content, "]]>", ""); //$NON-NLS-1$//$NON-NLS-2$
}
/* Return text */
return content;
}
}
}
/* Return text and html as is */
return element.getText();
}
private void processSource(Element element, INews news) {
ISource source = Owl.getModelFactory().createSource(news);
/* Check wether the Attributes are to be processed by a Contribution */
processNamespaceAttributes(element, source);
/* Interpret Children */
List< ? > sourceChilds = element.getChildren();
for (Iterator< ? > iter = sourceChilds.iterator(); iter.hasNext();) {
Element child = (Element) iter.next();
String name = child.getName().toLowerCase();
/* Check wether this Element is to be processed by a Contribution */
if (processElementExtern(child, source))
continue;
/* Name */
else if ("title".equals(name)) { //$NON-NLS-1$
source.setName(child.getText());
processNamespaceAttributes(child, source);
}
/* EMail */
else if ("link".equals(name)) { //$NON-NLS-1$
URI uri = URIUtils.createURI(child.getText());
if (uri != null)
source.setLink(uri);
processNamespaceAttributes(child, source);
}
/* URI */
else if ("id".equals(name) && source.getLink() == null) { //$NON-NLS-1$
URI uri = URIUtils.createURI(child.getText());
if (uri != null)
source.setLink(uri);
processNamespaceAttributes(child, source);
}
}
}
private void processCategory(Element element, IEntity type) {
ICategory category = Owl.getModelFactory().createCategory(null, type);
/* Interpret Attributes */
List< ? > categoryAttributes = element.getAttributes();
for (Iterator< ? > iter = categoryAttributes.iterator(); iter.hasNext();) {
Attribute attribute = (Attribute) iter.next();
String name = attribute.getName().toLowerCase();
/* Check wether this Attribute is to be processed by a Contribution */
if (processAttributeExtern(attribute, category))
continue;
/* Term */
else if ("term".equals(name)) {//$NON-NLS-1$
category.setDomain(attribute.getValue());
/* Use as Name if not yet set */
if (category.getName() == null)
category.setName(attribute.getValue());
}
/* Label */
else if ("label".equals(name)) //$NON-NLS-1$
category.setName(attribute.getValue());
}
}
private void processAuthor(Element element, IPersistable type) {
IPerson person = Owl.getModelFactory().createPerson(null, type);
/* Check wether the Attributes are to be processed by a Contribution */
processNamespaceAttributes(element, person);
/* Interpret Children */
List< ? > personChilds = element.getChildren();
for (Iterator< ? > iter = personChilds.iterator(); iter.hasNext();) {
Element child = (Element) iter.next();
String name = child.getName().toLowerCase();
/* Check wether this Element is to be processed by a Contribution */
if (processElementExtern(child, person))
continue;
/* Name */
else if ("name".equals(name)) { //$NON-NLS-1$
person.setName(child.getText());
processNamespaceAttributes(child, person);
}
/* EMail */
else if ("email".equals(name)) { //$NON-NLS-1$
URI uri = URIUtils.createURI(child.getText());
if (uri != null)
person.setEmail(uri);
processNamespaceAttributes(child, person);
}
/* URI */
else if ("uri".equals(name)) { //$NON-NLS-1$
URI uri = URIUtils.createURI(child.getText());
if (uri != null)
person.setUri(uri);
processNamespaceAttributes(child, person);
}
}
}
}