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 :normalize option to output JSON-LD in canonical form

Examples:

Obtaining a JSON-LD writer class

RDF::Writer.for(:jsonld)         #=> JSON::LD::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

  • :normalize (Boolean) — default: false

    Output document in [normalized form](json-ld.org/spec/latest/#normalization-1)

  • :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)


121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/json/ld/writer.rb', line 121

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)


89
90
91
92
93
# File 'lib/json/ld/writer.rb', line 89

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

.new_hashHash, InsertOrderPreservingHash

Local implementation of ruby Hash class to allow for ordering in 1.8.x implementations.

Returns:



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

def self.new_hash
  if RUBY_VERSION < "1.9"
    InsertOrderPreservingHash.new
  else
    Hash.new
  end
end

Instance Method Details

#format_list(object, options = {}) ⇒ Hash{"@list" => 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:

  • (Hash{"@list" => Array<Object>})


305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/json/ld/writer.rb', line 305

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' => list}.inspect}"}
  {'@list' => 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)


276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/json/ld/writer.rb', line 276

def format_literal(literal, options = {})
  if options[:normal] || @options[:normalize]
    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, :normal => 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



264
265
266
# File 'lib/json/ld/writer.rb', line 264

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)


236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/json/ld/writer.rb', line 236

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



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

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:



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
216
217
218
219
220
221
# File 'lib/json/ld/writer.rb', line 170

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

  reset

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

  preprocess
  
  # Don't generate context for canonical output
  json_hash = @options[:normalize] ? 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[:normalize]
      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)


140
141
142
143
# File 'lib/json/ld/writer.rb', line 140

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)


149
150
151
# File 'lib/json/ld/writer.rb', line 149

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



161
162
163
# File 'lib/json/ld/writer.rb', line 161

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