/
jsonld
executable file
·201 lines (189 loc) · 8.91 KB
/
jsonld
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
189
190
191
192
193
194
195
196
197
198
199
200
201
#!/usr/bin/env ruby
require 'rubygems'
begin
require 'linkeddata'
rescue LoadError
end
$:.unshift(File.expand_path("../../lib", __FILE__))
require 'json/ld'
require 'getoptlong'
require 'open-uri'
require 'logger'
def run(input, options, parser_options)
reader_class = RDF::Reader.for(options[:input_format].to_sym)
raise "Reader not found for #{options[:input_format]}" unless reader_class
# Override default (or specified) output format when framing
options[:format] = :jsonld if options[:compact] || options[:frame]
# If input format is not JSON-LD, transform input to JSON-LD first
reader = if options[:input_format] != :jsonld
reader_class.new(input, parser_options)
end
start = Time.new
if options[:expand]
parser_options = parser_options.merge(expandContext: parser_options.delete(:context)) if parser_options.key?(:context)
input = JSON::LD::API.fromRdf(reader) if reader
output = JSON::LD::API.expand(input, **parser_options)
secs = Time.new - start
options[:output].puts output.to_json(JSON::LD::JSON_STATE)
STDERR.puts "Expanded in #{secs} seconds." unless options[:quiet]
elsif options[:compact]
input = JSON::LD::API.fromRdf(reader) if reader
output = JSON::LD::API.compact(input, parser_options[:context], **parser_options)
secs = Time.new - start
options[:output].puts output.to_json(JSON::LD::JSON_STATE)
STDERR.puts "Compacted in #{secs} seconds." unless options[:quiet]
elsif options[:flatten]
input = JSON::LD::API.fromRdf(reader) if reader
output = JSON::LD::API.flatten(input, parser_options[:context], **parser_options)
secs = Time.new - start
options[:output].puts output.to_json(JSON::LD::JSON_STATE)
STDERR.puts "Flattened in #{secs} seconds." unless options[:quiet]
elsif options[:frame]
input = JSON::LD::API.fromRdf(reader) if reader
output = JSON::LD::API.frame(input, parser_options[:frame], **parser_options)
secs = Time.new - start
options[:output].puts output.to_json(JSON::LD::JSON_STATE)
STDERR.puts "Framed in #{secs} seconds." unless options[:quiet]
else
parser_options = parser_options.merge(expandContext: parser_options.delete(:context)) if parser_options.key?(:context)
parser_options[:standard_prefixes] = true
reader ||= JSON::LD::Reader.new(input, **parser_options)
num = 0
RDF::Writer.for(options[:output_format]).new(options[:output], **parser_options) do |w|
reader.each do |statement|
num += 1
w << statement
end
end
secs = Time.new - start
STDERR.puts "\nParsed #{num} statements in #{secs} seconds @ #{num/secs} statements/second." unless options[:quiet]
end
rescue
fname = case
when input.respond_to?(:path) then input.path
when input.respond_to?(:requested_url) && input.requested_url then input.requested_url
when input.respond_to?(:base_uri) then input.base_uri
else "-stdin-"
end
STDERR.puts("Error in #{fname}")
raise
end
logger = Logger.new(STDERR)
logger.level = Logger::WARN
logger.formatter = lambda {|severity, datetime, progname, msg| "#{severity}: #{msg}\n"}
parser_options = {
base: nil,
validate: false,
stream: false,
strict: false,
logger: logger,
}
options = {
output: STDOUT,
output_format: :jsonld,
input_format: :jsonld,
logger: logger,
}
input = nil
OPT_ARGS = [
["--debug", GetoptLong::NO_ARGUMENT, "Turn on verbose debugging"],
["--compact", GetoptLong::NO_ARGUMENT, "Compact document, using --context"],
["--compactArrays", GetoptLong::OPTIONAL_ARGUMENT, "Set compactArrays option"],
["--context", GetoptLong::REQUIRED_ARGUMENT,"Context to apply for expand, compact and converting from RDF"],
["--embed", GetoptLong::REQUIRED_ARGUMENT,"a flag specifying that objects should be directly embedded in the output, instead of being referred to by their IRI"],
["--evaluate","-e", GetoptLong::REQUIRED_ARGUMENT,"Evaluate argument as a JSON-LD document"],
["--expand", GetoptLong::NO_ARGUMENT, "Expand document, using an optional --context"],
["--expanded", GetoptLong::OPTIONAL_ARGUMENT, "Input is already expanded"],
["--explicit", GetoptLong::OPTIONAL_ARGUMENT, "a flag specifying that for properties to be included in the output, they must be explicitly declared in the framing context"],
["--flatten", GetoptLong::NO_ARGUMENT, "Flatten document, using an optional --context"],
["--format", GetoptLong::REQUIRED_ARGUMENT,"Specify output format when converting to RDF"],
["--frame", GetoptLong::REQUIRED_ARGUMENT,"Frame document, using the file or URL as a frame specification"],
["--input-format", GetoptLong::REQUIRED_ARGUMENT,"Format of the input document, when converting from RDF."],
["--omitDefault", GetoptLong::OPTIONAL_ARGUMENT,"a flag specifying that properties that are missing from the JSON-LD input should be omitted from the output"],
["--output", "-o", GetoptLong::REQUIRED_ARGUMENT,"Output to the specified file path"],
["--parse-only", GetoptLong::NO_ARGUMENT, "Parse the document for well-formedness only"],
["--processingMode",GetoptLong::REQUIRED_ARGUMENT,"Set processing mode, defaults to json-ld-1.1"],
["--quiet", GetoptLong::NO_ARGUMENT, "Supress most output other than progress indicators"],
["--rename_bnodes", GetoptLong::OPTIONAL_ARGUMENT,"Rename bnodes as part of expansion, or keep them the same"],
["--rdfstar", GetoptLong::NO_ARGUMENT, "Parse JSON-LD-star"],
["--requireAll", GetoptLong::OPTIONAL_ARGUMENT,"Rename bnodes as part of expansion, or keep them the same"],
["--stream", GetoptLong::NO_ARGUMENT, "Use Streaming reader/writer"],
["--unique_bnodes", GetoptLong::OPTIONAL_ARGUMENT,"Use unique bnode identifiers"],
["--uri", GetoptLong::REQUIRED_ARGUMENT,"URI to be used as the document base"],
["--validate", GetoptLong::NO_ARGUMENT, "Validate while processing"],
["--help", "-?", GetoptLong::NO_ARGUMENT, "This message"]
]
def usage
STDERR.puts %{Usage: #{$0} [options] file ...}
width = OPT_ARGS.map do |o|
l = o.first.length
l += o[1].length + 2 if o[1].is_a?(String)
l
end.max
OPT_ARGS.each do |o|
s = " %-*s " % [width, (o[1].is_a?(String) ? "#{o[0,2].join(', ')}" : o[0])]
s += o.last
STDERR.puts s
end
exit(1)
end
opts = GetoptLong.new(*OPT_ARGS.map {|o| o[0..-2]})
opts.each do |opt, arg|
case opt
when '--debug' then logger.level = Logger::DEBUG
when '--compact' then options[:compact] = true
when "--compactArrays" then parser_options[:compactArrays] = (arg || 'true') == 'true'
when '--context' then parser_options[:context] = RDF::URI(arg).absolute? ? arg : File.open(arg)
when '--evaluate' then input = arg
when '--expand' then options[:expand] = true
when "--expanded" then parser_options[:expanded] = (arg || 'true') == 'true'
when "--explicit" then parser_options[:compactArrays] = (arg || 'true') == 'true'
when '--format' then options[:output_format] = arg.to_sym
when '--flatten' then options[:flatten] = arg
when '--frame' then options[:frame] = parser_otpions[:frame] = RDF::URI(arg).absolute? ? arg : File.open(arg)
when '--input-format' then options[:input_format] = arg.to_sym
when "--omitDefault" then parser_options[:omitDefault] = (arg || 'true') == 'true'
when '--output' then options[:output] = File.open(arg, "w")
when '--parse-only' then options[:parse_only] = true
when '--processingMode' then parser_options[:processingMode] = arg
when '--quiet'
options[:quiet] = true
logger.level = Logger::FATAL
when "--rdfstar" then parser_options[:rdfstar] = true
when "--rename_bnodes" then parser_options[:rename_bnodes] = (arg || 'true') == 'true'
when "--requireAll" then parser_options[:requireAll] = (arg || 'true') == 'true'
when '--stream' then parser_options[:stream] = true
when "--unique_bnodes" then parser_options[:unique_bnodes] = (arg || 'true') == 'true'
when '--uri' then parser_options[:base] = arg
when '--validate' then parser_options[:validate] = true
when '--help' then usage
when '--embed'
case arg
when '@always', '@never', '@link', '@once'
parser_options[:embed] = arg
when 'true'
parser_options[:embed] = '@never'
when 'false'
parser_options[:embed] = '@first'
else
STDERR.puts "--embed option takes one of @always, @never, @link, or @once"
exit(1)
end
end
end
# Hack
if !(options.keys & %i{expand compact flatten frame}).empty? &&
(parser_options[:stream] || options[:output_format] != :jsonld)
STDERR.puts "Incompatible options"
exit(1)
end
if ARGV.empty?
s = input ? input : $stdin.read
run(StringIO.new(s), options, parser_options)
else
ARGV.each do |file|
# Call with opened files
RDF::Util::File.open_file(file, **options) {|f| run(f, options, parser_options)}
end
end
puts