Нормализация Nokogiri CSS

#css #ruby #nokogiri

#css #ruby #nokogiri

Вопрос:

У меня есть некоторые атрибуты, такие как:

 <span style="font:22px Arial">...</span>
  

и другие подобные:

 <span style="font-size:22px;font-family:Arial">...</span>
  

Теперь я могу получить атрибут style с помощью nokogiri, но мне бы хотелось получить следующую информацию:

  • семейство шрифтов
  • размер шрифта
  • Цвет
  • оформление текста
  • вес шрифта
  • стиль шрифта

Некоторые атрибуты, такие как цвет, получить легко, но некоторые другие, такие как размер шрифта, требуют довольно большой работы со строкой css.

Прежде чем заняться собственным решением, мне было интересно, сможет ли nokogiri или, возможно, специализированный css gem нормализовать строку css и позволить мне запрашивать css-атрибуты один за другим. Было бы еще удобнее, если бы я мог получить вычисленный css (например, элемент без размера шрифта внутри элемента с размером шрифта 10 дал бы мне 10, когда я запрашиваю размер шрифта для дочернего элемента), но эту последнюю часть легко реализовать с помощью хэша и стека, так что это не очень важно.

Ответ №1:

Хм. Анализатор DOM JavaScript мог бы сделать это прекрасно, но я не знаю, сможет ли Ruby. Драгоценный камень css_parser может быть отправной точкой, но я не знаю, может ли он обрабатывать встроенные стили…

И, конечно, встроенные стили, подобные этим, являются злом, отчасти потому, что их трудно нормализовать. Замените таблицей стилей как можно скорее, если это ваша собственная разметка.

Комментарии:

1. Я согласен, что замена таблицей стилей — лучшая идея. В этом случае Nokogiri может быть полезен при извлечении определенных в данный момент стилей и для перезаписи файла с целью удаления style параметра из тегов.

2. Правильно. Или, скорее всего, не Nokogiri, а любой другой анализатор CSS, который у вас есть.

3. На самом деле … если это одноразовое решение (или, по крайней мере, если его не нужно интегрировать в ваше приложение Ruby), вам, возможно, было бы лучше написать это на JavaScript или CoffeeScript (или HotRuby!) и запустить в браузере, чтобы у вас был доступ к getComputedStyle .

4. Идея состоит в том, чтобы избежать безголового браузера. HTML генерируется редактором WYSIWYG, над которым у нас нет контроля.

5. Понятно, но в данном случае браузерный движок, вероятно, является лучшим решением из-за вашей потребности в синтаксическом анализе CSS. Хм. И, если уж на то пошло, каков ваш вариант использования, когда у вас нет контроля над HTML, но вам нужно его нормализовать?

Ответ №2:

Нет, у Nokogiri нет таких возможностей для выполнения этого. Вы хотите, чтобы эквивалент JavaScript getComputedStyle() был реализован в Ruby, для чего потребовалась бы библиотека Ruby, которая знает, как анализировать HTML и CSS и применять правила CSS к HTML-документу.

Редактировать: вы могли бы попробовать использовать JRuby вместе с Celerity для безголового веб-браузера.

Ответ №3:

Перепробовав множество разных вещей, я закончил писать свое собственное решение с нуля.

Для дальнейшего использования, вот как я это сделал:

  • используйте Nokogiri doc.traverse для обхода документа
  • каждый раз, когда я сталкиваюсь с текстовым узлом, я делаю что-то вроде parents = []; parent = node.parent; while parent do parents << parent; parent = parent.parent; end; result << {:text => node.text, :parents => parents}
  • наконец, для каждого фрагмента текста в моем результирующем массиве я циклически перебираю родительские элементы и вручную анализирую каждый узел, устанавливая стиль один за другим, например, font размер шрифта:

         css = node[:style]
        if not style[:font_size] # style is a hash applied to each text chunk, the first encountered parent that define it wins
            if node.name == 'font' and node[:size]
                style[:font_size] = node[:size].to_i * 5
            elsif css =~ /font-size:[^;d]*(d*)/
                style[:font_size] = $1.to_i
            elsif css =~ /font:[^;d]*(d*)/
                style[:font_size] = $1.to_i
            end
        end
      

На самом деле было не сложно справиться со всеми случаями браузера, просто требовался системный подход. Окончательная реализация размера шрифта примерно в 5 раз длиннее (для обработки единиц измерения …). К сожалению, я не могу опубликовать полный исходный код. Но я надеюсь, что это ответит на вопрос для тех, кто этим занимается.