REXML で SAX風に id と class を抜き出してみた

こんな風に使います。

ruby class_id_picker.rb FILENAME

当然、HTML は処理できなくて、XHTML でないとダメです。

使い道は、とりあえず付けてある名前を推敲するのに使えるかなーくらい。あとは id が unique かどうかとか? 普通はこんなの要らない気がする。

attrs をチェックする際にわざわざ

//i

で引っ掛けているのは REXML でのパース時に大文字や小文字への正規化は行われないためです。

#! /usr/bin/env ruby

require 'rexml/document'
require 'rexml/streamlistener'

class ClassIdPicker
  def initialize
    @ids     = []
    @classes = []
  end
  attr_reader( :ids, :classes )

  def self.parse( io )
    obj = self.new
    REXML::Document.parse_stream( io, Listener.new( obj.ids, obj.classes ) )
    return obj
  end

  def attrs
    return instance_variables.map { |e|
      e.sub( /\A@/, '' )
    }
  end

  def browse
    puts "=== Classes ==="
    puts @classes.sort.uniq.join( "\n" )
    puts "=== Ids ==="
    puts @ids.sort.uniq.join( "\n" )
  end

  class Listener
    include REXML::StreamListener

    def initialize( ids, classes )
      @ids     = ids
      @classes = classes
    end
    attr_reader( :ids, :classes )

    def tag_start( name, attrs )
      attrs.each_pair { |name, val|
        case name
        when /\Aid\z/i
          @ids.push( val )
        when /\Aclass\z/i
          @classes.push( val )
        end
      }
    end

  end
end

if ( __FILE__ == $0 )
  app = ClassIdPicker.parse( ARGF.file )

  # 数を数えながら表示してみる
  app.attrs.each { |attr|
    p attr
    attr_list = app.send( attr ).dup
    attr_list.sort.uniq.each { |name|
      puts "#{name}\t#{attr_list.grep( name ).size}"
    }
  }
end

参考

More