2014-01-23 3 views
1

У меня есть файл SVG, содержащий:Проблема с Nokogiri :: Slop получает атрибуты узла?

<text x="10" y="20" 
    style="font-family: Helvetica; 
     font-size : 24; 
     fill  : #ff0000; 
     stroke  : #000000;">SVG text styling</text> 
<text x="85" y="150" 
    style="font-family: Helvetica; 
     font-size : 24; 
     fill  : #ff0000; 
     stroke  : #000000;">This is the second piece of text</text> 
<text x="45" y="250" 
    style="font-family: Helvetica; 
     font-size : 24; 
     fill  : #ff0000; 
     stroke  : #000000;">This is the third piece of text</text> 

     <text x="45" y="250" 
    style="font-family: Helvetica; 
     font-size : 24; 
     fill  : #ff0000; 
     stroke  : #000000;">test text</text> 
     <text x="45" y="250" 
    style="font-family: Helvetica; 
     font-size : 24; 
     fill  : #ff0000; 
     stroke  : #000000;">data data</text> 
     <text x="45" y="250" 
    style="font-family: Helvetica; 
     font-size : 24; 
     fill  : #ff0000; 
     stroke  : #000000;">txt txt txt</text> 

Я хочу, чтобы получить некоторые данные из него. Я использую этот код с помощью Nokogiri::Slop:

@test = Nokogiri::Slop(File.open("./file.svg")) 

и этого Еврорадио:

<% @test.xpath('//text').map do |i|%> 
<%=i%> 
<% end %> 

Это работает, но моя проблема в том, как получить ребенок font-family,font-size,fill,stroke

Я попробовал этот код

<%=i.("[@stroke]").text.content %> 

но не работает.

+1

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

ответ

2

Чтобы использовать данные в ERB, вы должны сначала преобразовать его в нечто более дружелюбное в своем контроллере. Этот код приведет в массив хэшей вы можете лупить друг от друга с точки зрения:

require 'nokogiri' 

doc = Nokogiri::XML(<<EOT) 
<svg> 
<text x="10" y="20" 
    style="font-family: Helvetica; 
     font-size : 24; 
     fill  : #ff0000; 
     stroke  : #000000;">SVG text styling</text> 
<text x="85" y="150" 
    style="font-family: Helvetica; 
     font-size : 24; 
     fill  : #ff0000; 
     stroke  : #000000;">This is the second piece of text</text> 
<text x="45" y="250" 
    style="font-family: Helvetica; 
     font-size : 24; 
     fill  : #ff0000; 
     stroke  : #000000;">This is the third piece of text</text> 

     <text x="45" y="250" 
    style="font-family: Helvetica; 
     font-size : 24; 
     fill  : #ff0000; 
     stroke  : #000000;">test text</text> 
     <text x="45" y="250" 
    style="font-family: Helvetica; 
     font-size : 24; 
     fill  : #ff0000; 
     stroke  : #000000;">data data</text> 
     <text x="45" y="250" 
    style="font-family: Helvetica; 
     font-size : 24; 
     fill  : #ff0000; 
     stroke  : #000000;">txt txt txt</text> 
</svg> 
EOT 

На данный момент Nokogiri имеет документ XML.

Вот все, что нужно, чтобы ходить <text> узлы:

text_styles = doc.search('text').map { |text| 
    Hash[text['style'].split(';').map{ |attr| attr.split(':').map(&:strip) }] 
} 

Который при запуске, будет возвращать text_styles содержащий:

text_styles 
# => [{"font-family"=>"Helvetica", 
#  "font-size"=>"24", 
#  "fill"=>"#ff0000", 
#  "stroke"=>"#000000"}, 
#  {"font-family"=>"Helvetica", 
#  "font-size"=>"24", 
#  "fill"=>"#ff0000", 
#  "stroke"=>"#000000"}, 
#  {"font-family"=>"Helvetica", 
#  "font-size"=>"24", 
#  "fill"=>"#ff0000", 
#  "stroke"=>"#000000"}, 
#  {"font-family"=>"Helvetica", 
#  "font-size"=>"24", 
#  "fill"=>"#ff0000", 
#  "stroke"=>"#000000"}, 
#  {"font-family"=>"Helvetica", 
#  "font-size"=>"24", 
#  "fill"=>"#ff0000", 
#  "stroke"=>"#000000"}, 
#  {"font-family"=>"Helvetica", 
#  "font-size"=>"24", 
#  "fill"=>"#ff0000", 
#  "stroke"=>"#000000"}] 

код считывает данные и анализирует его как XML. Затем, используя search, он ищет селектор CSS text. Почему CSS? Его легче читать.

После того, как <text> узел найден, он извлекает атрибут style от узла, а затем делит его значение на ;, то для каждого из полученных массивов, это разбивает их на : и полосы ведущий/конечные пробелы.

Наконец, он преобразует результирующий массив массивов в хэш и возвращает его.

0

В font-family, font-size, fill и stroke элементов в вашем XML являются не атрибутов XML, так что вы не можете получить их (непосредственно) с Nokogiri. Они являются частью строки, которая является значением атрибута style. Вам нужно будет получить эту строку, а затем проанализировать ее как-нибудь в Ruby.

Вот пример, показывающий, как получить значение этих четырех вещей для первого text элемента:

# first get the complete string: 
styles = @test.at_xpath("//text/@style").value 

# next split the string into key values pairs on ;, then each pair 
# into spearate strings on :, and create a hash with the result 
style_hash = Hash[style1.split(/\s*;\s*/).map { |s| s.split(/\s*:\s*/)}] 
+0

Я знаю концепцию сейчас, и она хорошо работала со мной , но как я могу получить длину Xpath – Astm

+0

@AndroidMan Я не понимаю, что вы имеете в виду. Вы имеете в виду, как получить все узлы 'text/@ style '?Обратите внимание, что я использовал 'at_path', чтобы упростить пример, который возвращает только первый узел - используйте' xpath', чтобы получить все. Взгляните на [ответ Оловянного Человека] (http://stackoverflow.com/a/21310518/214790), он включает аналогичный пример, который извлекает все узлы. – matt

Смежные вопросы