module MicroMicro module Parsers class ValueClassPatternParser # @see https://microformats.org/wiki/value-class-pattern#Basic_Parsing # @see https://microformats.org/wiki/value-class-pattern#Date_and_time_values HTML_ATTRIBUTES_MAP = { 'alt' => %w[area img], 'value' => %w[data], 'title' => %w[abbr], 'datetime' => %w[del ins time] }.freeze # @param context [Nokogiri::XML::Element] # @param separator [String] def initialize(node, separator = '') @node = node @separator = separator end # @return [String, nil] def value @value ||= values.join(separator).strip if values.any? end # @return [Array] def values @values ||= value_nodes.map { |value_node| self.class.value_from(value_node) }.select(&:present?) end # @param context [Nokogiri::XML::NodeSet, Nokogiri::XML::Element] # @param node_set [Nokogiri::XML::NodeSet] # @return [Nokogiri::XML::NodeSet] def self.nodes_from(context, node_set = Nokogiri::XML::NodeSet.new(context.document, [])) context.each { |node| nodes_from(node, node_set) } if context.is_a?(Nokogiri::XML::NodeSet) if context.is_a?(Nokogiri::XML::Element) && !Document.ignore_node?(context) if value_class_node?(context) || value_title_node?(context) node_set << context else nodes_from(context.element_children, node_set) end end node_set end # @param node [Nokogiri::XML::Element] # @return [Boolean] def self.value_class_node?(node) node.classes.include?('value') end # @param node [Nokogiri::XML::Element] # @return [String, nil] def self.value_from(node) return node['title'] if value_title_node?(node) HTML_ATTRIBUTES_MAP.each do |attribute, names| return node[attribute] if names.include?(node.name) && node[attribute] end node.text end # @param node [Nokogiri::XML::Element] # @return [Boolean] def self.value_title_node?(node) node.classes.include?('value-title') end private attr_reader :node, :separator # @return [Nokogiri::XML::NodeSet] def value_nodes @value_nodes ||= self.class.nodes_from(node) end end end end