Skip to content

Instantly share code, notes, and snippets.

@doertedev
Created June 20, 2017 19:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save doertedev/b1340b0e7fa754dcef79365f6473ca30 to your computer and use it in GitHub Desktop.
Save doertedev/b1340b0e7fa754dcef79365f6473ca30 to your computer and use it in GitHub Desktop.
XML / CSS resource selector for Inspec
require 'nokogiri'
require 'utils/simpleconfig'
class XML_CSS < Inspec.resource(1)
name 'xml_css'
desc 'XML for Chef Inspec using Nokogiri\'s CSS selector feature'
example '
Given this set of XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<this>
<but>
<some>XML</some>
</but>
<but>
<some>More</some>
</but>
</this>
Run this
describe xml_css "/tmp/file.xml", "but+but" do
its("inner_text") { should eq "More" }
end
The CSS is being put as a second variable in the describe block so we
can blindly call the its-descriptor as a Nokogiri::XML::NodeSet-method.
This way, not only to_s, to_a but also empty? and length are working as
expected.
'
def initialize(filename, xpath)
@file = inspec.file(filename)
@file_content = @file.content
# check if file is available
if !@file.file?
skip_resource "Can't find file \"#{@path}\""
return @params = {}
end
# check if file is readable
if @file_content.nil? && !@file.empty?
skip_resource "Can't read file \"#{@path}\""
return @params = {}
end
begin
doc = Nokogiri::XML(@file_content) do |config|
config.options = Nokogiri::XML::ParseOptions::NOERROR
end
doc.remove_namespaces!
rescue
unless doc.is_a?(Nokogiri::XML::Document)
skip_resource "Error parsing #{@file}'s XML!"
end
end
@object = doc.root.css(xpath)
@type = @object.class
skip_resource "#{@file}'s XML doesn't yielded nil at css-path #{xpath}" if @type.nil?
end
def method_missing(*keys)
skip_resource 'Please specify a method to call!' unless keys[0].is_a? String
skip_resource 'Unknown method called!' unless @object.methods.include? keys[0]
return @object.send keys[0].to_sym
end
end
@doertedev
Copy link
Author

doertedev commented Jun 21, 2017

Another form (for parsing once then re-querying all over the place):

require 'nokogiri'
require 'utils/simpleconfig'

class XML_CSS < Inspec.resource(1)
  name 'xml_css'

  desc 'XML for Chef Inspec using Nokogiri\'s CSS selector feature'

  example '
    Given this set of XML:

        <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
        <this>
          <but>
            <some>XML</some>
          </but>
          <but>
            <some>More</some>
          </but>
        </this>

      Run this

      describe xml_css "/tmp/file.xml" do
        its("but + but !! inner_text") { should eq "More" }
      end

    The CSS is being put as a second variable in the describe block so we
    can blindly call the its-descriptor as a Nokogiri::XML::NodeSet-method.
    This way, not only to_s, to_a but also empty? and length are working as
    expected.
  '

  def initialize(filename)
    @file = inspec.file(filename)
    @file_content = @file.content

    # check if file is available
    if !@file.file?
      skip_resource "Can't find file \"#{@path}\""
      return @params = {}
    end

    # check if file is readable
    if @file_content.nil? && !@file.empty?
      skip_resource "Can't read file \"#{@path}\""
      return @params = {}
    end
    begin
      doc = Nokogiri::XML(@file_content) do |config|
        config.options = Nokogiri::XML::ParseOptions::NOERROR
      end
      doc.remove_namespaces!
    rescue
      unless doc.is_a?(Nokogiri::XML::Document)
        skip_resource "Error parsing #{@file}'s XML!"
      end
    end
    @object = doc
    @type = @object.class
    skip_resource "#{@file}'s XML doesn't yielded nil at css-path #{xpath}" if @type.nil?
  end

  def method_missing(selector)
    keys = selector.to_s.split(' !! ')
    @object.root.css(keys[0]).send(keys[1].to_sym)
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment