posts - 262,  comments - 221,  trackbacks - 0

          既然知道了FeedParser類只是一個中介類,真正的解析工作都在各個版本號對應的解析器完成,那么下面就從RSS 0.9.x / 2.0系協議解析器開始學習。

          ★RSS_0_91_Parser

              /**
               * Private constructor suppresses generation of a (public) default
               * constructor.
               
          */

              
          private RSS_0_91_Parser() {
              }


              
          /**
               * Holder of the RSS_0_91_Parser instance.
               
          */

              
          private static class RSS_0_91_ParserHolder {
                  
          private static RSS_0_91_Parser instance = new RSS_0_91_Parser();
              }


              
          /**
               * Get the RSS_0_91_Parser instance.
               
          */

              
          public static RSS_0_91_Parser getInstance() {
                  
          return RSS_0_91_ParserHolder.instance;
              }

          可以看到解析器都是單例模式,這里比較特別的是使用靜態內部類來保存這個單例。 個人認為這里有點多余,靜態內部類的作用主要有:
           A.在創建靜態內部類的實例前,不需要額外創建外部類的實例
           B.靜態內部類可以也只能訪問外部類的靜態成員和靜態方法

          內部類的方法通常用在一些隱藏實現細節的地方。通常這些類只對另外的某個類有意義,對其他類來說完全沒有作用。如果定義在包里成為獨立類,反而顯得不協調。所以采用內部類的方式定義在需要使用它的類的內部,隱藏細節。

          其次靜態內部類的內部變量和方法都必須是靜態的,這樣我們才可以通過Outerclass.InnerClass.staticMethod的形式來引用他們。

          這個類的重點是parse方法,我們都知道了肯定是先從channel節點開始解析。

          Element channel = root.getChild("channel");


          ChannelIF chnl 
          = cBuilder.createChannel(channel, channel
                          .getChildTextTrim(
          "title"));

          首先獲取XML Document的root節點下的channel子節點。然后利用Jdom提供的訪問節點文本值的方法獲取channel的title。接下來就是調用ChannelBuilder的createChannel了。在這里就用到了Java的多態特性,不同的實現使用不同的構建方法。如果是使用hibernate方法,那么則是如下的過程:

              public ChannelIF createChannel(Element channelElement, String title,
                      String location) 
          {
                  ChannelIF obj 
          = null;
                  
          if (location != null{
                      Query query = session

                              .createQuery("from Channel as channel where channel.locationString = ? ");

                      query.setString(
          0, location);
                      obj 
          = (ChannelIF) query.uniqueResult();
                  }

                  
          if (obj == null{
                      obj = new Channel(channelElement, title, location);
                      session.save(obj);
                  }
           else {
                      logger
                              .info(
          "Found already existing channel instance with location "
                                      
          + location);
                  }

                  
          return obj;
              }

          先從數據庫加載,如果找不到就創建然后持久化它。

          下面的代碼則是對channel下屬的子節點和item的獲取。
                  // 1..n item elements
                  List items = channel.getChildren("item");
                  Iterator i 
          = items.iterator();
                  
          while (i.hasNext()) {
                      Element item 
          = (Element) i.next();

                      ParserUtils.matchCaseOfChildren(item, 
          new String[] "title",
                              
          "link""description""source""enclosure" }
          );

                      
          // get title element
                      Element elTitle = item.getChild("title");
                      String strTitle 
          = "<No Title>";
                      
          if (elTitle != null{
                          strTitle 
          = elTitle.getTextTrim();
                      }

                      
          if (logger.isDebugEnabled()) {
                          logger.debug(
          "Item element found (" + strTitle + ").");
                      }


                      
          // get link element
                      Element elLink = item.getChild("link");
                      String strLink 
          = "";
                      
          if (elLink != null{
                          strLink 
          = elLink.getTextTrim();
                      }


                      
          // get description element
                      Element elDesc = item.getChild("description");
                      String strDesc 
          = "";
                      
          if (elDesc != null{
                          strDesc 
          = elDesc.getTextTrim();
                      }


                      
          // generate new RSS item (link to article)
                      ItemIF rssItem = cBuilder.createItem(item, chnl, strTitle, strDesc,
                              ParserUtils.getURL(strLink));
                      rssItem.setFound(dateParsed);

                      
          // get source element (an RSS 0.92 element)
                      Element source = item.getChild("source");
                      
          if (source != null{
                          String sourceName 
          = source.getTextTrim();
                          Attribute sourceAttribute 
          = source.getAttribute("url");
                          
          if (sourceAttribute != null{
                              String location 
          = sourceAttribute.getValue().trim();
                              ItemSourceIF itemSource 
          = cBuilder.createItemSource(
                                      rssItem, sourceName, location, 
          null);
                              rssItem.setSource(itemSource);
                          }

                      }


                      
          // get enclosure element (an RSS 0.92 element)
                      Element enclosure = item.getChild("enclosure");
                      
          if (enclosure != null{
                          URL location 
          = null;
                          String type 
          = null;
                          
          int length = -1;
                          Attribute urlAttribute 
          = enclosure.getAttribute("url");
                          
          if (urlAttribute != null{
                              location 
          = ParserUtils.getURL(urlAttribute.getValue()
                                      .trim());
                          }

                          Attribute typeAttribute 
          = enclosure.getAttribute("type");
                          
          if (typeAttribute != null{
                              type 
          = typeAttribute.getValue().trim();
                          }

                          Attribute lengthAttribute 
          = enclosure.getAttribute("length");
                          
          if (lengthAttribute != null{
                              
          try {
                                  length 
          = Integer.parseInt(lengthAttribute.getValue()
                                          .trim());
                              }
           catch (NumberFormatException e) {
                                  logger.warn(e);
                              }

                          }

                          ItemEnclosureIF itemEnclosure 
          = cBuilder.createItemEnclosure(
                                  rssItem, location, type, length);
                          rssItem.setEnclosure(itemEnclosure);
                      }

                  }

          可以看到,對于這個解析過程,一般的步驟就是:
           A.獲取channnel下的某個子節點元素
           B.如果該子節點元素有子元素或屬性,則繼續遞歸訪問
           C.調用該channnel子元素的createXxx方法加載或創建該子元素
           D.調用Channel的setXxx方法添加該子元素到channel實例中

          整個RSS 0.9.1協議的解析過程如下:

          ==================根元素==================
          1. channel
          ==================必需元素==================
          2. title
          3.description
          4.link
          ==================可選元素==================
          5.language
          6.item
          7.image
          8.textinput
          9.copyright
          10.rating
          11.pubDate
          12.lastBuildDate
          13.docs
          14.managingEditor
          15.webMaster
          16.cloud

          ★RSS_2_0_Parser

          比較0.9.1和2.0協議,發現整個解析過程幾乎相同。最大的不同有以下兩點:

           A.從RSS 2.0協議開始,增加了對名稱空間(Namespace)的支持
           B.增加了對幾個2.0協議新增元素的解析

          在RSS_2_0_Parser類中,每個元素的訪問都需要使用name和namespace來區分,默認的namespace是""。其次在RSS 2.0的解析器中增加了對subjectcategoryauthorcreatorcommentsguid這些元素的解析,這些在0.9.1協議中是沒有的元素



          -------------------------------------------------------------
          生活就像打牌,不是要抓一手好牌,而是要盡力打好一手爛牌。
          posted on 2009-12-30 10:45 Paul Lin 閱讀(254) 評論(0)  編輯  收藏 所屬分類: J2SE
          <2009年12月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          常用鏈接

          留言簿(21)

          隨筆分類

          隨筆檔案

          BlogJava熱點博客

          好友博客

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 江永县| 河南省| 乐至县| 郧西县| 临清市| 南汇区| 三都| 盐亭县| 绵阳市| 黄骅市| 永福县| 清河县| 蕲春县| 红原县| 永善县| 布拖县| 大埔区| 南涧| 迁西县| 托克托县| 罗山县| 宜川县| 聂荣县| 南江县| 金门县| 乳源| 紫阳县| 洛宁县| 营口市| 边坝县| 桃源县| 辽阳县| 都江堰市| 舟山市| 双牌县| 绿春县| 保亭| 满洲里市| 克什克腾旗| 犍为县| 修文县|