xytop
@xytop
PHP/RoR web dev & tech lead

Структура данных для поиска подходящих CSS-правил

В качестве домашнего проекта начал потихоньку делать рендерер страниц на python.
Но вопрос не по языку.

Нужно организовать правильную структуру данных для удобного поиска подходящих правил.

Пример:

css:

a { display: block; font-size: 12pt; }
div p.links a { color: green; display: inline; }


Предположим, что я распарсил этот фрагмент и получил необходимую структуру.

Теперь должно быть возможно сделать такое:

cssTable.get_styles( 'html > div#content > h3 > a' );


Это возвратит: { display: block; font-size: 12pt; }

Если я запрашиваю такой путь:

cssTable.get_styles( 'html > div#content > p.links > a' );


Это должно возвратить совмещенное правило: {display: inline; color: green; font-size: 12pt;}

Есть идеи как правильно организовать такую структуру?
  • Вопрос задан
  • 4199 просмотров
Пригласить эксперта
Ответы на вопрос 4
Если учитывать что Вы не привязваетесь к DOM, то можно предположить что все возможныне css правила это бесконечное множество (конечно можно сделать его конечным с ограничениями на число элементов или длине строки правила). Теперь любой css или группу css или одно css правило можно представить как подмножество всех css правил. Как я понимаю Вы хотите сделать из подмножества группы css другое подмножество с меньшим или равным количесвом правил (иначе весь смысл теряется). Те Вы хотите для двух любых правил найти найти в лучшем случае одно, в худшем два правила. Тогда:

a {...} a {...} можно преобразовать в a {...}

a {...} div a {...} можно преобразовать в a {...} только в том случае если правила a имеют больший приоритет, например !important, в противном случае этого сделать нельзя тк данные правила определяют разные возможные подмножества.

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

Теперь поиск. Для того чтобы определить элементы которому удовлетворяет правило, необходимо пройтись по всему дереву. Это достаточно интересный момент, тк некоторые css правила могут явно описывать элементы находящиеся внутри другого правила, например:

.base .child и .base .child .node заведомо извесно что все .base .child .node элементы будут находиться внутри .base .child.

Таким образом если предствать такие правила как дерево, можно уменьшить затраты на поиск элементов в уже найденом базовом элементе.

Вариации поиска. Я вижу два основных варианта:
1. берем правило, проходим по DOM, для каждого элемента вычисляя является ли правило DOM элемента подмножеством определенного правила и применяем его, переходим к сл правилу.
2. берем DOM и начинаем проходить по нему, для элемента вычисляя является ли правило DOM элемента подмножеством определенного каждого правила и если да, то применяем его, переходи к сл элементу.

На второй вариант очень хорошо ложится предложение с деревом подправил и вообще кажется более интересным ввиду того что требуется один обход DOM.
Ответ написан
@m-haritonov
Не совсем понял в чём вопрос. Если распарсить CSS, то в итоге у Вас будет объектная структура данных CSS таблиц, их правил и селекторов (с которой Вы сможете взаимодействовать программно). И в реализации функции cssTable.get_styles Вам необходимо будет написать код, выполняющий поиск соответствующих CSS правил таблицы стилей по переданному CSS селектору (например, методом сопоставления переданного CSS селектора каждому из CSS селекторов таблицы стилей).

Т.е. когда функция, подобная Вашей cssTable.get_styles, применяется для поиска HTML элементов, она (руководствуясь переданным её CSS селектором и правилами синтаксиса CSS селекторов), находит нужный HTML элемент из всего дерева (например, сопоставляя по очереди каждый HTML элемент переданному CSS селектору). В Вашем же случае, в качестве HTML документа будет выступать таблица CSS стилей и при поиске Вы будете сопоставлять переданный функции CSS селектор каждому из CSS селектором в Вашей таблицы стилей.
Ответ написан
Daedmen
@Daedmen
Посмотри как браузеры DOM хранят
Ответ написан
seriyPS
@seriyPS
Писать собственный рендерер, да ещё на питоне это хардкорно конечно. Я бы не решился.
Мне кажется, для хранения правил CSS все же нужно непосредственно накладывать последовательно правила на DOM дерево без использования промежуточных хранилищ. Т.е. строим DOM дерево. Считываем последовательно правила из вашего CSS:
a { display: block; font-size: 12pt; }
div p.links a { color: green; display: inline; }

и последовательно накладываем правила по селектору (перезаписывая конфликтующие правила, учитывая !important и пр). Получается, что при модификации дерева придется все правила прогонять заново.

Код браузера можно попытаться тут: github.com/WebKit/webkit/tree/master/Source/WebCore/css поковырять, но там комментариев в коде нет, вряд-ли удастся что то понять =)
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы