Парсер CSS для .NET, написанный на C#

в 7:43, , рубрики: Без рубрики

(Попытка №2. Без лишней лирики, дабы опять не принялись сливать. Не горю желанием ловить плевки в рожу за проделанный труд.)

Парсер CSS для .NET, написанный на C# Понадобилось мне однажды распарсить CSS, чтобы вынуть @import, url(). Но для .NET были только разной степени кривоты поделки. Лучшей библиотекой была ExCSS, но она загибалась на таких тривиальных вещах, как медиа-запросы. Поэтому я решил заполнить пробел.

Были варианты: расковырять Chrome, расковырять Firefox, расковырять левую библиотеку. Нужно было гарантированное качество и регулярное обновление, поэтому последний вариант отпадал. В Chrome парсинг CSS и HTML генерировался на основе грамматик, и беглое изучение разнообразия инструментов для .NET повергло в уныние, что уж говорить о совместимости инструментов, поэтому Chrome отпал. Остался Firefox с вручную написанными парсерами.

(...)

Долго ли, коротко ли, в итоге получилась библиотека, которая полноценно распарсивает скормленные ей CSS файлы. Тесты в Firefox оказалось слишком проблематично конвертировать, да и не юнит-тесты они вовсе: написаны на JS, лежат внутри HTML. Поэтому полноценно проверить работу библиотеки оказалось проблематичным. Если у кого-нибудь есть предложения, где взять хорошие юнит-тесты для CSS — я весь внимание. Я очень надеюсь, что библиотека хоть кому-то пригодится, и, если обнаружатся проблемы, то мне об этом сообщит.

Что имеется

  • Поддерживаются все правила, свойства, значения и т.п., которые поддерживаются Mozilla Firefox. Специфические для ФФ расширения (-moz-*) в том числе.
  • Два режима совместимости: Full Standards (строгое следование стандартам) и Quirks (можно не указывать единицы измерения и позволять другие подобные вольности).
  • Все значения распарсиваются в сложные структуры. Краткое свойство background развернётся в несколько свойств, в том числе background-image, которое содержит список фоновых картинок, каждая из которых — URL или градиент; в последнем случае в градиенте будут содержаться отдельные точки и все параметры.
  • Обработка ошибок в соответствии со всеми спецификациями. Если что-то не распознает, то парсер просто пропустит непонятный кусок.
  • Детальное логирование ошибок. Все предупреждения про неверный синтаксис и свойства сваливаются в TraceSource "Alba.CsCss.CssParser" и кидаются событием.

Чего не имеется

  • Поддержка кодировок. В юникод нужно перекидывать самостоятельно.
  • Модификация и конвертация обратно в строку.
  • DOM CSS. Интерфейс с точки зрения стандартов кодирования C# весьма сомнителен, поэтому польза под вопросом.
  • Свойства с вендорными префиксами остальных браузеров (-webkit-, -ms-, -o-) игнорируются.
  • .NET 4.0 и ниже. От .NET 4.5 используется разве что IReadOnlyList, но пока возиться с версиями несколько лень.
  • Пакет NuGet. Сыровата пока библиотека.

Кодировки, модификацию, сериализацию, .NET 4.0 и пакет NuGet планирую добавить. Как скоро это произойдёт — зависит от того, нужно ли это кому-нибудь.

Пример использования

// Распарсить CSS, указав URL файла (для логирования) и базовый URL (для резолва относительных урлов)
CssStyleSheet css = new CssLoader().ParseSheet("h1, h2 { color: #123; }",
    "http://example.com/sheet.css", "http://example.com/");
Console.WriteLine(css.SheetUri); // http://example.com/sheet.css
// Получить цвет (варианты равносильны)
Console.WriteLine(css.StyleRules.Single().Declaration.Color.Color.R); // 17
Console.WriteLine(css.Rules.OfType<CssStyleRule>.Single().Declaration
                               .Data.Single().Color.R); // 17
Console.WriteLine(css.Rules.OfType<CssStyleRule>.Single().Declaration
                               .GetValue(CssProperty.Color).Color.R); // 17
// Получить тег в первом селекторе
Console.WriteLine(css.StyleRules.Single().SelectorGroups.First().Selectors.Single().Tag); // h1

Сборка проекта

  • Alba.CsCss — собственно библиотека. Зависимостей от других проектов не имеет. Если хотите использовать библитеку в своём солюшене, достаточно включить этот проект.
  • Alba.CsCss.Tests — юнит-тесты. Количество такое, о котором в приличном обществе принято молчать.
  • Alba.Framework — персональный сборник велосипедов фреймворк. Упрощает код в трансформациях T4. Для запуска оных нужно собрать Debug версию.
  • Alba.Framework.CodeGeneration — T4 часть фреймворка. Собираться должен под админским аккаунтом, чтобы установить custom tool «AttachT4» (родственно T4 Toolbox, только без тонны ненужных фич). Нужно, если хотите удобно работать с T4 в проекте.
  • Alba.Framework.Testing — используется в тестах.

Лицензия

Mozilla Public License. Помесь BSD с GPL. Вирусная, как GPL, но заражает только отдельные файлы сорцов с кодом MPL. Всё остальное лицензию не волнует. Никаких ограничений на использование вместе с проектами под другими лицензиями, в том числе коммерческими с закрытым кодом — нет.

Понятное дело, я бы предпочёл выпустить библиотеку под более либеральной и понятной лицензией BSD/MIT, но MPL «заразила» большую часть файлов, поэтому вариантов не осталось.

Итоги

Библиотека написана. Будет ли она развиваться — зависит от того, будет ли она использоваться. Мне самому-то только малая часть нужна. Надеюсь на баг-репорты, а, возможно, даже пулл-реквесты, если есть смелые.

Ссылки

P.S. Как я конвертировал библиотеку, какие цели преследовал и т.п. — урезанно в ReadMe на GitHub. Мою попытку рассказать о мытарствах Хабр не оценил, поэтому только сухие факты. Всем добра.

Автор: Athari

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js