web-dev-qa-db-ja.com

SimpleXMLを使用してCDATAと通常のデータの両方でxml要素を処理する方法

RSSフィードからの次の応答を逆シリアル化する方法を理解するのに苦労しています。テキストblah blah blahなどと埋め込み画像ソースhttp://Host/path/to/picture.jpgが必要です。

<description>blah blah blah blah br /&gt;
<![CDATA[<img src=http://Host/path/to/picture.jpg>]]>&lt;br /&gt;
blah blah blah blah&lt;br /&gt;&lt;br /&gt;
</description>

ここに私のモデルクラスがあります(または私が望むものです)-簡潔にするために短縮しました:

public static class Item {

    ...

    @Element(name="description", required=false)
    String descriptionContent;

    String imageLink;
    ...

}

ドキュメントから、data=true属性に@Elementを設定できることがわかっていますが、私のリーディングから、要素のコンテンツ全体が部分的ではなくCDATAである場合に機能します。

私はこれをAndroid RetrofitとSimpleXMLConverterを使用して実行していますが、それは単にbyによると思います。

2
piratemurray

私は最終的にこれを理解しました。うまくいけば、これは将来的に他の人を助けるでしょう。

必要なのは、逆シリアル化プロセスを中断し、カスタムコードを実行してデータを抽出する方法です。 SimpleXML を使用すると、シリアル化/非シリアル化にさまざまな戦略を使用できます。私はアノテーション戦略と呼ばれるものを選びました。私はPOJOモデルクラスに@Convertコンバータークラスを指すアノテーション。

....

@Element(name="description", required=false)
@Convert(DescriptionConverter.class)
Description description;

...

そして、コンバーターは次のようになります。

public class DescriptionConverter implements Converter<RssFeed.Description> {

    @Override
    public RssFeed.Description read(InputNode node) throws Exception {
        final String IMG_SRC_REG_EX = "<img src=([^>]+)>";
        final String HTML_TAG_REG_EX = "</?[^>]+>";

        String nodeText = node.getValue();

        Pattern imageLinkPattern = Pattern.compile(IMG_SRC_REG_EX);
        Matcher matcher = imageLinkPattern.matcher(nodeText);

        String link = null;
        while (matcher.find()) {
            link = matcher.group(1);
        }

        String text = nodeText.replaceFirst(IMG_SRC_REG_EX, "")
                              .replaceAll(HTML_TAG_REG_EX, "");

        return new RssFeed.Description(text, link);
    }

    @Override
    public void write(OutputNode node, RssFeed.Description value) throws Exception {
            ...
    }

}

Simpleに別の戦略を使用するように指示する必要がありますが、そうしないとアノテーションが無視されます。 RetrofitとSimpleXMLConverterを使用しているとすると、ここに私の実装は次のようになります。

private static final Retrofit.Builder builder = new Retrofit.Builder()
            .baseUrl(API_BASE_URL)
            .addConverterFactory(SimpleXmlConverterFactory.create(new Persister(new AnnotationStrategy())));
3
piratemurray