Inputstream обрабатывается различными объектами в зависимости от содержимого - PullRequest
1 голос
/ 21 июля 2011

Я пишу сканер / анализатор, который должен иметь возможность обрабатывать различные типы контента, такие как RSS, Atom и просто обычные HTML-файлы. Чтобы определить правильный синтаксический анализатор, я написал класс ParseFactory, который принимает URL-адрес, пытается определить тип содержимого и возвращает правильный синтаксический анализатор.

К сожалению, проверка типа содержимого с использованием предоставленного метода in в URLConnection не всегда работает. Например,

String contentType = url.openConnection().getContentType();

не всегда обеспечивает правильный тип содержимого (например, «text / html», где это должно быть RSS) или не позволяет различать RSS и Atom (например, «application / xml» может быть как Atom, так и RSS-канал). Чтобы решить эту проблему, я начал искать подсказки в InputStream. Проблема в том, что у меня возникают проблемы при создании элегантного дизайна класса, когда мне нужно загрузить InputStream только один раз. В моем текущем проекте я сначала написал отдельный класс, который определяет правильный тип содержимого, затем ParseFactory использует эту информацию для создания экземпляра соответствующего анализатора, который, в свою очередь, когда вызывается метод parse (), загружает весь InputStream во второй раз.

public Parser createParser(){

    InputStream inputStream = null;
    String contentType = null;
    String contentEncoding = null;

    ContentTypeParser contentTypeParser = new ContentTypeParser(this.url);
    Parser parser = null;

    try {

        inputStream = new BufferedInputStream(this.url.openStream());
        contentTypeParser.parse(inputStream);
        contentType = contentTypeParser.getContentType();
        contentEncoding = contentTypeParser.getContentEncoding();

        assert (contentType != null);

        inputStream = new BufferedInputStream(this.url.openStream());

        if (contentType.equals(ContentTypes.rss))
        {
            logger.info("RSS feed detected");
            parser = new RssParser(this.url);
            parser.parse(inputStream);
        }
        else if (contentType.equals(ContentTypes.atom))
        {
            logger.info("Atom feed detected");
            parser = new AtomParser(this.url);
        }
        else if (contentType.equals(ContentTypes.html))
        {
            logger.info("html detected");
            parser = new HtmlParser(this.url);
            parser.setContentEncoding(contentEncoding);
        }
        else if (contentType.equals(ContentTypes.UNKNOWN))
            logger.debug("Unable to recognize content type");

        if (parser != null)
            parser.parse(inputStream);

    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    return parser;

}

По сути, я ищу решение, которое позволило бы мне исключить второй "inputStream = new BufferedInputStream (this.url.openStream ())".

Любая помощь будет принята с благодарностью!

Примечание 1: просто для полноты я также попытался использовать метод URLConnection.guessContentTypeFromStream (inputStream), но он слишком часто возвращает ноль.

Примечание 2: XML-парсеры (Atom и Rss) основаны на SAXParser, Html-парсере в Jsoup.

Ответы [ 2 ]

1 голос
/ 21 июля 2011

Можете ли вы просто позвонить mark и reset?

inputStream = new BufferedInputStream(this.url.openStream());
inputStream.mark(2048); // Or some other sensible number

contentTypeParser.parse(inputStream);
contentType = contentTypeParser.getContentType();
contentEncoding = contentTypeParser.getContentEncoding();

inputstream.reset(); // Let the parser have a crack at it now
0 голосов
/ 21 июля 2011

Возможно, ваш ContentTypeParser должен кэшировать содержимое внутри и передать его соответствующему ContentParser вместо повторного запроса данных из InputStream.

...