2 * Copyright (C) 2001, 2002 The Mir-coders group
4 * This file is part of Mir.
6 * Mir is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Mir is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Mir; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * In addition, as a special exception, The Mir-coders gives permission to link
21 * the code of this program with any library licensed under the Apache Software License,
22 * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23 * (or with modified versions of the above that use the same license as the above),
24 * and distribute linked combinations including the two. You must obey the
25 * GNU General Public License in all respects for all of the code used other than
26 * the above mentioned libraries. If you modify this file, you may extend this
27 * exception to your version of the file, but you are not obligated to do so.
28 * If you do not wish to do so, delete this exception statement from your version.
32 import java.io.InputStream;
34 import java.util.List;
36 import java.util.Vector;
39 import mir.util.XMLReader;
45 * <p>Description: </p>
46 * <p>Copyright: Copyright (c) 2003</p>
48 * @author not attributable
52 public class RSSReader {
53 public static final String RDF_NAMESPACE_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
54 public static final String RSS_1_0_NAMESPACE_URI = "http://purl.org/rss/1.0/";
55 public static final String DUBLINCORE_NAMESPACE_URI = "http://purl.org/dc/elements/1.1/";
56 public static final String EVENT_NAMESPACE_URI = "http://purl.org/rss/1.0/modules/event/";
57 public static final String TAXONOMY_NAMESPACE_URI = "http://web.resource.org/rss/1.0/modules/taxonomy/";
58 public static final String DUBLINCORE_TERMS_NAMESPACE_URI = "http://purl.org/dc/terms/";
61 // ML: to be localized:
62 public static final String V2V_NAMESPACE_URI = "http://v2v.indymedia.de/rss/";
64 private static final XMLReader.XMLName RDF_ABOUT_PARAMETER = new XMLReader.XMLName(RDF_NAMESPACE_URI, "about");
65 private static final XMLReader.XMLName RDF_SEQUENCE_TAG = new XMLReader.XMLName(RDF_NAMESPACE_URI, "Seq");
66 private static final XMLReader.XMLName RDF_BAG_PARAMETER = new XMLReader.XMLName(RDF_NAMESPACE_URI, "Bag");
68 private static final XMLReader.XMLName RSS_CHANNEL_TAG = new XMLReader.XMLName(RSS_1_0_NAMESPACE_URI, "channel");
69 private static final XMLReader.XMLName RSS_ITEM_TAG = new XMLReader.XMLName(RSS_1_0_NAMESPACE_URI, "item");
70 private static final XMLReader.XMLName RSS_ITEMS_TAG = new XMLReader.XMLName(RSS_1_0_NAMESPACE_URI, "items");
73 private Map namespaceURItoModule;
74 private Map moduleToPrefix;
77 modules = new Vector();
78 namespaceURItoModule = new HashMap();
79 moduleToPrefix = new HashMap();
81 registerModule(new RSSBasicModule(RDF_NAMESPACE_URI, "RDF module"), "rdf");
82 registerModule(new RSSBasicModule(RSS_1_0_NAMESPACE_URI, "RSS 1.0 module"), "rss");
84 RSSBasicModule dcModule = new RSSBasicModule(DUBLINCORE_NAMESPACE_URI, "RSS Dublin Core 1.1");
85 dcModule.addProperty("date", dcModule.W3CDTF_PROPERTY_TYPE);
86 registerModule(dcModule, "dc");
88 RSSBasicModule dcTermsModule = new RSSBasicModule(DUBLINCORE_TERMS_NAMESPACE_URI, "RSS Qualified Dublin core");
89 dcTermsModule.addProperty("created", dcModule.W3CDTF_PROPERTY_TYPE);
90 dcTermsModule.addProperty("issued", dcModule.W3CDTF_PROPERTY_TYPE);
91 dcTermsModule.addProperty("modified", dcModule.W3CDTF_PROPERTY_TYPE);
92 dcTermsModule.addProperty("dateAccepted", dcModule.W3CDTF_PROPERTY_TYPE);
93 dcTermsModule.addProperty("dateCopyrighted", dcModule.W3CDTF_PROPERTY_TYPE);
94 dcTermsModule.addProperty("dateSubmitted", dcModule.W3CDTF_PROPERTY_TYPE);
95 registerModule(dcTermsModule, "dcterms");
97 RSSBasicModule v2vTermsModule = new RSSBasicModule(V2V_NAMESPACE_URI, "indymedia v2v RSS module");
98 dcTermsModule.addMultiValuedProperty("topic", dcModule.PCDATA_PROPERTY_TYPE);
99 dcTermsModule.addMultiValuedProperty("genre", dcModule.PCDATA_PROPERTY_TYPE);
100 dcTermsModule.addMultiValuedProperty("link", dcModule.PCDATA_PROPERTY_TYPE);
101 registerModule(dcTermsModule, "v2v");
103 registerModule(new RSSBasicModule(EVENT_NAMESPACE_URI, "Event RSS module"), "ev");
104 registerModule(new RSSBasicModule(TAXONOMY_NAMESPACE_URI, "Taxonomy RSS module"), "taxo");
107 public void registerModule(RSSModule aModule, String aPrefix) {
108 modules.add(aModule);
109 namespaceURItoModule.put(aModule.getNamespaceURI(), aModule);
110 moduleToPrefix.put(aModule, aPrefix);
113 public RSSData parseInputStream(InputStream aStream) throws RSSExc, RSSFailure {
115 XMLReader xmlReader = new XMLReader(true);
116 RSSData result = new RSSData();
117 xmlReader.parseInputStream(aStream, new RootSectionHandler(result));
121 catch (Throwable t) {
122 throw new RSSFailure(t);
126 public RSSData parseUrl(String anUrl) throws RSSExc, RSSFailure {
128 InputStream inputStream = (InputStream) new URL(anUrl).getContent(new Class[] {InputStream.class});
130 if (inputStream==null)
131 throw new RSSExc("RSSChannel.parseUrl: Can't get url content");
133 return parseInputStream(inputStream);
135 catch (Throwable t) {
136 throw new RSSFailure(t);
140 private class RootSectionHandler extends XMLReader.AbstractSectionHandler {
141 private RSSData data;
143 public RootSectionHandler(RSSData aData) {
147 public XMLReader.SectionHandler startElement(XMLReader.XMLName aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
148 if (aTag.getLocalName().equals("RDF")) {
149 return new RDFSectionHandler(data);
152 throw new XMLReader.XMLReaderFailure(new RSSExc("'RDF' tag expected"));
155 public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
158 public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
159 if (aCharacters.trim().length()>0)
160 throw new XMLReader.XMLReaderExc("No character data allowed here");
163 public void finishSection() throws XMLReader.XMLReaderExc {
167 private class RDFSectionHandler extends XMLReader.AbstractSectionHandler {
168 private RSSData data;
171 public RDFSectionHandler(RSSData aData) {
175 public XMLReader.SectionHandler startElement(XMLReader.XMLName aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
176 String identifier = (String) anAttributes.get(RDF_ABOUT_PARAMETER);
177 String rdfClass = makeQualifiedName(aTag);
179 return new RDFResourceSectionHandler(rdfClass, identifier);
182 public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
183 if (aHandler instanceof RDFResourceSectionHandler) {
184 data.addResource(((RDFResourceSectionHandler) aHandler).getResource());
188 public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
189 if (aCharacters.trim().length()>0)
190 throw new XMLReader.XMLReaderExc("No character data allowed here");
193 public void finishSection() throws XMLReader.XMLReaderExc {
197 private XMLReader.SectionHandler makePropertyValueSectionHandler(XMLReader.XMLName aTag, Map anAttributes) {
198 RSSModule module = (RSSModule) namespaceURItoModule.get(aTag.getNamespaceURI());
201 RSSModule.RSSModuleProperty property = module.getPropertyForName(aTag.getLocalName());
203 if (property!=null) {
204 switch (property.getType()) {
206 RSSModule.PCDATA_PROPERTY_TYPE:
207 return new PCDATASectionHandler();
209 RSSModule.RDFCOLLECTION_PROPERTY_TYPE:
210 return new RDFCollectionSectionHandler();
212 // RSSModule.RDF_PROPERTY_TYPE:
213 // return new RDFValueSectionHandler();
215 RSSModule.W3CDTF_PROPERTY_TYPE:
216 return new DateSectionHandler();
222 return new FlexiblePropertyValueSectionHandler();
225 private void usePropertyValueSectionHandler(RDFResource aResource, PropertyValueSectionHandler aHandler, XMLReader.XMLName aTag) {
226 RSSModule module = (RSSModule) namespaceURItoModule.get(aTag.getNamespaceURI());
229 RSSModule.RSSModuleProperty property = module.getPropertyForName(aTag.getLocalName());
231 if (property!=null && property.getIsMultiValued()) {
232 List value = (List) aResource.get(makeQualifiedName(aTag));
235 value = new Vector();
236 aResource.set(makeQualifiedName(aTag), value);
239 value.add(aHandler.getValue());
245 aResource.set(makeQualifiedName(aTag), aHandler.getValue());
248 private String makeQualifiedName(XMLReader.XMLName aName) {
249 String result=aName.getLocalName();
250 RSSModule module = (RSSModule) namespaceURItoModule.get(aName.getNamespaceURI());
252 String prefix = (String) moduleToPrefix.get(module);
254 if (prefix!=null && prefix.length()>0)
255 result = prefix+":"+result;
261 private class RDFResourceSectionHandler extends XMLReader.AbstractSectionHandler {
262 private String image;
263 private XMLReader.XMLName currentTag;
264 private RDFResource resource;
266 public RDFResourceSectionHandler(String anRDFClass, String anIdentifier) {
267 resource = new RDFResource(anRDFClass, anIdentifier);
270 public XMLReader.SectionHandler startElement(XMLReader.XMLName aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
273 return makePropertyValueSectionHandler(aTag, anAttributes);
276 public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
277 if (aHandler instanceof PropertyValueSectionHandler) {
278 usePropertyValueSectionHandler(resource, (PropertyValueSectionHandler) aHandler, currentTag);
279 // resource.set(makeQualifiedName(currentTag), ( (PropertyValueSectionHandler) aHandler).getValue());
283 public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
284 if (aCharacters.trim().length()>0)
285 throw new XMLReader.XMLReaderExc("No character data allowed here");
288 public void finishSection() throws XMLReader.XMLReaderExc {
291 public RDFResource getResource() {
296 private abstract class PropertyValueSectionHandler extends XMLReader.AbstractSectionHandler {
297 public abstract Object getValue();
300 private class FlexiblePropertyValueSectionHandler extends PropertyValueSectionHandler {
301 private StringBuffer stringData;
302 private Object structuredData;
304 public FlexiblePropertyValueSectionHandler() {
305 stringData = new StringBuffer();
309 public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
310 if (aTag.equals(RDF_SEQUENCE_TAG))
311 return new RDFSequenceSectionHandler();
313 return new DiscardingSectionHandler();
316 public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
317 if (aHandler instanceof RDFSequenceSectionHandler) {
318 structuredData= ((RDFSequenceSectionHandler) aHandler).getItems();
322 public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
323 stringData.append(aCharacters);
326 public void finishSection() throws XMLReader.XMLReaderExc {
329 public String getData() {
330 return stringData.toString();
333 public Object getValue() {
334 if (structuredData==null)
335 return stringData.toString();
337 return structuredData;
341 private class RDFCollectionSectionHandler extends PropertyValueSectionHandler {
344 public RDFCollectionSectionHandler() {
345 items = new Vector();
348 public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
349 if (aTag.equals(RDF_SEQUENCE_TAG))
350 return new RDFSequenceSectionHandler();
352 return new DiscardingSectionHandler();
355 public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
356 if (aHandler instanceof RDFSequenceSectionHandler) {
357 items.addAll(((RDFSequenceSectionHandler) aHandler).getItems());
361 public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
362 if (aCharacters.trim().length()>0)
363 throw new XMLReader.XMLReaderExc("No character data allowed here");
366 public void finishSection() throws XMLReader.XMLReaderExc {
369 public List getItems() {
373 public Object getValue() {
378 private class PCDATASectionHandler extends PropertyValueSectionHandler {
379 private StringBuffer data;
381 public PCDATASectionHandler() {
382 data = new StringBuffer();
385 public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
386 throw new XMLReader.XMLReaderFailure(new RSSExc("No subtags allowed here"));
389 public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
392 public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
393 data.append(aCharacters);
396 public void finishSection() throws XMLReader.XMLReaderExc {
399 public String getData() {
400 return data.toString();
403 public Object getValue() {
404 return data.toString();
408 private class DateSectionHandler extends PropertyValueSectionHandler {
409 private StringBuffer data;
411 public DateSectionHandler() {
412 data = new StringBuffer();
415 public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
416 throw new XMLReader.XMLReaderFailure(new RSSExc("No subtags allowed here"));
419 public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
422 public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
423 data.append(aCharacters);
426 public void finishSection() throws XMLReader.XMLReaderExc {
429 private final static String SPACE = "[\t\n\r ]*";
430 private final static String NUMBER = "[0-9]*";
431 private final static String SIGN = "[-+]";
433 public Object getValue() {
435 String expression = data.toString().trim();
437 return DateTimeFunctions.parseW3CDTFString(expression);
439 catch (Throwable t) {
447 private class RDFSequenceSectionHandler extends XMLReader.AbstractSectionHandler {
450 public RDFSequenceSectionHandler() {
451 items = new Vector();
454 public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
455 if (aTag.equals("rdf:li")) {
456 String item = (String) anAttributes.get("rdf:resource");
462 return new DiscardingSectionHandler();
465 public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
468 public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
471 public void finishSection() throws XMLReader.XMLReaderExc {
474 public List getItems() {
479 private class RDFLiteralSectionHandler extends PropertyValueSectionHandler {
480 private StringBuffer data;
483 public RDFLiteralSectionHandler() {
484 data = new StringBuffer();
487 protected StringBuffer getData() {
491 public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
493 data.append("<"+tag+">");
495 return new RDFLiteralSectionHandler();
498 public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
499 data.append(((RDFLiteralSectionHandler) aHandler).getData());
500 data.append("</"+tag+">");
503 public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
504 data.append(aCharacters);
507 public void finishSection() throws XMLReader.XMLReaderExc {
510 public Object getValue() {
511 return data.toString();
515 private class DiscardingSectionHandler extends XMLReader.AbstractSectionHandler {
516 public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
520 public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
523 public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
526 public void finishSection() throws XMLReader.XMLReaderExc {