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)


115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/json/ld/writer.rb', line 115

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)


85
86
87
88
89
# File 'lib/json/ld/writer.rb', line 85

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

.new_hashObject



72
73
74
75
76
77
78
# File 'lib/json/ld/writer.rb', line 72

def self.new_hash
  if RUBY_VERSION < "1.9"
    InsertOrderPreservingHash.new
  else
    Hash.new
  end
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>>)


299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'lib/json/ld/writer.rb', line 299

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)


270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/json/ld/writer.rb', line 270

def format_literal(literal, options = {})
  if options[:canonical] || @options[:canonicalize]
    ret = new_hash
    ret[LITERAL] = literal.value
    ret[DATATYPE] = format_uri(literal.datatype, :position => :subject)if literal.has_datatype?
    ret[LANGUAGE] = literal.language.to_s if literal.has_language?
    return ret.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



258
259
260
# File 'lib/json/ld/writer.rb', line 258

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)


230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/json/ld/writer.rb', line 230

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

#new_hashObject



79
# File 'lib/json/ld/writer.rb', line 79

def new_hash; self.class.new_hash; end

#write_epiloguevoid

This method returns an undefined value.

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

See Also:



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
207
208
209
210
211
212
213
214
215
# File 'lib/json/ld/writer.rb', line 164

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] ? new_hash : 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)


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

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)


143
144
145
# File 'lib/json/ld/writer.rb', line 143

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



155
156
157
# File 'lib/json/ld/writer.rb', line 155

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