问题与Nokogiri :: Slop获取节点属性?

时间:2014-01-23 13:40:12

标签: ruby nokogiri

我有一个包含以下内容的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>

我想从中获取一些数据。我使用Nokogiri::Slop

使用此代码
@test = Nokogiri::Slop(File.open("./file.svg"))

和这个ERb:

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

这样可行,但我现在的问题是如何让孩子font-family,font-size,fill,stroke

我试过这段代码

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

但它不起作用。

2 个答案:

答案 0 :(得分: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属性,然后在;上拆分它的值,然后,对于每个生成的数组,它将它们拆分为:并删除前导/尾随空格。

最后,它将生成的数组数组转换为哈希值并返回它。

答案 1 :(得分:0)

您的XML中的font-familyfont-sizefillstroke项是不是 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*/)}]