View Javadoc

1   /*
2    * Copyright 1999,2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.commons.feedparser;
18  
19  import java.util.Date;
20  
21  import org.apache.commons.feedparser.tools.ISO8601DateParser;
22  import org.apache.commons.feedparser.tools.RFC822DateParser;
23  import org.jdom.Element;
24  import org.jdom.Namespace;
25  
26  /**
27   * Handles parsing RSS metadata including dates
28   *
29   * @author <a href="mailto:burton@apache.org">Kevin A. Burton (burtonator)</a>
30   * @version $Id: MetaFeedParser.java 373879 2006-01-31 17:23:15Z mvdb $
31   */
32  public class MetaFeedParser extends BaseParser {
33  
34      /**
35       * 
36       */
37      public static void parse( FeedParserListener listener,
38                                FeedParserState state ) throws FeedParserException {
39  
40          //FIXME: this should be refactored into a new class called
41          //MetaFeedParser to be used by both Atom and RSS.  Also the date
42          //handling below needs to be generic.
43          
44          if ( listener instanceof MetaFeedParserListener == false )
45              return;
46  
47          MetaFeedParserListener mfp = (MetaFeedParserListener)listener;
48  
49          parseDate( state, mfp );
50          
51          //FIXME: make sure RSS .9 is working and 0.91.  I just need to confirm
52          //but I think they are working correctly
53          parseGUID( state, mfp );
54  
55          parseAuthor( state, mfp );
56  
57          parseComments( state, mfp );
58  
59          parseCommentsFeed( state, mfp );
60          
61      }
62  
63      private static void parseComments( FeedParserState state,
64                                         MetaFeedParserListener listener )
65          throws FeedParserException {
66  
67          Element element = state.current.getChild( "comments" );
68  
69          if ( element != null ) {
70  
71              String resource = element.getText();
72              listener.onComments( state, resource );
73              listener.onCommentsEnd();
74              
75          }
76          
77      }
78  
79      private static void parseCommentsFeed( FeedParserState state,
80                                             MetaFeedParserListener listener )
81          throws FeedParserException {
82  
83          Element element = state.current.getChild( "commentRSS", NS.WFW );
84  
85          if ( element != null ) {
86  
87              String resource = element.getText();
88              listener.onCommentsFeed( state, resource );
89              listener.onCommentsFeedEnd();
90              
91          }
92  
93      }
94  
95      private static void parseAuthor( FeedParserState state,
96                                       MetaFeedParserListener listener )
97          throws FeedParserException {
98  
99          Element element = null;
100 
101         String name = null;
102         String email = null;
103         String resource = null;
104 
105         try {
106             
107             //atom:author
108 
109             element = state.current.getChild( "author", NS.ATOM );
110 
111             if ( element != null ) {
112                 name = selectText( "atom:name", element );
113                 email = selectText( "atom:email", element );
114                 resource = selectText( "atom:uri", element );
115             }
116 
117             //dc:creator (RSS 1.0)
118             element = state.current.getChild( "creator", NS.DC );
119 
120             if ( element != null )
121                 name = element.getText();
122                 
123             //author (RSS 2.0)
124             element = state.current.getChild( "author" );
125 
126             if ( element != null )
127                 name = element.getText();
128 
129             if ( name != null && ! "".equals( name ) ) {
130 
131                 listener.onAuthor( state,
132                                    name,
133                                    email,
134                                    resource );
135                 
136                 listener.onAuthorEnd();
137 
138             }
139 
140         } catch ( Exception e ) {
141             throw new FeedParserException( e );
142         }
143 
144     }
145 
146     private static void parseGUID( FeedParserState state,
147                                    MetaFeedParserListener listener )
148         throws FeedParserException {
149 
150         Element id = null;
151 
152         String guid = null;
153         boolean isPermalink = false;
154         
155         id = state.current.getChild( "id", NS.ATOM );
156 
157         if ( id != null ) {
158             guid = id.getText();
159         }
160 
161         id = state.current.getChild( "guid" );
162 
163         if ( id != null ) {
164 
165             guid = id.getText();
166             isPermalink = "true".equals( id.getAttributeValue( "isPermalink" ) );
167             
168         }
169 
170         if ( guid != null ) {
171 
172             listener.onGUID( state,
173                              guid,
174                              isPermalink );
175             
176             listener.onGUIDEnd();
177 
178         }
179         
180     }
181 
182     private static void parseDate( FeedParserState state,
183                                    MetaFeedParserListener listener )
184         throws FeedParserException {
185 
186         if ( parseDate( "date", NS.DC, listener, state ) )
187             return;
188 
189         // http://www.mnot.net/drafts/draft-nottingham-atom-format-02.html#rfc.section.4.13.8
190         // 
191         // The "atom:created" element is a Date construct that indicates the
192         // time that the entry was created. atom:entry elements MAY contain
193         // an atom:created element, but MUST NOT contain more than one.
194 
195         // The content of an atom:created element MUST have a time zone
196         // whose value SHOULD be "UTC".
197         
198         if ( parseDate( "created", NS.ATOM, listener, state ) )
199             return;
200 
201         // http://www.mnot.net/drafts/draft-nottingham-atom-format-02.html#rfc.section.4.13.8
202         //            
203         // If atom:created is not present, its content MUST considered to be
204         // the same as that of atom:modified.
205 
206         if ( parseDate( "modified", NS.ATOM, listener, state ) )
207             return;
208 
209         //support RSS 2.0 and RSS 0.9x dates.
210 
211         if ( parseDate( "pubDate", null, listener, state, false ) )
212             return;
213 
214     }
215     
216     private static boolean parseDate( String name,
217                                       Namespace ns,
218                                       MetaFeedParserListener listener,
219                                       FeedParserState state ) {
220 
221         return parseDate( name, ns, listener, state, true );
222 
223     }
224     
225     private static boolean parseDate( String name,
226                                       Namespace ns,
227                                       MetaFeedParserListener listener,
228                                       FeedParserState state,
229                                       boolean ISO8601 ) {
230         try { 
231             //ok.  Support dc:date
232             String v = state.current.getChildText( name, ns );
233     
234             if ( v != null ) {
235                     
236                 Date d = null;
237                 if ( ISO8601 ) {
238                     d = ISO8601DateParser.parse( v );
239                 } else {
240                     d = RFC822DateParser.parse( v );
241                 }
242 
243                 listener.onCreated( state, d );
244                 listener.onCreatedEnd();
245 
246                 return true;
247             }
248         } catch ( Throwable t ) {
249             // ignore the exception, so we can just move on
250         }
251 
252         return false;
253 
254     }
255 
256 }