Понадобилось мне однажды распарсить 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 «заразила» большую часть файлов, поэтому вариантов не осталось.
Итоги
Библиотека написана. Будет ли она развиваться — зависит от того, будет ли она использоваться. Мне самому-то только малая часть нужна. Надеюсь на баг-репорты, а, возможно, даже пулл-реквесты, если есть смелые.
Если вам нужен парсер CSS, то, пожалуйста, напишите, как вы собираетесь его использовать. Это очень важно, чтобы понять дальнейший путь развития и приоритеты.
Ссылки
P.S. Как я конвертировал библиотеку, какие цели преследовал и т.п. — урезанно в ReadMe на GitHub. Мою попытку рассказать о мытарствах Хабр не оценил, поэтому только сухие факты. Всем добра.
