Правильная Сериализация Html В .Net

Всем привет! Те, кто активно использует XSLT для генерации HTML (не XHTML), вероятно, часто сталкивались с ситуациями, когда для генерации валидного HTML необходимо генерировать не только валидный XML — XHTML, но и для браузеров, не поддерживающих XHTML. это не то же самое.

Для этого мы использовали «грязные хаки» в XSLT. В этом посте я расскажу о более чистом и красивом методе, который, к сожалению, используется не часто.

Этот метод специфичен для платформы .

Net, но другие платформы, вероятно, имеют аналогичные инструменты.

Ну а теперь по порядку.



Введение

Понятно, что представления информации XML достаточно для описания любого HTML-документа, и, более того, оно прекрасно вписывается в структуру XML. Проблема в том, что текстовое представление XML может отличаться от представления HTML того же документа.



Суть проблемы

Критические отличия сериализации XML от HTML довольно просты:
  • В документе не может быть объявлений XML. ;
  • Некоторые элементы должны иметь закрывающий тег.

    , что означает, что стандартный сериализатор XML неправильно выполнит самозакрывающийся тег для пустого div, т.к.

    парсер HTML должен ожидать закрывающий тег для div;

  • некоторые элементы не могут содержать ссылки на сущности , что означает, что анализатор HTML не обрабатывает ссылки на сущности в таких элементах, как скрипт или стиль.

Кроме того, есть ограничения, которые зависят от самого контента (сериализатор тут ни при чем), но важно, чтобы эти ограничения соблюдались:
  • Некоторые элементы могут не иметь содержимого , т.е.

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

  • некоторые элементы не могут содержать дочерние элементы или комментарии , это такие элементы, как title и textarea;
  • общие ограничения структуры документа , которые мы здесь рассматривать не будем, а оставим пытливым умам =)


Сам метод

Дело в том, что окружающая среда использует XmlWriter , который берет на себя всю работу по правильному форматированию XML. Этот класс используется практически во всех операциях, где вам нужно каким-либо образом записать XML. В частности, с преобразованиями XSL ( XslCompiledTransform.Transform ), экземпляр этого класса используется в качестве места назначения.

Итак, все, что вам нужно, это реализовать свой собственный XmlWriter, который будет корректно форматировать наш XML в соответствии с правилами HTML. Итак, представим - HtmlXmlWriter !

Теория

Давайте возьмем спецификацию HTML, а точнее HTML5 (где бы мы сейчас были без нее), и посмотрим, что в ней есть? Существует 5 типов элементов.

:

  • Пустотные элементы - область, база, br, col, команда, встраивание, час, img, ввод, генератор ключей, ссылка, мета, параметр, источник;
  • необработанные текстовые элементы — сценарий, стиль;
  • Элементы RCDATA (только текст) - текстовая область, заголовок;
  • чужеродные (внешние) элементы — любые внешние элементы, не относящиеся к HTML, в частности из MathML и SVG, но мы будем считать таковыми любые элементы не из пространства имен XHTML;
  • нормальные элементы — все остальные элементы HTML;
Теперь наш HtmlXmlWriter должен контролировать и не позволять добавлять какой-либо контент в пустые (void) элементы, и они всегда будут самозакрывающимися (Выполнение Ну собственно саму реализацию я здесь приводить не буду, она не сложная и каждый сможет сделать ее сам.

Я сделал это для себя, и возможно, когда задокументирую, а если меня слезно попросят, то выложу в какой-нибудь репозиторий кода.

Здесь я буду давать только полезные замечания (возможно, немного сумбурные).

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

HtmlXmlWriter должен отслеживать, в каком элементе он находится в данный момент (имя и тип последнего элемента), определяя это в методе XmlWriter.WriteStartElement /Вритеендэлемент. Он также должен отслеживать, присутствует ли он в атрибуте (WriteStartAttribute/WriteEndAttribute).

При закрытии элемента (WriteEndElement/WriteFullEndElement) выберите, в зависимости от типа элемента, использование WriteEndElement или WriteFullEndElement. Сложнее всего обстоят дела с необработанными текстовыми элементами, поскольку XmlWriter экранирует некоторые символы.

Поэтому необходимо заменить вывод текста на них (WriteCharEntity, WriteString, WriteSurrogateCharEntity) на WriteRaw. Но здесь надо не забыть следить за тем, чтобы в тексте не было закрывающего тега.



Заключение

Теперь имея такой класс, вы можете легко передать его в XSL-преобразования (или куда-либо еще) и получить из XHTML нормальный HTML, так что его поймет даже любой тупой парсер HTML. Теги: #xhtml #xml #HTML #html5 #.

NET #xmlwriter #htmlxmlwriter #.

NET

Вместе с данным постом часто просматривают: