class Fluent::Plugin::XmlParser

Constants

TRUTHY_VALUES

Public Instance Methods

configure(config) click to toggle source
Calls superclass method
# File lib/fluent/plugin/parser_xml.rb, line 29
def configure(config)
  super

  # Create the time parser
  @time_parser = Fluent::TimeParser.new(@time_format)
end
convert(v, t) click to toggle source

This function converts the value v into the type t based on: github.com/fluent/fluentd/blob/5844f7209fec154a4e6807eb1bee6989d3f3297f/lib/fluent/plugin/parser.rb#L229.

# File lib/fluent/plugin/parser_xml.rb, line 75
def convert(v, t)
  case t
  when 'bool'
    return TRUTHY_VALUES.include?(v.to_s.downcase)
  when 'float'
    return v.to_f
  when 'integer'
    return v.to_i
  when 'string'
    return v.to_s
  else
    return v
  end
end
deep_each_pair(hash, parents = []) { |k, v, parents| ... } click to toggle source
# File lib/fluent/plugin/parser_xml.rb, line 100
def deep_each_pair(hash, parents = [])
  hash.each_pair do |k, v|
    if v.is_a?(Hash)
      parents << k

      deep_each_pair(v, parents) { |k, v, parents| yield(k, v, parents) }

      parents.pop
    elsif v.is_a?(Array) && v.size > 2
      attribute = v.last
      elements = v[0..-1]

      elements.each { |e| yield(k, [e, attribute], parents) }
    elsif v.is_a?(Array)
      yield(k, v, parents)
    end
  end
end
get_field_value(doc, xpath) click to toggle source
# File lib/fluent/plugin/parser_xml.rb, line 90
def get_field_value(doc, xpath)
  element = doc.elements[xpath[0]]
  return if element.nil?

  attribute = element.attributes[xpath[1]]
  return if attribute.nil?

  return attribute
end
parse(text) { |time, record| ... } click to toggle source
# File lib/fluent/plugin/parser_xml.rb, line 36
def parse(text)
  begin
    # Open the XML document
    doc = REXML::Document.new(text)

    # Create an empty record which assigns default values for missing
    # keys. See: https://stackoverflow.com/a/3339168.
    record = Hash.new { |h, k| h[k] = {} }

    # Create the time value
    time = @time_parser.parse(get_field_value(doc, @time_xpath))

    # Recursively parse XPath to handle nested structures
    deep_each_pair(@xpath) do |k, xpath, parents|
      # Retrieve the field value from the XPath
      value = get_field_value(doc, xpath)

      # Ignore the field if it has no value
      unless value.nil?
        # Convert the value
        type = @xpath_types.dig(*parents, k) unless @xpath_types.nil?
        value = convert(value, type) unless type.nil?

        # Save the field to the appropriate index (record["a"]["b"]["c"]).
        # See: https://stackoverflow.com/a/14294789.
        parents.inject(record, :[])[k] = value unless value.nil?
      end
    end

    yield(time, record)
  rescue StandardError
    yield(nil, nil)
  end
end