image

  • フォト Amazonギフト券
    ※この時計の時刻は、閲覧しているパソコンのものであり、必ずしも正確な時間とは限りません

検索

最近のトラックバック

無料ブログはココログ

« 2009年1月24日 | トップページ | 2009年2月2日 »

2009年1月26日

2009-01-26

XBRL ファイルの リンクをたどる (その2)

前に XBRL インスタンスデータから ファイル import 関係ツリーを作ることをした。
今度は、ファイル自体をローカルファイルに保存し、2回目からは ネット経由しないでデータアクセスするようなプログラムを作ってみた。

ソースコードは後で示すとして、実行例をまず 示そう。

$ ruby filescan.rb
"3740c8e0eedfad9f135dd69f9296f709"
"readed  100 files. 17439149 bytes."
  3.910000   2.450000   6.360000 (149.429177)

$ ruby filescan.rb
"3740c8e0eedfad9f135dd69f9296f709"
"readed  100 files. 17439149 bytes."
  1.190000   0.060000   1.250000 (  1.255830)

これは microsoft データを読んでみたものだ。
読み込みデータ全体の MD5 値、ファイル数, byte 総数と、benchmark 値を表示している。
2 回目の実行は、1.2 秒だ!

ソースを示そう。(150 行ほどある)

$ cat filescan.rb

# 2009-01-25 katoy
#  Scaw and cache all importd file for XBRL-instnce data.

require 'rubygems'
require 'xml/libxml'
require 'open-uri'
require 'pathname'
require 'pp'
require 'benchmark'
require 'md5'
require 'set'

class FileCache
  CACHE = './cache'   # Cache Folder. 末尾に / は付けない。

  attr_reader :md5
  attr_reader :count
  attr_reader :size
  attr_reader :readed

  def initialize
    @md5 = MD5.new
    @count = 0
    @size = 0
    @readed = Set.new
  end

  def visit(path, dir = '')
    from_path = Utils::normalize_path(path, dir)
    return if @readed.include?(from_path)

    parent = Utils::parent(from_path)
    data = ""

    if from_path.index('http:/') != 0
      cache_file = from_path
      open(cache_file) { |src| data = src.read }
    else
      # ネット上ファイルの場合
      cache_file = CACHE + from_path.gsub('http:/', '/http')   
      # キャッシュから読み込む
      if File.exists?(cache_file)
        open(cache_file) { |src| data = src.read }
      else
        # 読み込んでから、キャッシュにも保存する
        Utils::multi_mkdir(File::dirname(cache_file))  if !File.exists?(File::dirname(cache_file))
        open(from_path) { |src|
          data = src.read
          open(cache_file, "w") { |dest| dest.write(data) }
        }
      end
    end

    @readed << from_path
    @md5.update(data)
    @count += 1
    @size += data.length

    reader = nil

    begin
      reader = XML::Reader.new(data)
      while 1 == reader.read
        href = nil
        name = "#{reader.namespace_uri}:#{reader.local_name}"
        case name
        when 'http://www.w3.org/2001/XMLSchema:import'
          href = reader['schemaLocation']
        when 'http://www.xbrl.org/2003/linkbase:schemaRef'
          href = reader['xlink:href']
        when 'http://www.xbrl.org/2003/linkbase:linkbaseRef'
          href = reader['xlink:href']
        end

        if href != nil
          to_path = Utils::normalize_path(href, parent)
          visit(to_path, parent)
        end
      end
    rescue
      puts "---- error reading #{from_path} (#{cache_file})"
      exit 1
    ensure
      reader.close if reader != nil
      reader = nil
    end
  end
end

class Utils
  def self.cleanpath(path)
    Pathname.new(path).cleanpath
  end

  def self.parent(full_path)
    p = full_path.rindex('/') - 1
    full_path[0..p]
  end

  def self.multi_mkdir(mkpath)
    path = ''
    mkpath.split('/').each do |f|
      path.concat(f)
      Dir.mkdir(path) unless path == '' || File.exist?(path)
      path.concat('/')
    end
  end

  def self.normalize_path(path, dir='')
    if path.index('http://') == 0
      uri = URI.parse(path)
      full_path = "#{uri.scheme}://#{uri.host}#{Utils::cleanpath(uri.path.to_s)}"
    elsif dir.index('http://') == 0
      uri = URI.parse("#{dir}/#{path}")
      full_path = "#{uri.scheme}://#{uri.host}#{Utils::cleanpath(uri.path.to_s)}"
    else
      path = path[5.. path.length] if path.index('file:') == 0
      dir = File::expand_path('.') if dir == ''
      full_path = Utils::cleanpath(File::expand_path(path, dir))
    end

    full_path.to_s
  end
end

# See http://www.sec.gov
# SEC - adobe
# pat = "http://www.sec.gov/Archives/edgar/data/796343/000079634308000007/adbe-20080916.xml"
# SEC - microsoft
pat = "http://www.sec.gov/Archives/edgar/data/789019/000119312508215214/msft-20080930.xml"

# pat = "file:/Users/youichikato/work/www/xbrl.org/XBRL-CONF/Common/instance/397-00-ConsistentInstance-valid.xbrl"
# pat = "/Users/youichikato/work/www/xbrl.org/XBRL-CONF/**/*.xbrl"
# pat = "/Users/youichikato/NetBeansProjects/ruby-xbrl/Edinet/sample/**/*.xbrl"
# pat = "data/X99001-000/jpfr-asr-X99001-000-2008-03-31-01-2008-06-27.xbrl"
# pat = ARGV[0]

puts Benchmark.measure {
  fscan = FileCache.new

  if pat == nil
    puts "--No specified XBRL instance."
    exit 1
  elsif pat.index('http:') == 0
    full_path = Utils::normalize_path(pat)
    fscan.visit(full_path)
  else
    Dir.glob(pat).each do |f|
      full_path = Utils::normalize_path(f)
      fscan.visit(full_path)
    end
  end

  pp fscan.md5.hexdigest
  pp "readed  #{fscan.count} files. #{fscan.size} bytes."
}

ファイル読み込みが、この程度の処理時間で済むなら、どの言語で処理しても人間にとっては大差は無いかもしれない。

« 2009年1月24日 | トップページ | 2009年2月2日 »

mokuji

2013年12月
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        

google

  • twitter
  • __
  • _
    Googleボットチェッカー

合わせて読む

  • 合わせて読む
    フィードメーター - katoy: cocolog あわせて読みたい

リンク