Sha256: 942ac812337c11fd6e852284e1ff5b30ea10a4b40d4db44e06cbd91af849ec85

Contents?: true

Size: 1.21 KB

Versions: 3

Compression:

Stored size: 1.21 KB

Contents

module XPathMatchers
  extend RSpec::Matchers::DSL
  include RSpecXML::XMLMatchers

  EXPR_PREFIX = '//'
  LOCAL_NAME_EXPR = "*[local-name()='%s']"
  ATTRIBUTE_SEPARATORS = ['|', '&', 'and', 'or']

  matcher :exist_xpath do |xpath|
    match do |xml|
      xml.should have_xpath(ignore_namespaces(xpath))
    end
    description do
      "xpath #{xpath} exist"
    end

    failure_message_for_should do |actual|
      "expected xpath #{expected} to exist in #{actual}"
    end

    # TODO: Make it work with attributes
    # Typical cases are:
    #
    # //person[@id='abc123']/@*[name()='weight' or name()='haircolor']
    # //person[@id='abc123']/(@haircolor|@weight)`
    # [@id='abc123']
    # @*[name()='weight' or name()='haircolor']
    #
    # This should work, try it:
    #
    # //*[local-name()='a'][*[local-name()='aCode']='aaa']

    # takes smth like //w:p/w:r and
    # returns //*[local-name()='p']/*[local-name()='r]
    def ignore_namespaces(xpath)
      expressions = xpath.sub(EXPR_PREFIX, '').
        split('/').map { |expr| to_local_name(expr) }.join('/')
      EXPR_PREFIX + expressions
    end

    def to_local_name(expr)
      element = expr.split(':').last
      LOCAL_NAME_EXPR % element
    end
  end
end

Version data entries

3 entries across 3 versions & 2 rubygems

Version Path
docxtor2-0.0.9 spec/docxtor2/support/matchers/xpath_matchers.rb
docxtor-0.1.1 spec/docxtor/support/matchers/xpath_matchers.rb
docxtor2-0.1.0 spec/docxtor2/support/matchers/xpath_matchers.rb