YAML and RDF

Posted by Charlie Sun, 30 Jul 2006 05:14:00 GMT

Sean mentioned the idea of using YAML for MapServer configuration files instead of XML. I wholeheartedly agree. The most important thing for a configuration file is that it is easily readable and editable. YAML's simpler syntax and conciseness is a big win in this case.

After reading his article, a brilliant idea occurred to me (well, at least I thought it was brilliant!) - use YAML to serialize RDF. RDF's graph data model maps poorly onto XML's hierarchical model, making RDF's XML serialization format more complicated than RDF itself. This complexity has been the subject of endless debates and has led to a number of alternative syntaxes over the years, such as Notation 3, Turtle, RPV, etc. Yet none of them have have been widely adopted.

XML's main advantages, compared to other serialization formats, are its extensibility, strong internationalization support and strong tool support.

A quick look at the YAML specification shows it supports UTF8 and UTF16 encodings, so its internationalization support looks good (I haven't done any testing to see if the reality is different). YAML's tool support is also good - you can find YAML parsers for Ruby, Python, PHP, JavaScript (using the JSON subset) and other languages as well.

Just like with XML, you can serialize custom vocabularies using YAML. However, YAML lacks a schema language. But if you're using RDF and require a schema, then clearly you will use RDF schema. RDF schema reuses the RDF XML serialization format, so I would take the same approach with YAML and use it to both encode RDF and RDF schemas.

Curious to see what work has been done in this area, I did a quick search. It turns out that Micah Dubinko suggested using YAML for RDF more than three years ago on the xml-dev mailing list.

As far as implementations, the only example I could find was a Perl module that hasn't bee updated since 2003. Now that some of the hype around XML has died down, and YAML has established itself as a legitimate format, it seems like a good time to revisit this idea.

Posted in , ,  | 2 comments | no trackbacks

YAML and RDF

Posted by Charlie Sun, 30 Jul 2006 05:14:00 GMT

Sean mentioned the idea of using YAML for MapServer configuration files instead of XML. I wholeheartedly agree. The most important thing for a configuration file is that it is easily readable and editable. YAML's simpler syntax and conciseness is a big win in this case.

After reading his article, a brilliant idea occurred to me (well, at least I thought it was brilliant!) - use YAML to serialize RDF. RDF's graph data model maps poorly onto XML's hierarchical model, making RDF's XML serialization format more complicated than RDF itself. This complexity has been the subject of endless debates and has led to a number of alternative syntaxes over the years, such as Notation 3, Turtle, RPV, etc. Yet none of them have have been widely adopted.

XML's main advantages, compared to other serialization formats, are its extensibility, strong internationalization support and strong tool support.

A quick look at the YAML specification shows it supports UTF8 and UTF16 encodings, so its internationalization support looks good (I haven't done any testing to see if the reality is different). YAML's tool support is also good - you can find YAML parsers for Ruby, Python, PHP, JavaScript (using the JSON subset) and other languages as well.

Just like with XML, you can serialize custom vocabularies using YAML. However, YAML lacks a schema language. But if you're using RDF and require a schema, then clearly you will use RDF schema. RDF schema reuses the RDF XML serialization format, so I would take the same approach with YAML and use it to both encode RDF and RDF schemas.

Curious to see what work has been done in this area, I did a quick search. It turns out that Micah Dubinko suggested using YAML for RDF more than three years ago on the xml-dev mailing list.

As far as implementations, the only example I could find was a Perl module that hasn't bee updated since 2003. Now that some of the hype around XML has died down, and YAML has established itself as a legitimate format, it seems like a good time to revisit this idea.

Posted in , ,  | 2 comments | no trackbacks

YAML Troubles

Posted by Charlie Tue, 21 Mar 2006 06:04:00 GMT

So for MapBuzz we have some machines running on Ruby 1.8.2 and 1.8.4. And we use GEOS, a C++ library, for manipulating geometries. These geometries are part of Rails test fixtures, and thus must support custom YAML marshalling. Turns out there were some big changes in YAML between 1.8.2 and 1.8.4.After struggling most of today with this, partially due to lack of documentation, here is what we found.


We’ll use an example of a simple coordinate class that has an x and a y value. What we want to end up with is this:

!ruby/Geos::Geometry
  x: 7
  y: 4

Ruby 1.8.2

For Ruby 1.8.2, the to_yaml_type controls the type that is output in the YAML document (the !ruby/Geos::Geometry bit). You also need to define a method to output YAML (to_yaml naturally enough) and one to read YAML (add_ruby_type strangely).

require 'geos'

class Coordinate  
  def to_yaml_type
    "!ruby/#{self.class}"
  end

  def to_yaml( opts = {} )
    YAML::quick_emit( self.object_id, opts ) do |out|
      out.map(to_yaml_type) do |map|
        ['x','y'].each do |m|
          map.add( m, self.send(m) )
        end
      end
    end
  end
  YAML.add_ruby_type( /^Geos::Coordinate/ ) do |type, val|
    result = Geos::Coordinate.new()
    val.each_pair do |k,v|
      result.send("#{k}=", v)
    end
    result
  end
end

Ruby 1.8.4

Things are significantly different with Ruby 1.8.4. First, the add_ruby_type method has been deprecated in favor of a class method called yaml_new. In fact, as far as I can see the add_ruby_type no longer works. Another major change is the use of taguris, such as "tag:ruby.yaml.org,2002." In fact, the 1.8.2 form !ruby is a shortcut for a YAML tag.

require 'geos'

class Coordinate  
  yaml_as "tag:ruby.yaml.org,2002:#{self}"

  def to_yaml( opts = {} )
    YAML::quick_emit( self.object_id, opts ) do |out|
      out.map(taguri) do |map|
        ['x','y'].each do |m|
          map.add( m, self.send(m) )
        end
      end
    end
  end

  def self.yaml_new(klass, tag, val)
    result = Geos::Coordinate.new()
    val.each_pair do |k,v|
      result.send("#{k}=", v)
    end
    result
  end
end

Of course, writing code that works on both platforms is kind of a pain. The approach we are using is:

require 'geos'

class Coordinate  
  yaml_as "tag:ruby.yaml.org,2002:#{self}"

  if not self.respond_to?(:taguri)
    def taguri
      "!ruby/#{self.class}"
    end
    YAML.add_ruby_type( /^Geos::Coordinate/ ) do |type, val|
      Coordinate.yaml_new(Geos::Coordinate, type, val)
    end
  end
    
  def to_yaml( opts = {} )
    YAML::quick_emit( self.object_id, opts ) do |out|
      out.map(taguri) do |map|
        ['x','y'].each do |m|
          map.add( m, self.send(m) )
        end
      end
    end
  end

  def self.yaml_new(klass, tag, val)
    result = Geos::Coordinate.new()
    val.each_pair do |k,v|
      result.send("#{k}=", v)
    end
    result
  end
end

This requires putting this code somewhere:

if not Module.methods.include?('yaml_as')
  # We're on a Ruby version before 1.8.4, stub out yaml_as
  class Module
    def yaml_as( tag, sc = true )
    end
  end
end

Hope this helps!

Posted in ,  | no comments | no trackbacks

YAML Troubles

Posted by Charlie Tue, 21 Mar 2006 06:04:00 GMT

So for MapBuzz we have some machines running on Ruby 1.8.2 and 1.8.4. And we use GEOS, a C++ library, for manipulating geometries. These geometries are part of Rails test fixtures, and thus must support custom YAML marshalling. Turns out there were some big changes in YAML between 1.8.2 and 1.8.4.After struggling most of today with this, partially due to lack of documentation, here is what we found.


We’ll use an example of a simple coordinate class that has an x and a y value. What we want to end up with is this:

!ruby/Geos::Geometry
  x: 7
  y: 4

Ruby 1.8.2

For Ruby 1.8.2, the to_yaml_type controls the type that is output in the YAML document (the !ruby/Geos::Geometry bit). You also need to define a method to output YAML (to_yaml naturally enough) and one to read YAML (add_ruby_type strangely).

require 'geos'

class Coordinate  
  def to_yaml_type
    "!ruby/#{self.class}"
  end

  def to_yaml( opts = {} )
    YAML::quick_emit( self.object_id, opts ) do |out|
      out.map(to_yaml_type) do |map|
        ['x','y'].each do |m|
          map.add( m, self.send(m) )
        end
      end
    end
  end
  YAML.add_ruby_type( /^Geos::Coordinate/ ) do |type, val|
    result = Geos::Coordinate.new()
    val.each_pair do |k,v|
      result.send("#{k}=", v)
    end
    result
  end
end

Ruby 1.8.4

Things are significantly different with Ruby 1.8.4. First, the add_ruby_type method has been deprecated in favor of a class method called yaml_new. In fact, as far as I can see the add_ruby_type no longer works. Another major change is the use of taguris, such as "tag:ruby.yaml.org,2002." In fact, the 1.8.2 form !ruby is a shortcut for a YAML tag.

require 'geos'

class Coordinate  
  yaml_as "tag:ruby.yaml.org,2002:#{self}"

  def to_yaml( opts = {} )
    YAML::quick_emit( self.object_id, opts ) do |out|
      out.map(taguri) do |map|
        ['x','y'].each do |m|
          map.add( m, self.send(m) )
        end
      end
    end
  end

  def self.yaml_new(klass, tag, val)
    result = Geos::Coordinate.new()
    val.each_pair do |k,v|
      result.send("#{k}=", v)
    end
    result
  end
end

Of course, writing code that works on both platforms is kind of a pain. The approach we are using is:

require 'geos'

class Coordinate  
  yaml_as "tag:ruby.yaml.org,2002:#{self}"

  if not self.respond_to?(:taguri)
    def taguri
      "!ruby/#{self.class}"
    end
    YAML.add_ruby_type( /^Geos::Coordinate/ ) do |type, val|
      Coordinate.yaml_new(Geos::Coordinate, type, val)
    end
  end
    
  def to_yaml( opts = {} )
    YAML::quick_emit( self.object_id, opts ) do |out|
      out.map(taguri) do |map|
        ['x','y'].each do |m|
          map.add( m, self.send(m) )
        end
      end
    end
  end

  def self.yaml_new(klass, tag, val)
    result = Geos::Coordinate.new()
    val.each_pair do |k,v|
      result.send("#{k}=", v)
    end
    result
  end
end

This requires putting this code somewhere:

if not Module.methods.include?('yaml_as')
  # We're on a Ruby version before 1.8.4, stub out yaml_as
  class Module
    def yaml_as( tag, sc = true )
    end
  end
end

Hope this helps!

Posted in ,  | no comments | no trackbacks