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."
}
ファイル読み込みが、この程度の処理時間で済むなら、どの言語で処理しても人間にとっては大差は無いかもしれない。
最近のコメント