7

Web サービスを呼び出すと、XML エンベロープで HTML が返される状況があります。お気に入り:

<xml version="1.0" cache="false">
<head/>
<body>
<table>
<tr>
   <td>
        <a href="link-to-prev-post">
           <text color="red"><< Prev</text>
        </a>
   </td>
   <td>
        <a href="link-to-next-post">
           <text color="red">| Next >></text>
        </a>
   </td>
</tr>
</table>
</body>
</xml>

前の投稿へのリンクと次の投稿へのリンクのリンク取得する必要があるため、これらのリンクからより多くのデータを取得できます。

上記の XML/HTML を解析するためにXmlPullParserを使用しています。次/前のアイテムへのリンクを取得するには、次のようにしています。

if (xmlNodeName.equalsIgnoreCase("a")) {
                link = parser.getAttributeValue(null, "href");

            } else if (xmlNodeName.equalsIgnoreCase("text")) {
                color = parser.getAttributeValue(null, "color");

                if (color.equalsIgnoreCase("red") && parser.getEventType() == XmlPullParser.START_TAG) {
                        // check for next/prev blog entries links
                        // but this parser.nextText() throws XmlPullParserException
                        // i think because the nextText() returns << Prev which the parser considers to be wrong
                        String innerText = parser.nextText();
                        if (innerText.contains("<< Prev")) {
                            blog.setPrevBlogItemsUrl(link);                             
                        } else if (innerText.contains("Next >>")) {
                            blog.setNextBlogItemsUrl(link);
                        }
                    }

                    link = null;
                }
            }

parser.nextText()の実行時に XmlPullParserException をスローする...そして、このときのテキスト要素の値は<< Prev ..テキストに<<が存在するため、開始タグでこの値を誤解していると思います..

LogCat の詳細は次のとおりです。

04-08 18:32:09.827: W/System.err(688): org.xmlpull.v1.XmlPullParserException: precondition: START_TAG (position:END_TAG </text>@9:2535 in java.io.InputStreamReader@44c6d0d8) 
04-08 18:32:09.827: W/System.err(688):  at org.kxml2.io.KXmlParser.exception(KXmlParser.java:245)
04-08 18:32:09.827: W/System.err(688):  at org.kxml2.io.KXmlParser.nextText(KXmlParser.java:1382)
04-08 18:32:09.827: W/System.err(688):  at utilities.XMLParserHelper.parseBlogEntries(XMLParserHelper.java:139)
04-08 18:32:09.827: W/System.err(688):  at serviceclients.PlayerSummaryAsyncTask.doInBackground(PlayerSummaryAsyncTask.java:68)
04-08 18:32:09.827: W/System.err(688):  at serviceclients.PlayerSummaryAsyncTask.doInBackground(PlayerSummaryAsyncTask.java:1)
04-08 18:32:09.836: W/System.err(688):  at android.os.AsyncTask$2.call(AsyncTask.java:185)
04-08 18:32:09.836: W/System.err(688):  at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
04-08 18:32:09.836: W/System.err(688):  at java.util.concurrent.FutureTask.run(FutureTask.java:137)
04-08 18:32:09.836: W/System.err(688):  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
04-08 18:32:09.836: W/System.err(688):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
04-08 18:32:09.836: W/System.err(688):  at java.lang.Thread.run(Thread.java:1096)

問題が明確になったことを願っています。

解決

受信したデータを最初に文字列に変換するというMartin のアプローチに触発されて、私は一種の混合アプローチで問題を管理しました。

  1. 受信したInputStreamの値を文字列に変換し、誤った文字を * (または任意のもの) に置き換えます: 次のように

    InputStreamReader isr = new InputStreamReader(serviceReturnedStream);
    
    BufferedReader br = new BufferedReader(isr);
    StringBuilder xmlAsString = new StringBuilder(512);
    String line;
    try {
        while ((line = br.readLine()) != null) {
            xmlAsString.append(line.replace("<<", "*").replace(">>", "*"));
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    
  2. これで、正しい XML データ (私の場合) を含む文字列ができたので、自分で手動で解析する代わりに、通常の XmlPullParser を使用して解析します。

    XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
    
    factory.setNamespaceAware(false);
    
    XmlPullParser parser = factory.newPullParser();
    parser.setInput(new StringReader(xmlAsString.toString()));
    

これが誰かを助けることを願っています!

4

1 に答える 1

6

はい、 XML 1.0 仕様のセクション2.4 Character Data and Markupに従って無効な XML であるため、おそらく例外がスローされます。

[...] 左山括弧 (<) は、[その] リテラル形式で表示してはなりません [...]

その XML を Eclipse に入れると、Eclipse は XML が無効であると文句を言います。Web サービスを修正できる場合は、生成された XML を修正する必要があります。これには、エンティティ参照などを使用するか、CDATA&lt;を使用します。

Web サービスに対する権限がない場合は、一般性の要件がどれだけ緩和されているかに応じて、おそらく正規表現を使用して、カスタム コードを使用して手動で解析するのが最も簡単だと思います。

サンプルコード

上記の XML ファイルを解析する方法は次のとおりです。おそらくこのコードをより一般的なものにするために改善したいと思うでしょうが、少なくとも何かを始める必要があることに注意してください:

    // Read the XML into a StringBuilder so we can get get a Matcher for the
    // whole XML
    InputStream xmlResponseInputStream = // Get InputStream to XML somehow
    InputStreamReader isr = new InputStreamReader(xmlResponseInputStream);
    BufferedReader br = new BufferedReader(isr);
    StringBuilder xmlAsString = new StringBuilder(512);
    String line;
    try {
        while ((line = br.readLine()) != null) {
            xmlAsString.append(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

    // Look for links using a regex. Assume the first link is "Prev" and the
    // next link is "Next"
    Pattern hrefRegex = Pattern.compile("<a href=\"([^\"]*)\">");
    Matcher m = hrefRegex.matcher(xmlAsString);
    String linkToPrevPost = null;
    String linkToNextPost = null;
    while (m.find()) {
        String hrefValue = m.group(1);
        if (linkToPrevPost == null) {
            linkToPrevPost = hrefValue;
        } else {
            linkToNextPost = hrefValue;
        }
    }

    Log.i("Example", "'Prev' link = " + linkToPrevPost + 
            " 'Next' link = " + linkToNextPost);

XML ファイルを使用すると、logcat への出力は次のようになります。

I/Example (12399): 'Prev' link = link-to-prev-post 'Next' link = link-to-next-post
于 2012-04-11T11:40:10.120 に答える