-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathx_load.rb
executable file
·189 lines (160 loc) · 4.57 KB
/
x_load.rb
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#!/usr/bin/ruby
$KCODE='u'
require 'pp'
require 'optparse'
require 'ostruct'
require 'iconv'
$:.unshift(File.join(File.dirname(__FILE__), "lib"))
require "xml_util"
include XMLUtil::XML
def is_jruby?
defined?(JRUBY_VERSION)
end
options = OpenStruct.new
options.text = false
options.xpath = nil
options.code = nil
options.out = nil
options.fs = "\t"
options.root = "results"
options.pretty = false
options.encode = "utf-8"
OptionParser.new { |opt|
opt.banner = "usage: #{File.basename($0)} [options] [in.xml...]"
opt.separator " o input the XML document"
opt.separator " o filter the document by XPath expression"
opt.separator " o replace filtered nodes to any value which returned by the codeblock"
opt.separator " o output the result the XML document"
opt.separator " o if text-mode, it is output by TSV style."
opt.separator " "
opt.separator "Options:"
opt.on("-x", "--xpath=XPath", "XPath expression. ex. //element[@attr='yy']") do |v|
options.xpath = v
end
opt.on("-o", "--out=FILENAME", "filename to output") do |v|
options.out = v
end
opt.on("-e", "--encoding=ENCODING-NAME", "default: #{options.encode}") do |v|
options.encode = v
end
opt.on("--root=TAG", "tagname of root element for output") do |v|
options.root = v
end
opt.on("--pretty", "pretty print for XML") do |v|
options.pretty = true
end
opt.separator " "
opt.separator "with --xpath option:"
opt.on("--code=BLOCK", "code block. ex. {|n| n['fullname']}") do |v|
options.code = v
end
opt.on("-t", "--text", "output result by text each line") do |v|
options.text = true
end
opt.separator " "
opt.separator "with --text option:"
opt.on("--fs=SEPARATOR", "field separator for text mode") do |v|
options.fs = v
end
begin
opt.parse!(ARGV)
if options.code
begin
p = eval("Proc.new #{options.code}")
rescue SyntaxError => ex
raise ArgumentError, "*** invalid code block:\n#{ex.message}"
end
if !p.kind_of?(Proc)
raise ArgumentError, "*** specify code block"
end
options.code = p
end
if options.code && !options.xpath
raise ArgumentError, "*** specify both --code and --xpath"
end
rescue ArgumentError, OptionParser::ParseError => ex
STDERR.puts opt.to_s
STDERR.puts ""
STDERR.puts "#{ex.message}"
exit 1
end
}
if options.out
if is_jruby?
st = java.io.PrintStream.new(options.out)
else
st = File.open(options.out, "w")
end
else
if is_jruby?
st = java.lang.System.out
else
st = STDOUT
end
end
if ARGV.size == 0
ARGV.push(nil)
end
out_doc = XMLUtil::XML::new_document
out_doc.root = el_root = out_doc.create_element(options.root)
iconv = Iconv.new(options.encode, "utf-8")
ARGV.each {|fn_in|
doc = XMLUtil::XML::build_document(fn_in)
if !options.xpath
# XPath指定がない場合
# 読み込んだdocを出力する
if ARGV.size == 1
out_doc = doc
else
# が、複数のdocが指定されている場合、一個のdocにまとめないと
# 出力XMLがvalidでなくなるので一個にまとめる
el_root << out_doc.import_node(doc.root, true)
end
else
# XPath指定がある場合、XPath式でフィルタ
doc.find(options.xpath).to_a.each_with_index {|node,idx|
if options.code
# コードブロックが指定されている場合、フィルタされたノードを引数に
# コードブロックを実行し結果を得る
if options.code.arity == 1
result = options.code.call(node)
else
result = options.code.call(node,idx)
end
else
# コードブロックがない場合はフィルタされたノードを結果として扱う
result = node
end
# 結果、nilなら無視
if !result
next
end
result = [result].flatten
if options.text
# テキストモードの場合、TSVスタイルで出力
# TODO: jrubyはこれだとだめ
st.print iconv.iconv("#{result.join(options.fs)}\n")
else
# XML出力の場合は、結果それぞれに対して・・・
result.each { |item|
if item.respond_to?(:element?) && item.element?
# XML要素なら、複製して出力XMLのルートに追加する
el_root << out_doc.import_node(item, true)
else
# 結果を文字列化したものを1要素にして、出力XMLのルートに追加
el_result = out_doc.create_element("result")
el_result << item.to_s
el_root << el_result
end
}
end
}
end
}
# 出力XMLを書き出す
# テキストモードの場合、都度書き出しているので出力不要
if !options.text
XMLUtil::XML::write_document(out_doc, st, options.encode, false, options.pretty)
end
exit 0
# vi: ts=2 sw=2