AngleSharp извлекает форматированный текст

Мне интересно, можно ли извлечь форматированный текст из HTMLDocument с помощью AngleSharp. Я использую следующий код для извлечения текста. У меня проблема в том, что извлеченный текст идет вместе, между каждым из элементов нет разрыва.

var parser = new HtmlParser();
var document = parser.Parse("<script>var x = 1;</script> <h1>Some example source</h1><p>This is a paragraph element</p>");
var text = document.Body.Text();

Это возвращает следующий текст

Пример источника. Это элемент абзаца

В идеале я хотел бы, чтобы он возвращал Некоторый пример источника. Это элемент абзаца, где есть некоторое разделение между текстовыми значениями каждого из узлов.


person Bigtoe    schedule 21.04.2017    source источник
comment
Поскольку в документе нет разделения, в тексте ничего не будет возвращено. Если вы хотите что-то подобное, вам придется вручную обрабатывать структуру документа и решать, где разместить разделение.   -  person Sami Kuhmonen    schedule 21.04.2017
comment
Спасибо за ответ, Сами, я ценю этот факт, это настолько частое требование, что я надеялся, что оно будет доступно как часть библиотеки. В частности, там, где требуется разбор текста в HTML-документе. Например, извлечение текстового содержимого и его индексация, скажем, в Elastic Search — обычное дело.   -  person Bigtoe    schedule 21.04.2017


Ответы (1)


Я знаю, что опаздываю на вечеринку, но лучше поздно, чем никогда (также я надеюсь, что этот ответ принесет пользу кому-то еще).

Оба комментария к вопросу правильные. С одной стороны, у нас есть спецификация W3C и источник документа, который говорит нам, что в (официальной) сериализации не будет места, с другой стороны, у нас есть довольно распространенный случай «интегрировать» некоторые пробелы, когда это применимо. (или, может быть, даже новые строки, например, если виден элемент <br>).

При написании библиотека не знает вашего конкретного варианта использования (т. е. когда вы хотите вставить пробелы). Однако это может помочь вам более легко перейти в желаемое состояние.

Сериализация из DOM в строку выполняется через экземпляр класса, который реализует IMarkupFormatter. Метод ToHtml() любого узла DOM принимает такой объект для возврата строки. делать

var myFormatter = new MyMarkupFormatter();
var text = document.Body.ToHtml(myFormatter);

Теперь вопрос сводится к реализации MyMarkupFormatter, которая у нас работает. Однако этот модуль форматирования по существу выдает только текстовые узлы, а некоторые теги обрабатываются по-разному (например, возвращая некоторый текст, например пробелы).

public class MyMarkupFormatter : IMarkupFormatter
{
    String IMarkupFormatter.Comment(IComment comment)
    {
        return String.Empty;
    }

    String IMarkupFormatter.Doctype(IDocumentType doctype)
    {
        return String.Empty;
    }

    String IMarkupFormatter.Processing(IProcessingInstruction processing)
    {
        return String.Empty;
    }

    String IMarkupFormatter.Text(ICharacterData text)
    {
        return text.Data;
    }

    String IMarkupFormatter.OpenTag(IElement element, Boolean selfClosing)
    {
        switch (element.LocalName)
        {
            case "p":
                return "\n\n";
            case "br":
                return "\n";
            case "span":
                return " ";
        }

        return String.Empty;
    }

    String IMarkupFormatter.CloseTag(IElement element, Boolean selfClosing)
    {
        return String.Empty;
    }

    String IMarkupFormatter.Attribute(IAttr attr)
    {
        return String.Empty;
    }
}

Если вам не нужно удаление всей нетекстовой информации, AngleSharp также предлагает PrettyMarkupFormatter из коробки - возможно, это уже довольно близко к тому, что вы хотели («более красивый» форматировщик разметки).

Надеюсь это поможет!

person Florian Rappl    schedule 12.12.2017
comment
Для всех в конце 2019 года параметр для IMarkupFormatter.Text теперь имеет значение ICharacterData, поэтому вместо возврата text возвращается text.Data. - person Josiah Nunemaker; 18.12.2019
comment
Спасибо @JosiahNunemaker - исправлено! - person Florian Rappl; 19.12.2019