Class: JSON::LD::Writer

Inherits:
RDF::Writer
  • Object
show all
Defined in:
lib/json/ld/writer.rb

Overview

A JSON-LD parser in Ruby.

Note that the natural interface is to write a whole graph at a time. Writing statements or Triples will create a graph to add them to and then serialize the graph.

The writer will add prefix definitions, and use them for creating @context definitions, and minting CURIEs

Select the :canonicalize option to output JSON-LD in canonical form

Examples:

Obtaining a JSON-LD writer class

RDF::Writer.for(:jsonld)         #=> RDF::N3::Writer
RDF::Writer.for("etc/test.json")
RDF::Writer.for(:file_name      => "etc/test.json")
RDF::Writer.for(:file_extension => "json")
RDF::Writer.for(:content_type   => "application/turtle")

Serializing RDF graph into an JSON-LD file

JSON::LD::Writer.open("etc/test.json") do |writer|
  writer << graph
end

Serializing RDF statements into an JSON-LD file

JSON::LD::Writer.open("etc/test.json") do |writer|
  graph.each_statement do |statement|
    writer << statement
  end
end

Serializing RDF statements into an JSON-LD string

JSON::LD::Writer.buffer do |writer|
  graph.each_statement do |statement|
    writer << statement
  end
end

Creating @base, @vocab and @context prefix definitions in output

JSON::LD::Writer.buffer(
  :base_uri => "http://example.com/",
  :vocab => "http://example.net/"
  :prefixes => {
    nil => "http://example.com/ns#",
    :foaf => "http://xmlns.com/foaf/0.1/"}
) do |writer|
  graph.each_statement do |statement|
    writer << statement
  end
end

See Also:

Author:

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(output = $stdout, options = {}) {|writer| ... } ⇒ Writer

Initializes the RDF-LD writer instance.

Parameters:

  • output (IO, File) (defaults to: $stdout)

    the output stream

  • options (Hash{Symbol => Object}) (defaults to: {})

    any additional options

Options Hash (options):

  • :encoding (Encoding) — default: Encoding::UTF_8

    the encoding to use on the output stream (Ruby 1.9+)

  • :canonicalize (Boolean) — default: false

    whether to canonicalize literals when serializing

  • :prefixes (Hash) — default: Hash.new

    the prefix mappings to use (not supported by all writers)

  • :base_uri (#to_s) — default: nil

    Base IRI used for relativizing IRIs

  • :vocab (#to_s) — default: nil

    Vocabulary prefix used for relativizing IRIs

  • :standard_prefixes (Boolean) — default: false

    Add standard prefixes to @prefixes, if necessary.

Yields:

  • (writer)

    ‘self`

  • (writer)

Yield Parameters:

  • writer (RDF::Writer)
  • writer (RDF::Writer)

Yield Returns:

  • (void)


106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/json/ld/writer.rb', line 106

def initialize(output = $stdout, options = {}, &block)
  super do
    @graph = RDF::Graph.new
    @iri_to_prefix = DEFAULT_CONTEXT.dup.delete_if {|k,v| k == COERCE}.invert
    @coerce = DEFAULT_COERCE.merge(options[:coerce] || {})
    if block_given?
      case block.arity
        when 0 then instance_eval(&block)
        else block.call(self)
      end
    end
  end
end

Instance Attribute Details

#base_uriObject (readonly)



61
62
63
# File 'lib/json/ld/writer.rb', line 61

def base_uri
  @base_uri
end

#coerceObject

Type coersion to use for serialization. Defaults to DEFAULT_COERCION

Maintained as a reverse mapping of ‘property` => `type`.



70
71
72
# File 'lib/json/ld/writer.rb', line 70

def coerce
  @coerce
end

#graphObject (readonly)



59
60
61
# File 'lib/json/ld/writer.rb', line 59

def graph
  @graph
end

#vocabObject (readonly)



63
64
65
# File 'lib/json/ld/writer.rb', line 63

def vocab
  @vocab
end

Class Method Details

.hash(*args, &block) ⇒ Hash

Return the pre-serialized Hash before turning into JSON

Returns:

  • (Hash)


76
77
78
79
80
# File 'lib/json/ld/writer.rb', line 76

def self.hash(*args, &block)
  hash = {}
  self.new(hash, *args, &block)
  hash
end

Instance Method Details

#format_list(object, options = {}) ⇒ Array<Array<Object>>

Serialize an RDF list

Parameters:

  • object (RDF::URI)
  • options (Hash{Symbol => Object}) (defaults to: {})

Options Hash (options):

  • property (RDF::URI)

    Property referencing literal for type coercion

Returns:

  • (Array<Array<Object>>)


290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/json/ld/writer.rb', line 290

def format_list(object, options = {})
  predicate = options[:property]
  list = []

  add_debug "format_list(#{object}, #{predicate})"

  @depth += 1
  while object do
    subject_done(object)
    p = @graph.properties(object)
    item = p.fetch(RDF.first.to_s, []).first
    if item
      add_debug "format_list serialize #{item.inspect}"
      list << if predicate || item.literal?
        property(predicate, item)
      else
        subject(item)
      end
    end
    object = p.fetch(RDF.rest.to_s, []).first
  end
  @depth -= 1

  # Returns 
  add_debug "format_list => #{[list].inspect}"
  [list]
end

#format_literal(literal, options = {}) ⇒ Object

Returns the representation of a literal.

Parameters:

  • literal (RDF::Literal, String, #to_s)
  • options (Hash{Symbol => Object}) (defaults to: {})

Options Hash (options):

  • property (RDF::URI)

    Property referencing literal for type coercion

Returns:

  • (Object)


261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/json/ld/writer.rb', line 261

def format_literal(literal, options = {})
  if options[:canonical] || @options[:canonicalize]
    return {
      :literal => literal.value,
      :datatype => (format_uri(literal.datatype, :position => :subject) if literal.has_datatype?),
      :language => (literal.language.to_s if literal.has_language?)
    }.delete_if {|k,v| v.nil?}
  end

  case literal
  when RDF::Literal::Integer, RDF::Literal::Boolean
    literal.object
  when RDF::Literal
    if datatype_range?(options[:property]) || !(literal.has_datatype? || literal.has_language?)
      # Datatype coercion where literal has the same datatype
      literal.value
    else
      format_literal(literal, :canonical => true)
    end
  end
end

#format_node(value, options = {}) ⇒ String

This method is abstract.

Parameters:

  • value (RDF::Node)
  • options (Hash{Symbol => Object}) (defaults to: {})

Returns:

  • (String)

Raises:

  • (NotImplementedError)

    unless implemented in subclass



249
250
251
# File 'lib/json/ld/writer.rb', line 249

def format_node(value, options = {})
  format_uri(value, options)
end

#format_uri(value, options = {}) ⇒ Object

Returns the representation of a IRI reference.

Spec confusion: should a subject URI be normalized?

Parameters:

  • value (RDF::URI)
  • options (Hash{Symbol => Object}) (defaults to: {})

Options Hash (options):

  • position (:subject, :predicate, :object)

    Useful when determining how to serialize.

  • property (RDF::URI)

    Property for object reference, which can be used to return bare strings, rather than “iri”:

Returns:

  • (Object)


221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/json/ld/writer.rb', line 221

def format_uri(value, options = {})
  result = case options[:position]
  when :subject
    # attempt base_uri replacement
    short = value.to_s.sub(base_uri.to_s, "")
    short == value.to_s ? (get_curie(value) || value.to_s) : short
  when :predicate
    # attempt vocab replacement
    short = TYPE if value == RDF.type
    short ||= value.to_s.sub(@vocab.to_s, "")
    short == value.to_s ? (get_curie(value) || value.to_s) : short
  else
    # Encode like a subject
    iri_range?(options[:property]) ?
      format_uri(value, :position => :subject) :
      {:iri => format_uri(value, :position => :subject)}
  end

  add_debug("format_uri(#{options.inspect}, #{value.inspect}) => #{result.inspect}")
  result
end

#write_epiloguevoid

This method returns an undefined value.

Outputs the Serialized JSON-LD representation of all stored triples.

See Also:



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
202
203
204
205
206
# File 'lib/json/ld/writer.rb', line 155

def write_epilogue
  @base_uri = RDF::URI(@options[:base_uri]) if @options[:base_uri] && !@options[:canonicalize]
  @vocab = @options[:vocab] unless @options[:canonicalize]
  @debug = @options[:debug]

  reset

  add_debug "\nserialize: graph: #{@graph.size}"

  preprocess
  
  # Don't generate context for canonical output
  json_hash = @options[:canonicalize] ? {} : start_document

  elements = []
  order_subjects.each do |subject|
    unless is_done?(subject)
      elements << subject(subject, json_hash)
    end
  end
  
  return if elements.empty?
  
  if elements.length == 1 && elements.first.is_a?(Hash)
    json_hash.merge!(elements.first)
  else
    json_hash[SUBJECT] = elements
  end
  
  if @output.is_a?(Hash)
    @output.merge!(json_hash)
  else
    json_state = if @options[:canonicalize]
      JSON::State.new(
        :indent       => "",
        :space        => "",
        :space_before => "",
        :object_nl    => "",
        :array_nl     => ""
      )
    else
      JSON::State.new(
        :indent       => "  ",
        :space        => " ",
        :space_before => "",
        :object_nl    => "\n",
        :array_nl     => "\n"
      )
    end
    @output.write(json_hash.to_json(json_state))
  end
end

#write_graph(graph) ⇒ void

This method returns an undefined value.

Write whole graph

Parameters:

  • graph (Graph)


125
126
127
128
# File 'lib/json/ld/writer.rb', line 125

def write_graph(graph)
  add_debug "Add graph #{graph.inspect}"
  @graph = graph
end

#write_statement(statement) ⇒ void

This method returns an undefined value.

Addes a statement to be serialized

Parameters:

  • statement (RDF::Statement)


134
135
136
# File 'lib/json/ld/writer.rb', line 134

def write_statement(statement)
  @graph.insert(statement)
end

#write_triple(subject, predicate, object) ⇒ void

This method is abstract.

This method returns an undefined value.

Addes a triple to be serialized

Parameters:

  • subject (RDF::Resource)
  • predicate (RDF::URI)
  • object (RDF::Value)

Raises:

  • (NotImplementedError)

    unless implemented in subclass



146
147
148
# File 'lib/json/ld/writer.rb', line 146

def write_triple(subject, predicate, object)
  @graph.insert(Statement.new(subject, predicate, object))
end