2012-05-08 9 views
2

私はRSSフィードからいくつかのXHTMLを取り出そうとしていますので、WebViewに配置することができます。問題のRSSフィードには<content>というタグがあり、コンテンツ内の文字はXHTMLです。 (私が行っているサイトはブロガーのフィードです) このコンテンツをプルしようとする最善の方法は何ですか? <文字が私のパーサを混乱させています。私はDOMとSAXの両方を試しましたが、どちらもこれをうまく処理できません。Javaを使用してXHTMLをATOMフィードから取り出すにはどうすればよいですか?

Here is a sample of the XML as requested.この場合、基本的にコンテンツタグ内のXHTMLを文字列にします。 <content> XHTML </content>

編集:ignyhereの提案に基づいて私はXPathを試しましたが、私はまだ同じ問題を抱えています。 Here is a pastebin sample of my tests.

+0

いくつかのサンプルxhtmlを含めることができますか? – waqaslam

+0

@Waqasサンプルで質問を更新しました。 – schwiz

+0

http://www.xml.com/pub/a/2006/02/22/rome-parse-publish-rss-atom-feeds-java.htmlまたは別のlib http://www.giantflyingsaucer.com/blog /?p = 3308 – ant

答えて

3

これはかなりありませんが、これはXmlPullParserを使用してBloggerからATOMフィードを解析するためのものです(の本質)。コードはかなり不快ですが、実際のアプリからです。あなたはおそらくそれの一般的な風味を得ることができます、とにかく。

final String TAG_FEED = "feed"; 

public int parseXml(Reader reader) { 
    XmlPullParserFactory factory = null; 
    StringBuilder out = new StringBuilder(); 
    int entries = 0; 

    try { 
     factory = XmlPullParserFactory.newInstance(); 
     factory.setNamespaceAware(true); 
     XmlPullParser xpp = factory.newPullParser(); 
     xpp.setInput(reader); 

     while (true) { 
      int eventType = xpp.next(); 
      if (eventType == XmlPullParser.END_DOCUMENT) { 
       break; 
      } else if (eventType == XmlPullParser.START_DOCUMENT) { 
       out.append("Start document\n"); 
      } else if (eventType == XmlPullParser.START_TAG) { 
       String tag = xpp.getName(); 
       // out.append("Start tag " + tag + "\n"); 
       if (TAG_FEED.equalsIgnoreCase(tag)) { 
        entries = parseFeed(xpp); 
       } 
      } else if (eventType == XmlPullParser.END_TAG) { 
       // out.append("End tag " + xpp.getName() + "\n"); 
      } else if (eventType == XmlPullParser.TEXT) { 
       // out.append("Text " + xpp.getText() + "\n"); 
      } 
     } 
     out.append("End document\n"); 

    } catch (XmlPullParserException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    //  return out.toString(); 
    return entries; 

} 

private int parseFeed(XmlPullParser xpp) throws XmlPullParserException, IOException { 
    int depth = xpp.getDepth(); 
    assert (depth == 1); 
    int eventType; 
    int entries = 0; 
    xpp.require(XmlPullParser.START_TAG, null, TAG_FEED); 
    while (((eventType = xpp.next()) != XmlPullParser.END_DOCUMENT) && (xpp.getDepth() > depth)) { 
     // loop invariant: At this point, the parser is not sitting on 
     // end-of-document, and is at a level deeper than where it started. 

     if (eventType == XmlPullParser.START_TAG) { 
      String tag = xpp.getName(); 
      // Log.d("parseFeed", "Start tag: " + tag); // Uncomment to debug 
      if (FeedEntry.TAG_ENTRY.equalsIgnoreCase(tag)) { 
       FeedEntry feedEntry = new FeedEntry(xpp); 
       feedEntry.persist(this); 
       entries++; 
       // Log.d("FeedEntry", feedEntry.title); // Uncomment to debug 
       // xpp.require(XmlPullParser.END_TAG, null, tag); 
      } 
     } 
    } 
    assert (depth == 1); 
    return entries; 
} 

class FeedEntry { 
    String id; 
    String published; 
    String updated; 
    // Timestamp lastRead; 
    String title; 
    String subtitle; 
    String authorName; 
    int contentType; 
    String content; 
    String preview; 
    String origLink; 
    String thumbnailUri; 
    // Media media; 

    static final String TAG_ENTRY = "entry"; 
    static final String TAG_ENTRY_ID = "id"; 
    static final String TAG_TITLE = "title"; 
    static final String TAG_SUBTITLE = "subtitle"; 
    static final String TAG_UPDATED = "updated"; 
    static final String TAG_PUBLISHED = "published"; 
    static final String TAG_AUTHOR = "author"; 
    static final String TAG_CONTENT = "content"; 
    static final String TAG_TYPE = "type"; 
    static final String TAG_ORIG_LINK = "origLink"; 
    static final String TAG_THUMBNAIL = "thumbnail"; 
    static final String ATTRIBUTE_URL = "url"; 

    /** 
    * Create a FeedEntry by pulling its bits out of an XML Pull Parser. Side effect: Advances 
    * XmlPullParser. 
    * 
    * @param xpp 
    */ 
public FeedEntry(XmlPullParser xpp) { 
    int eventType; 
    int depth = xpp.getDepth(); 
    assert (depth == 2); 
    try { 
     xpp.require(XmlPullParser.START_TAG, null, TAG_ENTRY); 
     while (((eventType = xpp.next()) != XmlPullParser.END_DOCUMENT) 
     && (xpp.getDepth() > depth)) { 

      if (eventType == XmlPullParser.START_TAG) { 
       String tag = xpp.getName(); 
       if (TAG_ENTRY_ID.equalsIgnoreCase(tag)) { 
        id = Util.XmlPullTag(xpp, TAG_ENTRY_ID); 
       } else if (TAG_TITLE.equalsIgnoreCase(tag)) { 
        title = Util.XmlPullTag(xpp, TAG_TITLE); 
       } else if (TAG_SUBTITLE.equalsIgnoreCase(tag)) { 
        subtitle = Util.XmlPullTag(xpp, TAG_SUBTITLE); 
       } else if (TAG_UPDATED.equalsIgnoreCase(tag)) { 
        updated = Util.XmlPullTag(xpp, TAG_UPDATED); 
       } else if (TAG_PUBLISHED.equalsIgnoreCase(tag)) { 
        published = Util.XmlPullTag(xpp, TAG_PUBLISHED); 
       } else if (TAG_CONTENT.equalsIgnoreCase(tag)) { 
        int attributeCount = xpp.getAttributeCount(); 
        for (int i = 0; i < attributeCount; i++) { 
         String attributeName = xpp.getAttributeName(i); 
         if (attributeName.equalsIgnoreCase(TAG_TYPE)) { 
          String attributeValue = xpp.getAttributeValue(i); 
          if (attributeValue 
          .equalsIgnoreCase(FeedReaderContract.FeedEntry.ATTRIBUTE_NAME_HTML)) { 
           contentType = FeedReaderContract.FeedEntry.CONTENT_TYPE_HTML; 
           } else if (attributeValue 
           .equalsIgnoreCase(FeedReaderContract.FeedEntry.ATTRIBUTE_NAME_XHTML)) { 
            contentType = FeedReaderContract.FeedEntry.CONTENT_TYPE_XHTML; 
           } else { 
            contentType = FeedReaderContract.FeedEntry.CONTENT_TYPE_TEXT; 
           } 
           break; 
          } 
         } 
         content = Util.XmlPullTag(xpp, TAG_CONTENT); 
         extractPreview(); 
        } else if (TAG_AUTHOR.equalsIgnoreCase(tag)) { 
         // Skip author for now -- it is complicated 
         int authorDepth = xpp.getDepth(); 
         assert (authorDepth == 3); 
         xpp.require(XmlPullParser.START_TAG, null, TAG_AUTHOR); 
         while (((eventType = xpp.next()) != XmlPullParser.END_DOCUMENT) 
         && (xpp.getDepth() > authorDepth)) { 
         } 
         assert (xpp.getDepth() == 3); 
         xpp.require(XmlPullParser.END_TAG, null, TAG_AUTHOR); 

        } else if (TAG_ORIG_LINK.equalsIgnoreCase(tag)) { 
         origLink = Util.XmlPullTag(xpp, TAG_ORIG_LINK); 
        } else if (TAG_THUMBNAIL.equalsIgnoreCase(tag)) { 
         thumbnailUri = Util.XmlPullAttribute(xpp, tag, null, ATTRIBUTE_URL); 
        } else { 
         @SuppressWarnings("unused") 
          String throwAway = Util.XmlPullTag(xpp, tag); 
        } 
       } 
      } // while 
     } catch (XmlPullParserException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     assert (xpp.getDepth() == 2); 
    } 
} 

public static String XmlPullTag(XmlPullParser xpp, String tag) 
    throws XmlPullParserException, IOException { 
    xpp.require(XmlPullParser.START_TAG, null, tag); 
    String itemText = xpp.nextText(); 
    if (xpp.getEventType() != XmlPullParser.END_TAG) { 
     xpp.nextTag(); 
    } 
    xpp.require(XmlPullParser.END_TAG, null, tag); 
    return itemText; 
} 

public static String XmlPullAttribute(XmlPullParser xpp, 
    String tag, String namespace, String name) 
throws XmlPullParserException, IOException { 
    assert (!TextUtils.isEmpty(tag)); 
    assert (!TextUtils.isEmpty(name)); 
    xpp.require(XmlPullParser.START_TAG, null, tag); 
    String itemText = xpp.getAttributeValue(namespace, name); 
    if (xpp.getEventType() != XmlPullParser.END_TAG) { 
     xpp.nextTag(); 
    } 
    xpp.require(XmlPullParser.END_TAG, null, tag); 
    return itemText; 
} 

私はあなたにヒントを与えます:戻り値は重要ではありません。データは、次の行にある方法(図示せず)によってデータベースに保存されます。

feedEntry.persist(this); 
+0

偉大な答えをありがとう!ここに浸ることはたくさんありますが、これは私が使い終わったものよりはるかに強く、より頑丈なソリューションのように見えます。これを一度に試してみると、少し時間がかかります。 – schwiz

3

私はXPathで攻撃しようとします。この作品のようなものはありますか?

public static String parseAtom (InputStream atomIS) 
    throws Exception { 

    // Below should yield the second content block 
    String xpathString = "(//*[starts-with(name(),"content")])[2]"; 
    // or, String xpathString = "//*[name() = 'content'][2]"; 
    // remove the '[2]' to get all content tags or get the count, 
    // if needed, and then target specific blocks 
    //String xpathString = "count(//*[starts-with(name(),"content")])"; 
    // note the evaluate expression below returns a glob and not a node set 

    XPathFactory xpf    = XPathFactory.newInstance(); 
    XPath xpath     = xpf.newXPath(); 
    XPathExpression xpathCompiled = xpath.compile (xpathString); 

    // use the first to recast and evaluate as NodeList 
    //Object atomOut = xpathCompiled.evaluate ( 
    // new InputSource (atomIS), XPathConstants.NODESET); 
    String atomOut = xpathCompiled.evaluate ( 
     new InputSource (atomIS), XPathConstants.STRING); 

    System.out.println (atomOut); 

    return atomOut; 

} 
+0

に追加しました。それほどうまくいきませんでした。より堅牢なサンプルを提供できるとは思いませんか?私はXpathに慣れていないので、おそらく私は愚かな間違いをしています。あなたが気にしていれば私のテストのペーストビンで私の質問を更新します。 – schwiz

+0

申し訳ありませんが、私は与えられたシナリオで動作するようにXPath式を変更しました。 – ingyhere

+0

アップデートをお寄せいただきありがとうございます。ダウンタイムが発生した場合、私はあなたのXPathでテストする必要があります。しかし、私は(私の問題は名前空間だった)後のコンテンツノードでハンドルを取得することができましたが、それでも完全にxhtmlを引き出していませんでした。あなたの助けのためのまだupvotes: – schwiz

1

私はここにあなたの問題を見ることができ、あなたの<content>タグの内容は、私がどうなるのか<![CDATA[ ]]>、にラップされていないので、私は、私は「より適切な解決策を見つけるまでは、これらのパーサーは、正しい結果を生成していない理由は、 d迅速かつ汚れたトリックを使用してください:

private void parseFile(String fileName) throws IOException { 
     String line; 
     BufferedReader br = new BufferedReader(new FileReader(new File(fileName))); 
     StringBuilder sb = new StringBuilder(); 
     boolean match = false; 

     while ((line = br.readLine()) != null) { 
      if(line.contains("<content")){ 
       sb.append(line); 
       sb.append("\n"); 
       match = true; 
       continue; 
      } 

      if(match){ 
       sb.append(line); 
       sb.append("\n"); 
       match = false; 
      } 

      if(line.contains("</content")){ 
       sb.append(line); 
       sb.append("\n"); 
      } 
     } 

     System.out.println(sb.toString()); 
    } 

これは、Stringのすべてのコンテンツを提供します。この方法をわずかに変更することによってオプションで分離することもできますし、実際には不要な場合は<content>でもフィルタリングすることができます。

+0

CDATAに関する洞察をお寄せいただき、ありがとうございました。文字列置換を行うだけで、コンテンツの後にCDATAタグを追加しました。 SAXはまだそれを処理できませんでしたが、DOMは私が望むようにそれを読んでいます。おそらく最高の解決策ではありませんが、私の要件を満たしています。 – schwiz

+0

不合理。 xmlに要素の内容をCDATAでラップする必要はありません。これは、データがXML用に正しくエンコードされていない場合にのみ必要です。彼はサーバーが提供するものを扱っており、結果セットを変更することは必須ではありません。 – ingyhere

+0

@ingyhere yeah私は解決策に満足していると言っているわけではありません。私はちょうど少なくともそれが働いていると言っています:-) – schwiz

関連する問題