1.1 restoration
[mir.git] / source / mir / rss / RSSReader.java
index 45fbe4f..6d89d49 100755 (executable)
-/*\r
- * Copyright (C) 2001, 2002  The Mir-coders group\r
- *\r
- * This file is part of Mir.\r
- *\r
- * Mir is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * Mir is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with Mir; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
- *\r
- * In addition, as a special exception, The Mir-coders gives permission to link\r
- * the code of this program with the com.oreilly.servlet library, any library\r
- * licensed under the Apache Software License, The Sun (tm) Java Advanced\r
- * Imaging library (JAI), The Sun JIMI library (or with modified versions of\r
- * the above that use the same license as the above), and distribute linked\r
- * combinations including the two.  You must obey the GNU General Public\r
- * License in all respects for all of the code used other than the above\r
- * mentioned libraries.  If you modify this file, you may extend this exception\r
- * to your version of the file, but you are not obligated to do so.  If you do\r
- * not wish to do so, delete this exception statement from your version.\r
- */\r
-\r
-package mir.rss;\r
-\r
-import java.io.InputStream;\r
-import java.net.URL;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Vector;\r
-\r
-import mir.util.XMLReader;\r
-import mir.util.XMLReaderTool;\r
-\r
-/**\r
- *\r
- * <p>Title: </p>\r
- * <p>Description: </p>\r
- * <p>Copyright: Copyright (c) 2003</p>\r
- * <p>Company: </p>\r
- * @author not attributable\r
- * @version 1.0\r
- */\r
-\r
-public class RSSReader {\r
-  public RSSReader() {\r
-  }\r
-\r
-  public RSSData parseInputStream(InputStream aStream) throws RSSExc, RSSFailure {\r
-    try {\r
-      XMLReader xmlReader = new XMLReader();\r
-      RSSData result = new RSSData();\r
-      xmlReader.parseInputStream(aStream, new RootSectionHandler(result));\r
-\r
-      return result;\r
-    }\r
-    catch (Throwable t) {\r
-      throw new RSSFailure(t);\r
-    }\r
-  }\r
-\r
-  public RSSData parseUrl(String anUrl) throws RSSExc, RSSFailure {\r
-    try {\r
-      InputStream inputStream = (InputStream) new URL(anUrl).getContent(new Class[] {InputStream.class});\r
-\r
-      if (inputStream==null)\r
-        throw new RSSExc("RSSChannel.parseUrl: Can't get url content");\r
-\r
-      return parseInputStream(inputStream);\r
-    }\r
-    catch (Throwable t) {\r
-      throw new RSSFailure(t);\r
-    }\r
-  }\r
-\r
-  private static class RootSectionHandler extends XMLReader.AbstractSectionHandler {\r
-    private RSSData data;\r
-\r
-    public RootSectionHandler(RSSData aData) {\r
-      data = aData;\r
-    }\r
-\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      if (XMLReaderTool.getLocalNameFromQualifiedName(aTag).equals("RDF")) {\r
-        return new RDFSectionHandler(data);\r
-      }\r
-      else\r
-        throw new XMLReader.XMLReaderFailure(new RSSExc("'RDF' tag expected"));\r
-    };\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {\r
-    };\r
-\r
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {\r
-      if (aCharacters.trim().length()>0)\r
-        throw new XMLReader.XMLReaderExc("No character data allowed here");\r
-    };\r
-\r
-    public void finishSection() throws XMLReader.XMLReaderExc {\r
-    };\r
-  }\r
-\r
-  private static class RDFSectionHandler extends XMLReader.AbstractSectionHandler {\r
-    private RSSData data;\r
-\r
-    public RDFSectionHandler(RSSData aData) {\r
-      data = aData;\r
-    }\r
-\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      String identifier = (String) anAttributes.get("rdf:about");\r
-\r
-      if (aTag.equals("channel")) {\r
-        if (identifier==null)\r
-          throw new XMLReader.XMLReaderFailure(new RSSExc("Missing rdf:about"));\r
-        else\r
-          return new ChannelSectionHandler(identifier);\r
-      }\r
-      else if (aTag.equals("item")) {\r
-        if (identifier==null)\r
-          throw new XMLReader.XMLReaderFailure(new RSSExc("Missing rdf:about"));\r
-        else\r
-          return new ItemSectionHandler(identifier);\r
-      }\r
-      else\r
-        return new DiscardingSectionHandler();\r
-    };\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {\r
-      if (aHandler instanceof ItemSectionHandler) {\r
-        data.addItem(((ItemSectionHandler) aHandler).getItem());\r
-      }\r
-      else if (aHandler instanceof ChannelSectionHandler) {\r
-        data.setChannel(((ChannelSectionHandler) aHandler).getChannel());\r
-      }\r
-    };\r
-\r
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {\r
-      if (aCharacters.trim().length()>0)\r
-        throw new XMLReader.XMLReaderExc("No character data allowed here");\r
-    };\r
-\r
-    public void finishSection() throws XMLReader.XMLReaderExc {\r
-    };\r
-  }\r
-\r
-  private static class ChannelSectionHandler extends XMLReader.AbstractSectionHandler {\r
-    private String image;\r
-    private String currentTag;\r
-    private RSSChannel channel;\r
-\r
-    public ChannelSectionHandler(String anIdentifier) {\r
-      channel = new RSSChannel(anIdentifier);\r
-    }\r
-\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      currentTag = aTag;\r
-      if (currentTag.equals("items")) {\r
-        return new ChannelItemsSectionHandler();\r
-      }\r
-      else if (currentTag.equals("description") ||\r
-               currentTag.equals("link") ||\r
-               currentTag.equals("title")) {\r
-        return new PCDATASectionHandler();\r
-      }\r
-\r
-      return new DiscardingSectionHandler();\r
-    };\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {\r
-      if (currentTag.equals("items")) {\r
-        channel.setItems(((ChannelItemsSectionHandler) aHandler).getItems());\r
-      }\r
-      if (currentTag.equals("description")) {\r
-        channel.setDescription(((PCDATASectionHandler) aHandler).getData());\r
-      }\r
-      else if (currentTag.equals("title")) {\r
-        channel.setTitle(((PCDATASectionHandler) aHandler).getData());\r
-      }\r
-      else if (currentTag.equals("link")) {\r
-        channel.setLink(((PCDATASectionHandler) aHandler).getData());\r
-      }\r
-    };\r
-\r
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {\r
-      if (aCharacters.trim().length()>0)\r
-        throw new XMLReader.XMLReaderExc("No character data allowed here");\r
-    };\r
-\r
-    public void finishSection() throws XMLReader.XMLReaderExc {\r
-    };\r
-\r
-    public RSSChannel getChannel () {\r
-      return channel;\r
-    }\r
-  }\r
-\r
-  private static class ChannelItemsSectionHandler extends XMLReader.AbstractSectionHandler {\r
-    private List items;\r
-\r
-    public ChannelItemsSectionHandler() {\r
-      items = new Vector();\r
-    }\r
-\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      if (aTag.equals("rdf:Seq"))\r
-        return new RDFSequenceSectionHandler();\r
-      else\r
-        return new DiscardingSectionHandler();\r
-    };\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {\r
-      if (aHandler instanceof RDFSequenceSectionHandler) {\r
-        items.addAll(((RDFSequenceSectionHandler) aHandler).getItems());\r
-      }\r
-    };\r
-\r
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {\r
-      if (aCharacters.trim().length()>0)\r
-        throw new XMLReader.XMLReaderExc("No character data allowed here");\r
-    };\r
-\r
-    public void finishSection() throws XMLReader.XMLReaderExc {\r
-    };\r
-\r
-    public List getItems() {\r
-      return items;\r
-    }\r
-  }\r
-\r
-  private static class ItemSectionHandler extends XMLReader.AbstractSectionHandler {\r
-    private String currentTag;\r
-    private RSSItem item;\r
-\r
-    public ItemSectionHandler(String anIdentifier) {\r
-      item = new RSSItem(anIdentifier);\r
-    }\r
-\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      currentTag = aTag;\r
-\r
-      if (currentTag.equals("description") ||\r
-               currentTag.equals("link") ||\r
-               currentTag.equals("title")) {\r
-        return new PCDATASectionHandler();\r
-      }\r
-\r
-      return new DiscardingSectionHandler();\r
-    };\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {\r
-      if (currentTag.equals("description")) {\r
-        item.setDescription(((PCDATASectionHandler) aHandler).getData());\r
-      }\r
-      else if (currentTag.equals("title")) {\r
-        item.setTitle(((PCDATASectionHandler) aHandler).getData());\r
-      }\r
-      else if (currentTag.equals("link")) {\r
-        item.setLink(((PCDATASectionHandler) aHandler).getData());\r
-      }\r
-    };\r
-\r
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {\r
-      if (aCharacters.trim().length()>0)\r
-        throw new XMLReader.XMLReaderExc("No character data allowed here");\r
-    };\r
-\r
-    public void finishSection() throws XMLReader.XMLReaderExc {\r
-    };\r
-\r
-    public RSSItem getItem() {\r
-      return item;\r
-    };\r
-  }\r
-\r
-  private static class PCDATASectionHandler extends XMLReader.AbstractSectionHandler {\r
-    private StringBuffer data;\r
-\r
-    public PCDATASectionHandler() {\r
-      data = new StringBuffer();\r
-    }\r
-\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      throw new XMLReader.XMLReaderFailure(new RSSExc("No subtags allowed here"));\r
-    };\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {\r
-    };\r
-\r
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {\r
-      data.append(aCharacters);\r
-    };\r
-\r
-    public void finishSection() throws XMLReader.XMLReaderExc {\r
-    };\r
-\r
-    public String getData() {\r
-      return data.toString();\r
-    }\r
-  }\r
-\r
-\r
-  private static class RDFSequenceSectionHandler extends XMLReader.AbstractSectionHandler {\r
-    private List items;\r
-\r
-    public RDFSequenceSectionHandler() {\r
-      items = new Vector();\r
-    }\r
-\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      if (aTag.equals("rdf:li")) {\r
-        String item = (String) anAttributes.get("rdf:resource");\r
-\r
-        if (item!=null)\r
-          items.add(item);\r
-      }\r
-\r
-      return new DiscardingSectionHandler();\r
-    };\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {\r
-    };\r
-\r
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {\r
-    };\r
-\r
-    public void finishSection() throws XMLReader.XMLReaderExc {\r
-    };\r
-\r
-    public List getItems() {\r
-      return items;\r
-    }\r
-  }\r
-\r
-  private static class RDFLiteralSectionHandler extends XMLReader.AbstractSectionHandler {\r
-    private StringBuffer data;\r
-    private String tag;\r
-\r
-    public RDFLiteralSectionHandler() {\r
-      data = new StringBuffer();\r
-    }\r
-\r
-    protected StringBuffer getData() {\r
-      return data;\r
-    }\r
-\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      tag=aTag;\r
-      data.append("<"+tag+">");\r
-\r
-      return new RDFLiteralSectionHandler();\r
-    };\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {\r
-      data.append(((RDFLiteralSectionHandler) aHandler).getData());\r
-      data.append("</"+tag+">");\r
-    };\r
-\r
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {\r
-      data.append(aCharacters);\r
-    };\r
-\r
-    public void finishSection() throws XMLReader.XMLReaderExc {\r
-    };\r
-  }\r
-\r
-  private static class DiscardingSectionHandler extends XMLReader.AbstractSectionHandler {\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      return this;\r
-    };\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {\r
-    };\r
-\r
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {\r
-    };\r
-\r
-    public void finishSection() throws XMLReader.XMLReaderExc {\r
-    };\r
-  }\r
-}\r
+/*
+ * Copyright (C) 2001, 2002 The Mir-coders group
+ *
+ * This file is part of Mir.
+ *
+ * Mir is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Mir is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mir; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * In addition, as a special exception, The Mir-coders gives permission to link
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * and distribute linked combinations including the two.  You must obey the
+ * GNU General Public License in all respects for all of the code used other than
+ * the above mentioned libraries.  If you modify this file, you may extend this
+ * exception to your version of the file, but you are not obligated to do so.
+ * If you do not wish to do so, delete this exception statement from your version.
+ */
+package mir.rss;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import mir.util.DateTimeFunctions;
+import mir.util.HTTPClientHelper;
+import mir.util.xml.XMLParserEngine;
+import mir.util.xml.XMLParserExc;
+import mir.util.xml.XMLParserFailure;
+
+/**
+ *
+ * <p>Title: </p>
+ * <p>Description: </p>
+ * <p>Copyright: Copyright (c) 2003</p>
+ * <p>Company: </p>
+ * @author not attributable
+ * @version 1.0
+ */
+
+public class RSSReader {
+  public static final String RDF_NAMESPACE_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+  public static final String RSS_1_0_NAMESPACE_URI = "http://purl.org/rss/1.0/";
+  public static final String RSS_0_9_NAMESPACE_URI = "http://my.netscape.com/rdf/simple/0.9/";
+  public static final String DUBLINCORE_NAMESPACE_URI = "http://purl.org/dc/elements/1.1/";
+  public static final String EVENT_NAMESPACE_URI = "http://purl.org/rss/1.0/modules/event/";
+  public static final String TAXONOMY_NAMESPACE_URI = "http://web.resource.org/rss/1.0/modules/taxonomy/";
+  public static final String DUBLINCORE_TERMS_NAMESPACE_URI = "http://purl.org/dc/terms/";
+  public static final String CONTENT_NAMESPACE_URI = "http://purl.org/rss/1.0/modules/content/";
+
+  // ML: to be localized:
+  public static final String V2V_NAMESPACE_URI = "http://v2v.cc/rss/";
+
+  private static final mir.util.xml.XMLName RDF_ABOUT_PARAMETER = new mir.util.xml.XMLName(RDF_NAMESPACE_URI, "about");
+  private static final mir.util.xml.XMLName RDF_SEQUENCE_TAG = new mir.util.xml.XMLName(RDF_NAMESPACE_URI, "Seq");
+  private static final mir.util.xml.XMLName RDF_BAG_PARAMETER = new mir.util.xml.XMLName(RDF_NAMESPACE_URI, "Bag");
+
+  private static final mir.util.xml.XMLName RSS_CHANNEL_TAG = new mir.util.xml.XMLName(RSS_1_0_NAMESPACE_URI, "channel");
+  private static final mir.util.xml.XMLName RSS_ITEM_TAG = new mir.util.xml.XMLName(RSS_1_0_NAMESPACE_URI, "item");
+  private static final mir.util.xml.XMLName RSS_ITEMS_TAG = new mir.util.xml.XMLName(RSS_1_0_NAMESPACE_URI, "items");
+
+  private List modules;
+  private Map namespaceURItoModule;
+  private Map moduleToPrefix;
+
+  public RSSReader() {
+    modules = new ArrayList();
+    namespaceURItoModule = new HashMap();
+    moduleToPrefix = new HashMap();
+
+    registerModule(new RSSBasicModule(RDF_NAMESPACE_URI, "RDF module"), "rdf");
+    registerModule(new RSSBasicModule(RSS_1_0_NAMESPACE_URI, "RSS 1.0 module"), "rss");
+    registerModule(new RSSBasicModule(RSS_0_9_NAMESPACE_URI, "RSS 0.9 module"), "rss");
+
+    RSSBasicModule dcModule = new RSSBasicModule(DUBLINCORE_NAMESPACE_URI, "RSS Dublin Core 1.1");
+    dcModule.addProperty("date", RSSModule.W3CDTF_PROPERTY_TYPE);
+    registerModule(dcModule, "dc");
+
+    RSSBasicModule dcTermsModule = new RSSBasicModule(DUBLINCORE_TERMS_NAMESPACE_URI, "RSS Qualified Dublin core");
+    dcTermsModule.addProperty("created", RSSModule.W3CDTF_PROPERTY_TYPE);
+    dcTermsModule.addProperty("issued", RSSModule.W3CDTF_PROPERTY_TYPE);
+    dcTermsModule.addProperty("modified", RSSModule.W3CDTF_PROPERTY_TYPE);
+    dcTermsModule.addProperty("dateAccepted", RSSModule.W3CDTF_PROPERTY_TYPE);
+    dcTermsModule.addProperty("dateCopyrighted", RSSModule.W3CDTF_PROPERTY_TYPE);
+    dcTermsModule.addProperty("dateSubmitted", RSSModule.W3CDTF_PROPERTY_TYPE);
+    registerModule(dcTermsModule, "dcterms");
+
+    RSSBasicModule v2vTermsModule = new RSSBasicModule(V2V_NAMESPACE_URI, "indymedia v2v RSS module");
+    v2vTermsModule.addMultiValuedProperty("topic", RSSModule.PCDATA_PROPERTY_TYPE);
+    v2vTermsModule.addMultiValuedProperty("genre", RSSModule.PCDATA_PROPERTY_TYPE);
+    v2vTermsModule.addMultiValuedProperty("link", RSSModule.PCDATA_PROPERTY_TYPE);
+    registerModule(v2vTermsModule, "v2v");
+
+    registerModule(new RSSBasicModule(EVENT_NAMESPACE_URI, "Event RSS module"), "ev");
+    registerModule(new RSSBasicModule(TAXONOMY_NAMESPACE_URI, "Taxonomy RSS module"), "taxo");
+    registerModule(new RSSBasicModule(CONTENT_NAMESPACE_URI  , "Content RSS module"), "content");
+  }
+
+  public void registerModule(RSSModule aModule, String aPrefix) {
+    modules.add(aModule);
+    namespaceURItoModule.put(aModule.getNamespaceURI(), aModule);
+    moduleToPrefix.put(aModule, aPrefix);
+  }
+
+  public RSSData parseInputStream(InputStream aStream) throws RSSExc, RSSFailure {
+    try {
+      RSSData result = new RSSData();
+      XMLParserEngine.getInstance().parse("xml", aStream, new RootSectionHandler(result));
+
+      return result;
+    }
+    catch (Throwable t) {
+      throw new RSSFailure(t);
+    }
+  }
+
+  public RSSData parseInputStream(InputStream aStream, String anEncoding) throws RSSExc, RSSFailure {
+    try {
+      RSSData result = new RSSData();
+      XMLParserEngine.getInstance().parse("xml", aStream, anEncoding, new RootSectionHandler(result));
+
+      return result;
+    }
+    catch (Throwable t) {
+      throw new RSSFailure(t);
+    }
+  }
+
+  public RSSData parseUrl(String anUrl) throws RSSExc, RSSFailure {
+    try {
+      HTTPClientHelper httpClientHelper = new HTTPClientHelper();      
+      InputStream inputStream = httpClientHelper.getUrl(anUrl);
+      if (inputStream==null)
+        throw new RSSExc("RSSChannel.parseUrl: Can't get url content");
+
+      RSSData theRSSData =  parseInputStream(inputStream);
+      httpClientHelper.releaseHTTPConnection();
+      return theRSSData;
+    }
+    catch (Throwable t) {
+      throw new RSSFailure(t);
+    }
+  }
+
+  public RSSData parseUrl(String anUrl, String anEncoding) throws RSSExc, RSSFailure {
+    try {
+      HTTPClientHelper httpClientHelper = new HTTPClientHelper();      
+      InputStream inputStream = httpClientHelper.getUrl(anUrl);
+      if (inputStream==null)
+        throw new RSSExc("RSSChannel.parseUrl: Can't get url content");
+
+      RSSData theRSSData =  parseInputStream(inputStream, anEncoding);
+      httpClientHelper.releaseHTTPConnection();
+      return theRSSData;
+    }
+    catch (Throwable t) {
+      throw new RSSFailure(t);
+    }
+  }
+
+  private class RootSectionHandler extends mir.util.xml.AbstractSectionHandler {
+    private RSSData data;
+
+    public RootSectionHandler(RSSData aData) {
+      data = aData;
+    }
+
+    public mir.util.xml.SectionHandler startElement(mir.util.xml.XMLName aTag, Map anAttributes) throws XMLParserExc {
+      if (aTag.getLocalName().equals("RDF")) {
+        return new RDFSectionHandler(data);
+      }
+      else
+        throw new XMLParserFailure(new RSSExc("'RDF' tag expected"));
+    };
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
+    };
+
+    public void characters(String aCharacters) throws XMLParserExc {
+      if (aCharacters.trim().length()>0)
+        throw new XMLParserExc("No character data allowed here");
+    };
+
+    public void finishSection() throws XMLParserExc {
+    };
+  }
+
+  private class RDFSectionHandler extends mir.util.xml.AbstractSectionHandler {
+    private RSSData data;
+
+
+    public RDFSectionHandler(RSSData aData) {
+      data = aData;
+    }
+
+    public mir.util.xml.SectionHandler startElement(mir.util.xml.XMLName aTag, Map anAttributes) throws XMLParserExc {
+      String identifier = (String) anAttributes.get(RDF_ABOUT_PARAMETER);
+      String rdfClass = makeQualifiedName(aTag);
+
+      return new RDFResourceSectionHandler(rdfClass, identifier);
+    };
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
+      if (aHandler instanceof RDFResourceSectionHandler) {
+        data.addResource(((RDFResourceSectionHandler) aHandler).getResource());
+      }
+    };
+
+    public void characters(String aCharacters) throws XMLParserExc {
+      if (aCharacters.trim().length()>0)
+        throw new XMLParserExc("No character data allowed here");
+    };
+
+    public void finishSection() throws XMLParserExc {
+    };
+  }
+
+  private mir.util.xml.SectionHandler makePropertyValueSectionHandler(mir.util.xml.XMLName aTag, Map anAttributes) {
+    RSSModule module = (RSSModule) namespaceURItoModule.get(aTag.getNamespaceURI());
+
+    if (module!=null) {
+      RSSModule.RSSModuleProperty property = module.getPropertyForName(aTag.getLocalName());
+
+      if (property!=null) {
+        switch (property.getType()) {
+          case
+            RSSModule.PCDATA_PROPERTY_TYPE:
+              return new PCDATASectionHandler();
+          case
+            RSSModule.RDFCOLLECTION_PROPERTY_TYPE:
+              return new RDFCollectionSectionHandler();
+//          case
+//            RSSModule.RDF_PROPERTY_TYPE:
+//              return new RDFValueSectionHandler();
+          case
+            RSSModule.W3CDTF_PROPERTY_TYPE:
+              return new DateSectionHandler();
+        }
+      }
+    }
+
+    return new FlexiblePropertyValueSectionHandler();
+  }
+
+  private void usePropertyValueSectionHandler(RDFResource aResource, PropertyValueSectionHandler aHandler, mir.util.xml.XMLName aTag) {
+    RSSModule module = (RSSModule) namespaceURItoModule.get(aTag.getNamespaceURI());
+
+    if (module!=null) {
+      RSSModule.RSSModuleProperty property = module.getPropertyForName(aTag.getLocalName());
+
+      if (property!=null && property.getIsMultiValued()) {
+        List value = (List) aResource.get(makeQualifiedName(aTag));
+
+        if (value==null) {
+          value = new ArrayList();
+          aResource.set(makeQualifiedName(aTag), value);
+        }
+
+        value.add(aHandler.getValue());
+
+        return;
+      }
+    }
+
+    aResource.set(makeQualifiedName(aTag), aHandler.getValue());
+  }
+
+  private String makeQualifiedName(mir.util.xml.XMLName aName) {
+    String result=aName.getLocalName();
+    RSSModule module = (RSSModule) namespaceURItoModule.get(aName.getNamespaceURI());
+    if (module!=null) {
+      String prefix = (String) moduleToPrefix.get(module);
+
+      if (prefix!=null && prefix.length()>0)
+        result = prefix+":"+result;
+    }
+
+    return result;
+  }
+
+  private class RDFResourceSectionHandler extends mir.util.xml.AbstractSectionHandler {
+    private String image;
+    private mir.util.xml.XMLName currentTag;
+    private RDFResource resource;
+
+    public RDFResourceSectionHandler(String anRDFClass, String anIdentifier) {
+      resource = new RDFResource(anRDFClass, anIdentifier);
+    }
+
+    public mir.util.xml.SectionHandler startElement(mir.util.xml.XMLName aTag, Map anAttributes) throws XMLParserExc {
+      currentTag = aTag;
+
+      return makePropertyValueSectionHandler(aTag, anAttributes);
+    };
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
+      if (aHandler instanceof PropertyValueSectionHandler) {
+        usePropertyValueSectionHandler(resource, (PropertyValueSectionHandler) aHandler, currentTag);
+//        resource.set(makeQualifiedName(currentTag), ( (PropertyValueSectionHandler) aHandler).getFieldValue());
+      }
+    };
+
+    public void characters(String aCharacters) throws XMLParserExc {
+      if (aCharacters.trim().length()>0)
+        throw new XMLParserExc("No character data allowed here");
+    };
+
+    public void finishSection() throws XMLParserExc {
+    };
+
+    public RDFResource getResource() {
+      if ((resource.getIdentifier()==null || resource.getIdentifier().length()==0) && resource.get("rss:link")!=null) {
+        resource.setIdentifier(resource.get("rss:link").toString());
+      }
+
+      return resource;
+    }
+  }
+
+  private abstract class PropertyValueSectionHandler extends mir.util.xml.AbstractSectionHandler {
+    public abstract Object getValue();
+  }
+
+  private class FlexiblePropertyValueSectionHandler extends PropertyValueSectionHandler {
+    private StringBuffer stringData;
+    private Object structuredData;
+
+    public FlexiblePropertyValueSectionHandler() {
+      stringData = new StringBuffer();
+      structuredData=null;
+    }
+
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      if (aTag.equals(RDF_SEQUENCE_TAG))
+        return new RDFSequenceSectionHandler();
+      else
+        return new DiscardingSectionHandler();
+    };
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
+      if (aHandler instanceof RDFSequenceSectionHandler) {
+        structuredData= ((RDFSequenceSectionHandler) aHandler).getItems();
+      }
+    };
+
+    public void characters(String aCharacters) throws XMLParserExc {
+      stringData.append(aCharacters);
+    };
+
+    public void finishSection() throws XMLParserExc {
+    };
+
+    public String getData() {
+      return stringData.toString();
+    }
+
+    public Object getValue() {
+      if (structuredData==null)
+        return stringData.toString();
+      else
+        return structuredData;
+    }
+  }
+
+  private class RDFCollectionSectionHandler extends PropertyValueSectionHandler {
+    private List items;
+
+    public RDFCollectionSectionHandler() {
+      items = new ArrayList();
+    }
+
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      if (aTag.equals(RDF_SEQUENCE_TAG))
+        return new RDFSequenceSectionHandler();
+      else
+        return new DiscardingSectionHandler();
+    };
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
+      if (aHandler instanceof RDFSequenceSectionHandler) {
+        items.addAll(((RDFSequenceSectionHandler) aHandler).getItems());
+      }
+    };
+
+    public void characters(String aCharacters) throws XMLParserExc {
+      if (aCharacters.trim().length()>0)
+        throw new XMLParserExc("No character data allowed here");
+    };
+
+    public void finishSection() throws XMLParserExc {
+    };
+
+    public List getItems() {
+      return items;
+    }
+
+    public Object getValue() {
+      return items;
+    }
+  }
+
+  private class PCDATASectionHandler extends PropertyValueSectionHandler {
+    private StringBuffer data;
+
+    public PCDATASectionHandler() {
+      data = new StringBuffer();
+    }
+
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      throw new XMLParserFailure(new RSSExc("No subtags allowed here"));
+    };
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
+    };
+
+    public void characters(String aCharacters) throws XMLParserExc {
+      data.append(aCharacters);
+    };
+
+    public void finishSection() throws XMLParserExc {
+    };
+
+    public String getData() {
+      return data.toString();
+    }
+
+    public Object getValue() {
+      return data.toString();
+    }
+  }
+
+  private class DateSectionHandler extends PropertyValueSectionHandler {
+    private StringBuffer data;
+
+    public DateSectionHandler() {
+      data = new StringBuffer();
+    }
+
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      throw new XMLParserFailure(new RSSExc("No subtags allowed here"));
+    };
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
+    };
+
+    public void characters(String aCharacters) throws XMLParserExc {
+      data.append(aCharacters);
+    };
+
+    public void finishSection() throws XMLParserExc {
+    };
+
+    public Object getValue() {
+      try {
+        String expression = data.toString().trim();
+
+        return DateTimeFunctions.parseW3CDTFString(expression);
+      }
+      catch (Throwable t) {
+
+        return null;
+      }
+    }
+  }
+
+
+  private class RDFSequenceSectionHandler extends mir.util.xml.AbstractSectionHandler {
+    private List items;
+
+    public RDFSequenceSectionHandler() {
+      items = new ArrayList();
+    }
+
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      if (aTag.equals("rdf:li")) {
+        String item = (String) anAttributes.get("rdf:resource");
+
+        if (item!=null)
+          items.add(item);
+      }
+
+      return new DiscardingSectionHandler();
+    };
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
+    };
+
+    public void characters(String aCharacters) throws XMLParserExc {
+    };
+
+    public void finishSection() throws XMLParserExc {
+    };
+
+    public List getItems() {
+      return items;
+    }
+  }
+
+  private class RDFLiteralSectionHandler extends PropertyValueSectionHandler {
+    private StringBuffer data;
+    private String tag;
+
+    public RDFLiteralSectionHandler() {
+      data = new StringBuffer();
+    }
+
+    protected StringBuffer getData() {
+      return data;
+    }
+
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      tag=aTag;
+      data.append("<"+tag+">");
+
+      return new RDFLiteralSectionHandler();
+    };
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
+      data.append(((RDFLiteralSectionHandler) aHandler).getData());
+      data.append("</"+tag+">");
+    };
+
+    public void characters(String aCharacters) throws XMLParserExc {
+      data.append(aCharacters);
+    };
+
+    public void finishSection() throws XMLParserExc {
+    };
+
+    public Object getValue() {
+      return data.toString();
+    }
+  }
+
+  private class DiscardingSectionHandler extends mir.util.xml.AbstractSectionHandler {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      return this;
+    };
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
+    };
+
+    public void characters(String aCharacters) throws XMLParserExc {
+    };
+
+    public void finishSection() throws XMLParserExc {
+    };
+  }
+}