从标记中提取HTML5数据属性

时间:2012-03-17 22:41:46

标签: ruby xml html5 nokogiri

我想从标记中提取所有HTML5数据属性,就像this jQuery plugin

一样

例如,给定:

<span data-age="50" data-location="London" class="highlight">Joe Bloggs</span>

我希望得到一个哈希:

{ 'data-age' => '50', 'data-location' => 'London' }

我最初希望使用通配符作为我的CSS选择器的一部分,例如

Nokogiri(html).css('span[@data-*]').size

但似乎不支持。

4 个答案:

答案 0 :(得分:6)

选项1:抓取所有数据元素

如果你需要的只是列出所有页面的数据元素,这里有一个单行:

Hash[doc.xpath("//span/@*[starts-with(name(), 'data-')]").map{|e| [e.name,e.value]}]

输出:

{"data-age"=>"50", "data-location"=>"London"}

选项2:按标签分组结果

如果您想按标记对结果进行分组(可能需要对每个标记进行额外处理),您可以执行以下操作:

tags = []
datasets = "@*[starts-with(name(), 'data-')]"

#If you want any element, replace "span" with "*"
doc.xpath("//span[#{datasets}]").each do |tag|
    tags << Hash[tag.xpath(datasets).map{|a| [a.name,a.value]}]
end

然后tags是一个包含按标记分组的键值哈希对的数组。

选项3:jQuery数据集插件

之类的行为

如果您更喜欢类似插件的方法,以下内容将在每个Nokogiri节点上为您提供dataset方法。

module Nokogiri
  module XML
    class Node
      def dataset
        Hash[self.xpath("@*[starts-with(name(), 'data-')]").map{|a| [a.name,a.value]}]
      end
    end
  end
end

然后您可以找到单个元素的数据集:

doc.at_css("span").dataset

或获取一组元素的数据集:

doc.css("span").map(&:dataset)

示例:

以下是上述dataset方法的行为。给出HTML中的以下行:

<span data-age="50" data-location="London" class="highlight">Joe Bloggs</span>
<span data-age="40" data-location="Oxford" class="highlight">Jim Foggs</span>

输出结果为:

[
 {"data-location"=>"London", "data-age"=>"50"},
 {"data-location"=>"Oxford", "data-age"=>"40"}
]

答案 1 :(得分:3)

你可以用一点xpath做到这一点:

doc = Nokogiri.HTML(html)
data_attrs = doc.xpath "//span/@*[starts-with(name(), 'data-')]"

这将获得以{data-'开头的span元素的所有属性。 (您可能希望分两步完成此操作,首先获取您感兴趣的所有元素,然后依次从每个元素中提取数据属性。

继续示例(使用问题中的span):

hash = data_attrs.each_with_object({}) do |n, hsh|
  hsh[n.name] = n.value
end

puts hash

产生

{"data-age"=>"50", "data-location"=>"London"}

答案 2 :(得分:2)

尝试循环浏览element.attributes,同时忽略任何不以data-开头的属性。

答案 3 :(得分:2)

Node#css文档提到了一种附加自定义伪选择器的方法。对于选择属性以“data - ”开头的节点,可能如下所示:

Nokogiri(html).css('span:regex_attrs("^data-.*")', Class.new {
  def regex_attrs node_set, regex
    node_set.find_all { |node| node.attributes.keys.any? {|k| k =~ /#{regex}/ } }
  end
}.new)