<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Gregg Kellogg</title>
    <description>Gregg's Personal Blog</description>
    <link>https://greggkellogg.net/</link>
    <atom:link href="https://greggkellogg.net/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Sat, 12 Nov 2022 00:38:30 +0000</pubDate>
    <lastBuildDate>Sat, 12 Nov 2022 00:38:30 +0000</lastBuildDate>
    <generator>Jekyll v4.3.1</generator>
    
      <item>
        <title>Roatan June 2022</title>
        <description>&lt;p&gt;First time diving at &lt;a href=&quot;https://www.cocoviewresort.com&quot;&gt;Coco View Resort&lt;/a&gt; in &lt;a href=&quot;https://en.wikipedia.org/wiki/Roatán&quot;&gt;Roatan&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another new camara rig to break in. This time, the &lt;a href=&quot;https://www.backscatter.com/Olympus-PEN-E-PL10-Camera&quot;&gt;Olympus E-LP-10&lt;/a&gt; using the &lt;a href=&quot;https://www.backscatter.com/Backscatter-Olympus-PEN-E-PL9-E-PL10-Underwater-Housing-UH-EPL10&quot;&gt;Backscatter Octo Housing&lt;/a&gt;. The new &lt;a href=&quot;https://www.backscatter.com/Backscatter-Mini-Flash-Underwater-Strobe&quot;&gt;Mini Flash&lt;/a&gt; with &lt;a href=&quot;https://www.backscatter.com/Backscatter-Optical-Snoot-for-Backscatter-Mini-Flash-1&quot;&gt;Snoot&lt;/a&gt; makes for some cool Macro shots, although is challenging to get proper lighting.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://lightroom.adobe.com/gallery/7b25cc9c355b4a5dbc0e0e2c81bdd444/albums/27b8221b605a4f3f8a2b2d738bfc0f4b/assets&quot; jscontroller=&quot;false&quot; rel=&quot;qtposter&quot;&gt;
  Gallery&lt;br /&gt;
  &lt;img alt=&quot;Roatan Photo Gallery&quot; src=&quot;/galleries/Roatan-2022-06/6130018.jpg&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Sat, 25 Jun 2022 00:00:00 +0000</pubDate>
        <link>https://greggkellogg.net/2022/06/Roatan/</link>
        <guid isPermaLink="true">https://greggkellogg.net/2022/06/Roatan/</guid>
        
        
        <category>Diving</category>
        
        <category>Photography</category>
        
      </item>
    
      <item>
        <title>Roatan June 2021</title>
        <description>&lt;p&gt;After a year lock down, back diving in &lt;a href=&quot;https://en.wikipedia.org/wiki/Roatán&quot;&gt;Roatan&lt;/a&gt; at &lt;a href=&quot;https://www.turquoisebayresort.com&quot;&gt;Turquoise Bay Resort&lt;/a&gt;. Away from much of the rest of the island, this place has good nearby diving and was a fun relaxing place to stay.&lt;/p&gt;

&lt;p&gt;It was fun to get the photo rig back in the water, and I’m happy with my shots; enjoy!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://lightroom.adobe.com/gallery/7b25cc9c355b4a5dbc0e0e2c81bdd444/albums/4c0d6945ebc842eaa3f2ec6bea956495/assets&quot; jscontroller=&quot;false&quot; rel=&quot;qtposter&quot;&gt;
  Gallery&lt;br /&gt;
  &lt;img alt=&quot;Roatan Photo Gallery&quot; src=&quot;/galleries/Roatan-2021-06/IMG_1440.jpg&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Wed, 30 Jun 2021 00:00:00 +0000</pubDate>
        <link>https://greggkellogg.net/2021/06/Roatan/</link>
        <guid isPermaLink="true">https://greggkellogg.net/2021/06/Roatan/</guid>
        
        
        <category>Diving</category>
        
        <category>Photography</category>
        
      </item>
    
      <item>
        <title>Channel Islands August 2019</title>
        <description>&lt;p&gt;Nice to be back diving the &lt;a href=&quot;https://en.wikipedia.org/wiki/Channel_Islands_(California)&quot;&gt;Channel Islands&lt;/a&gt; on the &lt;a href=&quot;https://www.truthaquatics.com&quot;&gt;Truth&lt;/a&gt;. This time, conditions prevented us from diving Catalina and San Clemente, but we got a day in on &lt;a href=&quot;https://en.wikipedia.org/wiki/Santa_Barbara_Island&quot;&gt;Santa Barbara Island&lt;/a&gt; and two on &lt;a href=&quot;https://en.wikipedia.org/wiki/Santa_Cruz_Island&quot;&gt;Santa Cruz Island&lt;/a&gt;. Conditions were so-so, but it was fun to be back with friends and in the more rugged California diving conditions.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://lightroom.adobe.com/gallery/7b25cc9c355b4a5dbc0e0e2c81bdd444/albums/0d333bc2db4e4f888d863e7cb9c4aaf5/assets&quot; jscontroller=&quot;false&quot; rel=&quot;qtposter&quot;&gt;
  Gallery&lt;br /&gt;
  &lt;img alt=&quot;Channel Islands Photo Gallery&quot; src=&quot;/galleries/Channel%20Islands%202019-08/IMG_0789.jpg&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Sat, 01 Jun 2019 00:00:00 +0000</pubDate>
        <link>https://greggkellogg.net/2019/08/channel-islands-august-2019/</link>
        <guid isPermaLink="true">https://greggkellogg.net/2019/08/channel-islands-august-2019/</guid>
        
        
        <category>Diving</category>
        
        <category>Photography</category>
        
      </item>
    
      <item>
        <title>Saint Lucia June 2019</title>
        <description>&lt;p&gt;It was great to be back diving at &lt;a href=&quot;https://ansechastanet.com&quot;&gt;Anse Chastenet&lt;/a&gt; in &lt;a href=&quot;https://en.wikipedia.org/wiki/Saint_Lucia&quot;&gt;Saint Lucia&lt;/a&gt; after a long hiatus from diving. The resort is wonderful and the reefs are in great shape. First real chance to use my Olympus OMD-5.&lt;/p&gt;

&lt;p&gt;A Youtube video slideshow can be found &lt;a href=&quot;https://youtu.be/WHwPW3jOnx0&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://lightroom.adobe.com/gallery/7b25cc9c355b4a5dbc0e0e2c81bdd444/albums/fdb9b965729c40aea5a985bafe808c23/assets&quot; jscontroller=&quot;false&quot; rel=&quot;qtposter&quot;&gt;
  Gallery&lt;br /&gt;
  &lt;img alt=&quot;Saint Lucia Photo Gallery&quot; src=&quot;/galleries/Saint-Lucia-2019-06/saint-lucia-22.jpg&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Sat, 01 Jun 2019 00:00:00 +0000</pubDate>
        <link>https://greggkellogg.net/2019/06/saint-lucia-june-2019/</link>
        <guid isPermaLink="true">https://greggkellogg.net/2019/06/saint-lucia-june-2019/</guid>
        
        
        <category>Diving</category>
        
        <category>Photography</category>
        
      </item>
    
      <item>
        <title>CSV on the Web presentation</title>
        <description>&lt;p&gt;I presented &lt;a href=&quot;http://www.w3.org/2013/csvw/wiki/Main_Page&quot;&gt;CSV on the Web&lt;/a&gt; at the &lt;a href=&quot;http://smartdata2015.dataversity.net&quot;&gt;Smart Data Conference&lt;/a&gt; in San Jose. The slides are on &lt;a href=&quot;http://www.slideshare.net/gkellogg1/tabular-data-on-the-web&quot;&gt;SlideShare&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Thu, 20 Aug 2015 17:10:48 +0000</pubDate>
        <link>https://greggkellogg.net/2015/08/csv-on-the-web-presentation/</link>
        <guid isPermaLink="true">https://greggkellogg.net/2015/08/csv-on-the-web-presentation/</guid>
        
        
        <category>Semantic Web</category>
        
      </item>
    
      <item>
        <title>Implementing CSV on the Web</title>
        <description>&lt;p&gt;As I blogged about &lt;a href=&quot;https://greggkellogg.net/2015/04/csv-on-the-web/&quot;&gt;before&lt;/a&gt;, I’ve implemented the &lt;a href=&quot;http://www.w3.org/blog/data/2015/04/16/csv-on-the-web-seeking-comments-and-implementations/&quot;&gt;current drafts&lt;/a&gt; of &lt;a href=&quot;http://www.w3.org/2013/csvw/wiki/Main_Page&quot;&gt;CSV on the Web&lt;/a&gt; in the &lt;a href=&quot;http://rubygems.org/gems/rdf-tabular&quot;&gt;rdf-tabular gem&lt;/a&gt;. The gem is is available from &lt;a href=&quot;http://github.com/ruby-rdf/rdf-tabular&quot;&gt;rdf-tabular repo&lt;/a&gt; and is in the public domain (&lt;a href=&quot;http://unlicense.org&quot;&gt;Unlicense&lt;/a&gt;) and is freely usable by anyone wishing to get a start on their own implementation. For those wishing to take an incremental approach, this post describes the basic workings of the gem, highlights more advanced cases necessary to pass the &lt;a href=&quot;http://w3c.github.io/csvw/tests/&quot;&gt;Test Suite&lt;/a&gt; and attempts to provide some insight into the process of implementing the specifications.&lt;/p&gt;

&lt;h2 id=&quot;csvw--in-a-nutshell&quot;&gt;CSVW – in a nutshell&lt;/h2&gt;

&lt;p&gt;The basic purpose of the CSVW specifications is to do an informed process of CSVs into an &lt;em&gt;annotated data model&lt;/em&gt;, and use this model as the basis of creating RDF or JSON. At a minimum, this means assuming that the first row of a CSV is a &lt;em&gt;header row&lt;/em&gt; containing &lt;em&gt;titles&lt;/em&gt; for cells in that CSV, and that each row constitutes a record with properties based on the &lt;em&gt;column titles&lt;/em&gt; with values from each cell. We’ll use the canonical example of the &lt;a href=&quot;http://w3c.github.io/csvw/tests/tree-ops.csv&quot;&gt;tree-ops&lt;/a&gt; example from the &lt;a href=&quot;http://www.w3.org/TR/tabular-data-model/&quot; title=&quot;Model for Tabular Data and Metadata on the Web&quot;&gt;Model for Tabular Data&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;GID,On Street,Species,Trim Cycle,Inventory Date
1,ADDISON AV,Celtis australis,Large Tree Routine Prune,10/18/2010
2,EMERSON ST,Liquidambar styraciflua,Large Tree Routine Prune,6/2/2010
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This example has a header row and two data rows. The simple transformation of this to RDF without any external metadata would yield the following (in minimal mode):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;@base &amp;lt;http://w3c.github.io/csvw/tests/tree-ops.csv&amp;gt; .

[
  &amp;lt;#GID&amp;gt; &quot;2&quot;;
  &amp;lt;#Inventory%20Date&amp;gt; &quot;6/2/2010&quot;;
  &amp;lt;#On%20Street&amp;gt; &quot;EMERSON ST&quot;;
  &amp;lt;#Species&amp;gt; &quot;Liquidambar styraciflua&quot;;
  &amp;lt;#Trim%20Cycle&amp;gt; &quot;Large Tree Routine Prune&quot;
] .

[
  &amp;lt;#GID&amp;gt; &quot;1&quot;;
  &amp;lt;#Inventory%20Date&amp;gt; &quot;10/18/2010&quot;;
  &amp;lt;#On%20Street&amp;gt; &quot;ADDISON AV&quot;;
  &amp;lt;#Species&amp;gt; &quot;Celtis australis&quot;;
  &amp;lt;#Trim%20Cycle&amp;gt; &quot;Large Tree Routine Prune&quot;
] .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is minimally useful, but we can use this as a walk-through of how the &lt;a href=&quot;http://rubygems.org/gems/rdf-tabular&quot;&gt;rdf-tabular gem&lt;/a&gt; creates this.&lt;/p&gt;

&lt;p&gt;The first step is to retrieve the document from It’s URL: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://w3c.github.io/csvw/tests/tree-ops.csv&lt;/code&gt;. We then can look for metadata associated with the file to inform the creation of the &lt;em&gt;annotated table&lt;/em&gt;; this information might come from by the user specifying to location of metadata separately, from an HTTP Link header, by looking at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://w3c.github.io/csvw/tests/tree-ops.csv-metadata.json&lt;/code&gt; for file-specific metadata, or at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://w3c.github.io/csvw/tests/metadata.json&lt;/code&gt; for directory-specific metadata. In this case, there is none, so we constructed &lt;em&gt;embedded metatata&lt;/em&gt; from just the &lt;em&gt;header row&lt;/em&gt;. The process for locating metadata is described in &lt;a href=&quot;http://www.w3.org/TR/tabular-data-model/#creating-annotated-tables&quot;&gt;Creating Annotated Tables&lt;/a&gt;, and creating embedded metadata is described in &lt;a href=&quot;http://www.w3.org/TR/tabular-data-model/#parsing&quot;&gt;Parsing Tabular Data&lt;/a&gt;. Basically, we’re looking to create a &lt;em&gt;table description&lt;/em&gt; with a &lt;em&gt;schema&lt;/em&gt; describing each &lt;em&gt;column&lt;/em&gt; resulting in the following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;@context&quot;: &quot;http://www.w3.org/ns/csvw&quot;,
  &quot;url&quot;: &quot;http://w3c.github.io/csvw/tests/tree-ops.csv&quot;,
  &quot;tableSchema&quot;: {
    &quot;columns&quot;: [
      {&quot;titles&quot;: &quot;GID&quot;},
      {&quot;titles&quot;: &quot;On Street&quot;},
      {&quot;titles&quot;: &quot;Species&quot;},
      {&quot;titles&quot;: &quot;Trim Cycle&quot;},
      {&quot;titles&quot;: &quot;Inventory Date&quot;}
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By following the rules in the &lt;a href=&quot;http://www.w3.org/TR/tabular-metadata/&quot; title=&quot;Metadata Vocabulary for Tabular Data&quot;&gt;Metadata Format&lt;/a&gt;, we then create annotations on an &lt;em&gt;annotated table&lt;/em&gt; (an abstract model, shown in arbitrary JSON):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;@type&quot;: &quot;AnnotatedTableGroup&quot;,
  &quot;tables&quot;: [
    {
      &quot;@type&quot;: &quot;AnnotatedTable&quot;,
      &quot;url&quot;: &quot;http://w3c.github.io/csvw/tests/tree-ops.csv&quot;,
      &quot;columns&quot;: [
        {
          &quot;@id&quot;: &quot;http://w3c.github.io/csvw/tests/tree-ops.csv#col=1&quot;,
          &quot;@type&quot;: &quot;Column&quot;,
          &quot;number&quot;: 1,
          &quot;sourceNumber&quot;: 1,
          &quot;cells&quot;: [],
          &quot;name&quot;: &quot;GID&quot;,
          &quot;titles&quot;: {&quot;und&quot;: [&quot;GID&quot;]}
        },
        {
          &quot;@id&quot;: &quot;http://w3c.github.io/csvw/tests/tree-ops.csv#col=2&quot;,
          &quot;@type&quot;: &quot;Column&quot;,
          &quot;number&quot;: 2,
          &quot;sourceNumber&quot;: 2,
          &quot;cells&quot;: [],
          &quot;name&quot;: &quot;On%20Street&quot;,
          &quot;titles&quot;: {&quot;und&quot;: [&quot;On Street&quot;]}
        },
        {
          &quot;@id&quot;: &quot;http://w3c.github.io/csvw/tests/tree-ops.csv#col=3&quot;,
          &quot;@type&quot;: &quot;Column&quot;,
          &quot;number&quot;: 3,
          &quot;sourceNumber&quot;: 3,
          &quot;cells&quot;: [],
          &quot;name&quot;: &quot;Species&quot;,
          &quot;titles&quot;: {&quot;und&quot;: [&quot;Species&quot;]}
        },
        {
          &quot;@id&quot;: &quot;http://w3c.github.io/csvw/tests/tree-ops.csv#col=4&quot;,
          &quot;@type&quot;: &quot;Column&quot;,
          &quot;number&quot;: 4,
          &quot;sourceNumber&quot;: 4,
          &quot;cells&quot;: [],
          &quot;name&quot;: &quot;Trim%20Cycle&quot;,
          &quot;titles&quot;: {&quot;und&quot;: [&quot;Trim Cycle&quot;]}
        },
        {
          &quot;@id&quot;: &quot;http://w3c.github.io/csvw/tests/tree-ops.csv#col=5&quot;,
          &quot;@type&quot;: &quot;Column&quot;,
          &quot;number&quot;: 5,
          &quot;sourceNumber&quot;: 5,
          &quot;cells&quot;: [],
          &quot;name&quot;: &quot;Inventory%20Date&quot;,
          &quot;titles&quot;: {&quot;und&quot;: [&quot;Inventory Date&quot;]}
        }
      ],
      &quot;rows&quot;: []
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we gather some metadata based on the row and column numbers (logical and actual, which are the same here) and create a default for the &lt;em&gt;column name&lt;/em&gt; from &lt;em&gt;titles&lt;/em&gt;. Also, note that &lt;em&gt;titles&lt;/em&gt; is expanded to a &lt;a href=&quot;http://w3c.github.io/csvw/metadata/#dfn-natural-language-property&quot;&gt;natural language property&lt;/a&gt;, which is basically a &lt;a href=&quot;http://www.w3.org/TR/json-ld/#language-maps&quot;&gt;JSON-LD Language Map&lt;/a&gt; where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;und&lt;/code&gt; is used when there is no language. The &lt;em&gt;column name&lt;/em&gt; is percent encoded so that it can be used in a &lt;a href=&quot;https://tools.ietf.org/html/rfc6570&quot;&gt;URI template&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Note that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rows&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cells&lt;/code&gt; values are empty, as we haven’t actually processed any rows from the input yet.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;http://rubygems.org/gems/rdf-tabular&quot;&gt;rdf-tabular gem&lt;/a&gt; implements the &lt;a href=&quot;https://ruby-rdf.github.io/rdf/RDF/Reader&quot;&gt;RDF::Reader&lt;/a&gt; pattern, which takes care of much of the process of opening the file and getting useful metadata. In the case of the &lt;a href=&quot;http://rubygems.org/gems/rdf-tabular&quot;&gt;rdf-tabular gem&lt;/a&gt;, this includes the steps described in &lt;a href=&quot;http://www.w3.org/TR/tabular-data-model/#creating-annotated-tables&quot;&gt;Creating Annotated Tables&lt;/a&gt; which involves recursive invocations of the reader, but nominally, it yields a &lt;em&gt;reader instance&lt;/em&gt; which implements the &lt;a href=&quot;https://ruby-rdf.github.io/rdf/RDF/Enumerable&quot;&gt;RDF::Enumerable&lt;/a&gt; pattern. In particular, the reader implements an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#each&lt;/code&gt; method to yield each RDF Statement (triple); this is where the work actually happens. A call looks like the following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;RDF::Tabular::Reader.open(&quot;http://w3c.github.io/csvw/tests/tree-ops.csv&quot;) do |reader|
  reader.each do |statement|
    puts statement.inspect
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Basically, the job of the reader is to create the &lt;em&gt;abstract tabular data model&lt;/em&gt; and use it to read each row of the table(s) described in the model and use that to generate RDF triples (it can also be used to generate JSON output without going the RDF, but that’s another story).&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;http://rubygems.org/gems/rdf-tabular&quot;&gt;rdf-tabular gem&lt;/a&gt; implements &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RDF::Tabular::Metadata&lt;/code&gt;, with subclasses for the different kinds of metadata we need. This provides the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#each_row&lt;/code&gt; method, which given an input file yields each row. For the Ruby implementation, we use the &lt;a href=&quot;http://docs.ruby-lang.org/en/2.1.0/CSV.html&quot;&gt;CSV library&lt;/a&gt; and use dialect information to set parsing defaults. The gist of the implementation looks like the following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;def each_row(input)
  csv = ::CSV.new(input, csv_options)
  # Skip skipRows and headerRowCount
  number, skipped = 0, (dialect.skipRows.to_i + dialect.headerRowCount)
  (1..skipped).each {csv.shift}
  csv.each do |data|
    number += 1
    yield(Row.new(data, self, number, number + skipped))
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Row&lt;/code&gt; then abstracts information for each table row and provides the cells for that row:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Wraps each resulting row
class Row
  attr_reader :values

  # Class for returning values
  Cell = Struct.new(:table, :column, :row, :stringValue, :value, :errors)

  def initialize(row, metadata, number, source_number)
    @values = []
    skipColumns = metadata.dialect.skipColumns.to_i
    columns = metadata.tableSchema.columns
    row.each_with_index do |value, index|
      next if index &amp;lt; skipColumns
      column = columns[index - skipColumns]
      @values &amp;lt;&amp;lt; cell = Cell.new(metadata, column, self, value)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There’s more to this in the actual implementation, of course, but this handles a simple value.&lt;/p&gt;

&lt;p&gt;Now we can implement &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RDF::Tabular::Reader#each_statement&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;def each_statement(&amp;amp;block)
  metadata.each_row(input) do |row|
    default_cell_subject = RDF::Node.new
    row.values.each_with_index do |cell, index|
      propertyUrl = RDF::URI(&quot;#{metadata.url}##{cell.column.name}&quot;)
      yield RDF::Statement(default_cell_subject, propertyUrl, cell.value)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s pretty much the basis of a Ruby implementation. There’s more work to do in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#each_statement&lt;/code&gt;, as It’s initially invoked with a &lt;em&gt;TableGroup&lt;/em&gt;, which recursively invokes it again for each &lt;em&gt;Table&lt;/em&gt;, which then calls again for the actual CSV, but that’s all setup. There’s also work in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RDF::Tabular::Reader#initialize&lt;/code&gt; to find the metadata, ensure that it is compatible with the actual tables, and so forth.&lt;/p&gt;

&lt;h2 id=&quot;fleshing-out-with-more-details&quot;&gt;Fleshing out with more details&lt;/h2&gt;

&lt;p&gt;So, this implements a basic reader interface from a CSV using the &lt;em&gt;abstract tabular data model&lt;/em&gt;, but the output’s not too interesting. What if we want to make the data richer:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Give unique identifiers (&lt;em&gt;subjects&lt;/em&gt;) to the cells in a row&lt;/li&gt;
  &lt;li&gt;Use &lt;em&gt;subjects&lt;/em&gt; for different cells&lt;/li&gt;
  &lt;li&gt;Define &lt;em&gt;property URIs&lt;/em&gt; for each cell&lt;/li&gt;
  &lt;li&gt;Assign and match cell &lt;em&gt;string values&lt;/em&gt; to datatypes&lt;/li&gt;
  &lt;li&gt;Parse microformats within a given cell&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For that we need to define a Metadata file.&lt;/p&gt;

&lt;h3 id=&quot;defining-metadata&quot;&gt;Defining Metadata&lt;/h3&gt;

&lt;p&gt;A Metadata file is a &lt;a href=&quot;http://www.w3.org/TR/json-ld&quot; title=&quot;JSON-LD 1.0&quot;&gt;JSON-LD&lt;/a&gt; document (really, it has the structure of a JSON-LD document, it is parsed as JSON) which allows us to define &lt;em&gt;properties&lt;/em&gt; on metadata &lt;em&gt;declarations&lt;/em&gt; which directly relate to the &lt;em&gt;abstract tabular data model&lt;/em&gt;. For example, let’s look at the metadata description for the &lt;a href=&quot;http://w3c.github.io/csvw/tests/test011/tree-ops.csv&quot;&gt;tree-ops&lt;/a&gt; example: &lt;a href=&quot;http://w3c.github.io/csvw/tests/test011/tree-ops.csv-metadata.json&quot;&gt;tree-ops.csv-metadata.json&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;@context&quot;: [&quot;http://www.w3.org/ns/csvw&quot;, {&quot;@language&quot;: &quot;en&quot;}],
  &quot;url&quot;: &quot;tree-ops.csv&quot;,
  &quot;dc:title&quot;: &quot;Tree Operations&quot;,
  &quot;dcat:keyword&quot;: [&quot;tree&quot;, &quot;street&quot;, &quot;maintenance&quot;],
  &quot;dc:publisher&quot;: {
    &quot;schema:name&quot;: &quot;Example Municipality&quot;,
    &quot;schema:url&quot;: {&quot;@id&quot;: &quot;http://example.org&quot;}
  },
  &quot;dc:license&quot;: {&quot;@id&quot;: &quot;http://opendefinition.org/licenses/cc-by/&quot;},
  &quot;dc:modified&quot;: {&quot;@value&quot;: &quot;2010-12-31&quot;, &quot;@type&quot;: &quot;xsd:date&quot;},
  &quot;tableSchema&quot;: {
    &quot;columns&quot;: [{
      &quot;name&quot;: &quot;GID&quot;,
      &quot;titles&quot;: [&quot;GID&quot;, &quot;Generic Identifier&quot;],
      &quot;dc:description&quot;: &quot;An identifier for the operation on a tree.&quot;,
      &quot;datatype&quot;: &quot;string&quot;,
      &quot;required&quot;: true
    }, {
      &quot;name&quot;: &quot;on_street&quot;,
      &quot;titles&quot;: &quot;On Street&quot;,
      &quot;dc:description&quot;: &quot;The street that the tree is on.&quot;,
      &quot;datatype&quot;: &quot;string&quot;
    }, {
      &quot;name&quot;: &quot;species&quot;,
      &quot;titles&quot;: &quot;Species&quot;,
      &quot;dc:description&quot;: &quot;The species of the tree.&quot;,
      &quot;datatype&quot;: &quot;string&quot;
    }, {
      &quot;name&quot;: &quot;trim_cycle&quot;,
      &quot;titles&quot;: &quot;Trim Cycle&quot;,
      &quot;dc:description&quot;: &quot;The operation performed on the tree.&quot;,
      &quot;datatype&quot;: &quot;string&quot;
    }, {
      &quot;name&quot;: &quot;inventory_date&quot;,
      &quot;titles&quot;: &quot;Inventory Date&quot;,
      &quot;dc:description&quot;: &quot;The date of the operation that was performed.&quot;,
      &quot;datatype&quot;: {&quot;base&quot;: &quot;date&quot;, &quot;format&quot;: &quot;M/d/yyyy&quot;}
    }],
    &quot;primaryKey&quot;: &quot;GID&quot;,
    &quot;aboutUrl&quot;: &quot;#gid-{GID}&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we have a couple of different things going on. Note the following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;@context&quot;: [&quot;http://www.w3.org/ns/csvw&quot;, {&quot;@language&quot;: &quot;en&quot;}],
  &quot;url&quot;: &quot;tree-ops.csv&quot;,
  &quot;dc:title&quot;: &quot;Tree Operations&quot;,
  &quot;dcat:keyword&quot;: [&quot;tree&quot;, &quot;street&quot;, &quot;maintenance&quot;],
  &quot;dc:publisher&quot;: {
    &quot;schema:name&quot;: &quot;Example Municipality&quot;,
    &quot;schema:url&quot;: {&quot;@id&quot;: &quot;http://example.org&quot;}
  },
  &quot;dc:license&quot;: {&quot;@id&quot;: &quot;http://opendefinition.org/licenses/cc-by/&quot;},
  &quot;dc:modified&quot;: {&quot;@value&quot;: &quot;2010-12-31&quot;, &quot;@type&quot;: &quot;xsd:date&quot;},
  ...
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;em&gt;prefixed name&lt;/em&gt; properties are &lt;em&gt;common properties&lt;/em&gt;, basically just JSON-LD that’s inserted into the model to define &lt;em&gt;annotations&lt;/em&gt; on the model. In this case, their defined on a &lt;em&gt;Table&lt;/em&gt;, so they annotate that model. As it is JSON-LD, the string values take the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@langauge&lt;/code&gt; defined in the context. CSVW uses a &lt;a href=&quot;http://www.w3.org/TR/tabular-metadata/#json-ld-dialect&quot;&gt;dialect of JSON-LD&lt;/a&gt; which places some restrictions on what can go here. Basically, nothing more can go into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@context&lt;/code&gt; besides &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@language&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@base&lt;/code&gt;; it also must use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://www.w3.org/ns/csvw&lt;/code&gt; and only the terms and prefixes defined within that context can be used along with absolute IRIs.&lt;/p&gt;

&lt;pre&gt;{
  &quot;@context&quot;: [&quot;http://www.w3.org/ns/csvw&quot;, {&quot;@language&quot;: &quot;en&quot;}],
  &quot;url&quot;: &quot;tree-ops.csv&quot;,
  ...
  &quot;tableSchema&quot;: {
    &quot;columns&quot;: [{
      &quot;name&quot;: &quot;GID&quot;,
      &quot;titles&quot;: [&quot;GID&quot;, &quot;Generic Identifier&quot;],
      &quot;dc:description&quot;: &quot;An identifier for the operation on a tree.&quot;,
      &quot;datatype&quot;: &quot;string&quot;,
      &quot;required&quot;: true
    }, {
      &quot;name&quot;: &quot;on_street&quot;,
      &quot;titles&quot;: &quot;On Street&quot;,
      &quot;dc:description&quot;: &quot;The street that the tree is on.&quot;,
      &quot;datatype&quot;: &quot;string&quot;
    }, {
      &quot;name&quot;: &quot;species&quot;,
      &quot;titles&quot;: &quot;Species&quot;,
      &quot;dc:description&quot;: &quot;The species of the tree.&quot;,
      &quot;datatype&quot;: &quot;string&quot;
    }, {
      &quot;name&quot;: &quot;trim_cycle&quot;,
      &quot;titles&quot;: &quot;Trim Cycle&quot;,
      &quot;dc:description&quot;: &quot;The operation performed on the tree.&quot;,
      &quot;datatype&quot;: &quot;string&quot;
    }, {
      &quot;name&quot;: &quot;inventory_date&quot;,
      &quot;titles&quot;: &quot;Inventory Date&quot;,
      &quot;dc:description&quot;: &quot;The date of the operation that was performed.&quot;,
      &quot;datatype&quot;: {&quot;base&quot;: &quot;date&quot;, &quot;format&quot;: &quot;M/d/yyyy&quot;}
    }],
    &quot;primaryKey&quot;: &quot;GID&quot;,
    &quot;aboutUrl&quot;: &quot;#gid-{GID}&quot;
  }
}
&lt;/pre&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tableSchema&lt;/code&gt; property tells us that this is a &lt;em&gt;Table description&lt;/em&gt;; we could also have added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;@type&quot;: &quot;Table&quot;&lt;/code&gt; property to make this explicit, but It’s not necessary. Metadata always starts with either a &lt;em&gt;Table description&lt;/em&gt; or a &lt;em&gt;TableGroup description&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We define an explicit &lt;em&gt;name&lt;/em&gt; property for the first column. If we didn’t, it would take the first value from &lt;em&gt;titles&lt;/em&gt;. The &lt;em&gt;column&lt;/em&gt; has a &lt;em&gt;common property&lt;/em&gt;, which is presently not used in the transformation, but exists in the &lt;em&gt;annotated tabular data model&lt;/em&gt;. It also declares the data type to be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt;, which is a synonym for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xsd:string&lt;/code&gt;, and a value is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;required&lt;/code&gt;, meaning that it is considered an error if a cell value has an empty string (or one matching that defined using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt; annotation). Note that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;datatype&lt;/code&gt; is an &lt;em&gt;inherited property&lt;/em&gt;, meaning that it could have been defined on the &lt;em&gt;Table&lt;/em&gt;, &lt;em&gt;Schema&lt;/em&gt; or &lt;em&gt;Column&lt;/em&gt; and would be in scope for all cells based on the inheritance model.&lt;/p&gt;

&lt;p&gt;The last column uses a complex datatype: It is based on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xsd:date&lt;/code&gt; and uses a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;format&lt;/code&gt; string to match string values and map them onto the datatype. This allows a date of the form 4/17/2015 to be interpreted as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;2015-04-17&quot;^^xsd:date&lt;/code&gt; by using &lt;em&gt;date field symbols&lt;/em&gt; as defined in &lt;a href=&quot;http://www.unicode.org/reports/tr35/tr35-31/tr35.html&quot;&gt;UAX35&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All of these map pretty much as you would expect onto the &lt;em&gt;annotated tabular data model&lt;/em&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;@type&quot;: &quot;AnnotatedTableGroup&quot;,
  &quot;tables&quot;: [
    {
      &quot;@type&quot;: &quot;AnnotatedTable&quot;,
      &quot;url&quot;: &quot;http://w3c.github.io/csvw/tests/test011/tree-ops.csv&quot;,
      &quot;dc:title&quot;: {&quot;@value&quot;: &quot;Tree Operations&quot;,&quot;@language&quot;: &quot;en&quot;},
      &quot;dcat:keyword&quot;: [
        {&quot;@value&quot;: &quot;tree&quot;,&quot;@language&quot;: &quot;en&quot;},
        {&quot;@value&quot;: &quot;street&quot;,&quot;@language&quot;: &quot;en&quot;},
        {&quot;@value&quot;: &quot;maintenance&quot;,&quot;@language&quot;: &quot;en&quot;}
      ],
      &quot;dc:publisher&quot;: {
        &quot;schema:name&quot;: {&quot;@value&quot;: &quot;Example Municipality&quot;,&quot;@language&quot;: &quot;en&quot;},
        &quot;schema:url&quot;: {&quot;@id&quot;: &quot;http://example.org&quot;}
      },
      &quot;dc:license&quot;: {&quot;@id&quot;: &quot;http://opendefinition.org/licenses/cc-by/&quot;},
      &quot;dc:modified&quot;: {&quot;@value&quot;: &quot;2010-12-31&quot;,&quot;@type&quot;: &quot;xsd:date&quot;},
      &quot;columns&quot;: [
        {
          &quot;@id&quot;: &quot;http://w3c.github.io/csvw/tests/test011/tree-ops.csv#col=1&quot;,
          &quot;@type&quot;: &quot;Column&quot;,
          &quot;number&quot;: 1,
          &quot;sourceNumber&quot;: 1,
          &quot;cells&quot;: [],
          &quot;name&quot;: &quot;GID&quot;,
          &quot;titles&quot;: {&quot;en&quot;: [&quot;GID&quot;, &quot;Generic Identifier&quot;]},
          &quot;dc:description&quot;: {&quot;@value&quot;: &quot;An identifier for the operation on a tree.&quot;, &quot;@language&quot;: &quot;en&quot;},
          &quot;datatype&quot;: {&quot;base&quot;: &quot;string&quot;},
          &quot;required&quot;: true
        },
        {
          &quot;@id&quot;: &quot;http://w3c.github.io/csvw/tests/test011/tree-ops.csv#col=2&quot;,
          &quot;@type&quot;: &quot;Column&quot;,
          &quot;number&quot;: 2,
          &quot;sourceNumber&quot;: 2,
          &quot;cells&quot;: [],
          &quot;name&quot;: &quot;on_street&quot;,
          &quot;titles&quot;: {&quot;en&quot;: [&quot;On Street&quot;]},
          &quot;dc:description&quot;: {&quot;@value&quot;: &quot;The street that the tree is on.&quot;,&quot;@language&quot;: &quot;en&quot;},
          &quot;datatype&quot;: {&quot;base&quot;: &quot;string&quot;}
        },
        {
          &quot;@id&quot;: &quot;http://w3c.github.io/csvw/tests/test011/tree-ops.csv#col=3&quot;,
          &quot;@type&quot;: &quot;Column&quot;,
          &quot;number&quot;: 3,
          &quot;sourceNumber&quot;: 3,
          &quot;cells&quot;: [],
          &quot;name&quot;: &quot;species&quot;,
          &quot;titles&quot;: {&quot;en&quot;: [&quot;Species&quot;]},
          &quot;dc:description&quot;: {&quot;@value&quot;: &quot;The species of the tree.&quot;,&quot;@language&quot;: &quot;en&quot;},
          &quot;datatype&quot;: {&quot;base&quot;: &quot;string&quot;}
        },
        {
          &quot;@id&quot;: &quot;http://w3c.github.io/csvw/tests/test011/tree-ops.csv#col=4&quot;,
          &quot;@type&quot;: &quot;Column&quot;,
          &quot;number&quot;: 4,
          &quot;sourceNumber&quot;: 4,
          &quot;cells&quot;: [],
          &quot;name&quot;: &quot;trim_cycle&quot;,
          &quot;titles&quot;: {&quot;en&quot;: [&quot;Trim Cycle&quot;]},
          &quot;dc:description&quot;: {&quot;@value&quot;: &quot;The operation performed on the tree.&quot;,&quot;@language&quot;: &quot;en&quot;},
          &quot;datatype&quot;: {&quot;base&quot;: &quot;string&quot;}
        },
        {
          &quot;@id&quot;: &quot;http://w3c.github.io/csvw/tests/test011/tree-ops.csv#col=5&quot;,
          &quot;@type&quot;: &quot;Column&quot;,
          &quot;number&quot;: 5,
          &quot;sourceNumber&quot;: 5,
          &quot;cells&quot;: [],
          &quot;name&quot;: &quot;inventory_date&quot;,
          &quot;titles&quot;: {&quot;en&quot;: [&quot;Inventory Date&quot;]},
          &quot;dc:description&quot;: {&quot;@value&quot;: &quot;The date of the operation that was performed.&quot;,&quot;@language&quot;: &quot;en&quot;},
          &quot;datatype&quot;: {&quot;base&quot;: &quot;date&quot;, &quot;format&quot;: &quot;M/d/yyyy&quot;}
        }
      ],
      &quot;rows&quot;: []
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that the &lt;em&gt;common properties&lt;/em&gt; have been expanded and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@context&lt;/code&gt; simplified to remove &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@language&lt;/code&gt;. Also &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;datatype&lt;/code&gt; values have been normalized to the expanded form. This happens through the process of &lt;em&gt;Normalization&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;normalization&quot;&gt;Normalization&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://www.w3.org/TR/tabular-metadata/#normalization&quot;&gt;Normalization&lt;/a&gt; places metadata into a consistent format where compact values are expanded, values which may be an &lt;em&gt;Array&lt;/em&gt; are made into an &lt;em&gt;Array&lt;/em&gt;, &lt;em&gt;link properties&lt;/em&gt; have their URL expanded based on the base of the metadata and &lt;em&gt;object properties&lt;/em&gt; which are in the form of a URL string are opened and replaced with the content of the resource they reference.&lt;/p&gt;

&lt;h3 id=&quot;ensuring-metadata-compatibility-was-merging-metadata&quot;&gt;Ensuring Metadata Compatibility (was Merging Metadata)&lt;/h3&gt;

&lt;p&gt;The &lt;a href=&quot;http://www.w3.org/TR/tabular-data-model/#locating-metadata&quot;&gt;Locating Metadata&lt;/a&gt; describes the various places metadata files may be found. &lt;a href=&quot;http://www.w3.org/TR/tabular-data-model/#creating-annotated-tables&quot;&gt;Creating Annotated Tables&lt;/a&gt; defines the process of creating the final metadata when starting with either a Metadata File or a CSV. This calls for ensuring &lt;a href=&quot;http://w3c.github.io/csvw/syntax/#metadata-compatibility&quot;&gt;Metadata Compatibility&lt;/a&gt;. Given metadata, this can be used to find one or more tabular data files. These files are considered &lt;em&gt;compatible&lt;/em&gt; with the metadata, if they are referenced from the metadata (i.e., there is a Table Description referencing that particular tabular data file), and the columns in the Table Description Schema, match the columns in the tabular data file by comparing titles or names from the column metadata with the title of the tabular data file column, if it has one. This is necessary to ensure that the CSV file matches the schema described in metadata.&lt;/p&gt;

&lt;h3 id=&quot;uri-templates&quot;&gt;URI Templates&lt;/h3&gt;

&lt;p&gt;In the &lt;a href=&quot;http://w3c.github.io/csvw/examples/tree-ops-virtual.json&quot;&gt;tree-ops-virtual.json&lt;/a&gt; example, &lt;em&gt;URI template properties&lt;/em&gt; were defined:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;url&quot;: &quot;tree-ops.csv&quot;,
  &quot;@context&quot;: [&quot;http://www.w3.org/ns/csvw&quot;, {&quot;@language&quot;: &quot;en&quot;}],
  &quot;tableSchema&quot;: {
    &quot;columns&quot;: [{
      &quot;name&quot;: &quot;GID&quot;,
      &quot;titles&quot;: &quot;GID&quot;,
      &quot;datatype&quot;: &quot;string&quot;,
      &quot;propertyUrl&quot;: &quot;schema:url&quot;,
      &quot;valueUrl&quot;: &quot;#gid-{GID}&quot;
    }, {
      &quot;name&quot;: &quot;on_street&quot;,
      &quot;titles&quot;: &quot;On Street&quot;,
      &quot;datatype&quot;: &quot;string&quot;,
      &quot;aboutUrl&quot;: &quot;#location-{GID}&quot;,
      &quot;propertyUrl&quot;: &quot;schema:streetAddress&quot;
    }, {
      &quot;name&quot;: &quot;species&quot;,
      &quot;titles&quot;: &quot;Species&quot;,
      &quot;datatype&quot;: &quot;string&quot;,
      &quot;propertyUrl&quot;: &quot;schema:name&quot;
    }, {
      &quot;name&quot;: &quot;trim_cycle&quot;,
      &quot;titles&quot;: &quot;Trim Cycle&quot;,
      &quot;datatype&quot;: &quot;string&quot;
    }, {
      &quot;name&quot;: &quot;inventory_date&quot;,
      &quot;titles&quot;: &quot;Inventory Date&quot;,
      &quot;datatype&quot;: {&quot;base&quot;: &quot;date&quot;, &quot;format&quot;: &quot;M/d/yyyy&quot;},
      &quot;aboutUrl&quot;: &quot;#event-{inventory_date}&quot;,
      &quot;propertyUrl&quot;: &quot;schema:startDate&quot;
    }, {
      &quot;propertyUrl&quot;: &quot;schema:event&quot;,
      &quot;valueUrl&quot;: &quot;#event-{inventory_date}&quot;,
      &quot;virtual&quot;: true
    }, {
      &quot;propertyUrl&quot;: &quot;schema:location&quot;,
      &quot;valueUrl&quot;: &quot;#location-{GID}&quot;,
      &quot;virtual&quot;: true
    }, {
      &quot;aboutUrl&quot;: &quot;#location-{GID}&quot;,
      &quot;propertyUrl&quot;: &quot;rdf:type&quot;,
      &quot;valueUrl&quot;: &quot;schema:PostalAddress&quot;,
      &quot;virtual&quot;: true
    }],
    &quot;aboutUrl&quot;: &quot;#gid-{GID}&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This introduces several new concepts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The &lt;em&gt;Schema&lt;/em&gt; has an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aboutUrl&lt;/code&gt; property: &lt;strong&gt;“#gid-{GID}”&lt;/strong&gt;. This is a &lt;a href=&quot;https://tools.ietf.org/html/rfc6570&quot;&gt;URI Template&lt;/a&gt;, where &lt;em&gt;GID&lt;/em&gt; acts as a variable, taking the &lt;em&gt;cell value&lt;/em&gt; of the cell in the &lt;em&gt;GID&lt;/em&gt; column to construct a URI. In this case it constructs values such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;http://w3c.github.io/csvw/examples/tree-ops.csv#gid-1&amp;gt;&lt;/code&gt;. This is because the &lt;em&gt;Table&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;url&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tree-ops.csv&lt;/code&gt;, which is a URL relative to the location of the metadata file. In the first row, the value of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GID&lt;/code&gt; column is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;, so that is substituted to create &lt;strong&gt;“#gid-1”&lt;/strong&gt;, then resolved against &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;url&lt;/code&gt;. This &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aboutUrl&lt;/code&gt; then defines the default subject for all cells within that row.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first column has &lt;strong&gt;“propertyUrl”: “schema:url”&lt;/strong&gt;, which turns into the absolute URL &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://schema.org/url&lt;/code&gt;, and is used as the &lt;em&gt;predicate&lt;/em&gt; for that cell. As the column as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;valueUrl&lt;/code&gt; (&lt;strong&gt;“valueUrl”: “#gid-{GID}”&lt;/strong&gt;), that is expanded and used as the object for that cell. Thus, the first cell of the first row would result in the following triple:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;#gid-1&amp;gt; schema:url &amp;lt;#gid-1&amp;gt; .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(relative to the URL file location).&lt;/p&gt;

&lt;p&gt;The second column has It’s own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aboutUrl&lt;/code&gt; (&lt;strong&gt;“aboutUrl”: “#location-{GID}”&lt;/strong&gt;), meaning that the &lt;em&gt;subject&lt;/em&gt; for triples for this column are different than the &lt;em&gt;default subject&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The last three columns are &lt;em&gt;virtual columns&lt;/em&gt;, as they don’t correspond to data actually in the CSV; these are used for injecting information into the row. When fully processed, the following RDF is created (again, in minimal mode):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;@base &amp;lt;http://w3c.github.io/csvw/examples/tree-ops.csv&amp;gt; .
@prefix rdf: &amp;lt;http://www.w3.org/1999/02/22-rdf-syntax-ns#&amp;gt; .
@prefix schema: &amp;lt;http://schema.org/&amp;gt; .
@prefix xsd: &amp;lt;http://www.w3.org/2001/XMLSchema#&amp;gt; .

&amp;lt;#event-2010-06-02&amp;gt; schema:startDate &quot;2010-06-02&quot;^^xsd:date .

&amp;lt;#event-2010-10-18&amp;gt; schema:startDate &quot;2010-10-18&quot;^^xsd:date .

&amp;lt;#gid-1&amp;gt; schema:event &amp;lt;#event-2010-10-18&amp;gt;;
   schema:location &amp;lt;#location-1&amp;gt;;
   schema:name &quot;Celtis australis&quot;;
   schema:url &amp;lt;#gid-1&amp;gt;;
   &amp;lt;#trim_cycle&amp;gt; &quot;Large Tree Routine Prune&quot; .

&amp;lt;#gid-2&amp;gt; schema:event &amp;lt;#event-2010-06-02&amp;gt;;
   schema:location &amp;lt;#location-2&amp;gt;;
   schema:name &quot;Liquidambar styraciflua&quot;;
   schema:url &amp;lt;#gid-2&amp;gt;;
   &amp;lt;#trim_cycle&amp;gt; &quot;Large Tree Routine Prune&quot; .

&amp;lt;#location-1&amp;gt; a schema:PostalAddress;
   schema:streetAddress &quot;ADDISON AV&quot; .

&amp;lt;#location-2&amp;gt; a schema:PostalAddress;
   schema:streetAddress &quot;EMERSON ST&quot; .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Processing this requires some enhancement to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RDF::Tabular::Row#initialize&lt;/code&gt; method:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Wraps each resulting row
class Row
  attr_reader :values

  # Class for returning values
  Cell = Struct.new(:table, :column, :row, :stringValue, :aboutUrl, :propertyUrl, :valueUrl, :value, :errors) do

    def set_urls(mapped_values)
      %w(aboutUrl propertyUrl valueUrl).each do |prop|
        # If the cell value is nil, and it is not a virtual column
        next if prop == &quot;valueUrl&quot; &amp;amp;&amp;amp; value.nil? &amp;amp;&amp;amp; !column.virtual
        if v = column.send(prop.to_sym)
          t = Addressable::Template.new(v)
          mapped = t.expand(mapped_values).to_s
          url = row.context.expand_iri(mapped, documentRelative: true)
          self.send(&quot;#{prop}=&quot;.to_sym, url)
        end
      end
    end

  end

  def initialize(row, metadata, number, source_number)
    @values = []
    skipColumns = metadata.dialect.skipColumns.to_i
    columns = metadata.tableSchema.columns
    row.each_with_index do |value, index|
      next if index &amp;lt; skipColumns
      column = columns[index - skipColumns]
      @values &amp;lt;&amp;lt; cell = Cell.new(metadata, column, self, value)

      datatype = column.datatype || Datatype.new(base: &quot;string&quot;, parent: column)
      cell_value = value_matching_datatype(value.dup, datatype, expanded_dt, column.lang)
      map_values[columns[index - skipColumns].name] =  cell_value.to_s

    end

    # Map URLs for row
    ...
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This introduces datatype matching through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#value_matching_datatype&lt;/code&gt; (not detailed), creates a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map_values&lt;/code&gt; structure that can be used for &lt;a href=&quot;https://tools.ietf.org/html/rfc6570&quot;&gt;URI template&lt;/a&gt; processing, and then calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cell#set_urls&lt;/code&gt; to actually create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aboutUrl&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;propertyUrl&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;valueUrl&lt;/code&gt; annotations on the cell.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#each_statement&lt;/code&gt; method is updated to take these into consideration:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;def each_statement(&amp;amp;block)
  metadata.each_row(input) do |row|
    default_cell_subject = RDF::Node.new
    row.values.each_with_index do |cell, index|
      cell_subject = cell.aboutUrl || default_cell_subject
      propertyUrl = cell.propertyUrl || RDF::URI(&quot;#{metadata.url}##{cell.column.name}&quot;)
        yield RDF::Statement(cell_subject, propertyUrl, cell.column.valueUrl || cell.value)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here the only difference is that we use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cell.aboutUrl&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cell.propertyUrl&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cell.valueUrl&lt;/code&gt; if they are defined, and the defaults otherwise.&lt;/p&gt;

&lt;h3 id=&quot;multiple-values&quot;&gt;Multiple Values&lt;/h3&gt;

&lt;p&gt;Microsyntaxes are common in CSVs, and there are many different kind. A microsyntax is some convention for formatting information within a cell. CSVW supports delimited values within a cell, so that a list of elements can be provided, allowing a single cell to contain multiple values.&lt;/p&gt;

&lt;p&gt;For example the &lt;a href=&quot;http://w3c.github.io/csvw/examples/tree-ops-ext.csv&quot;&gt;tree-ops-ext.csv&lt;/a&gt; example allows for multiple comments on a record using “;” as a separator:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;GID,On Street,Species,Trim Cycle,Diameter at Breast Ht,Inventory Date,Comments,Protected,KML
1,ADDISON AV,Celtis australis,Large Tree Routine Prune,11,10/18/2010,,,&quot;&amp;lt;Point&amp;gt;&amp;lt;coordinates&amp;gt;-122.156485,37.440963&amp;lt;/coordinates&amp;gt;&amp;lt;/Point&amp;gt;&quot;
2,EMERSON ST,Liquidambar styraciflua,Large Tree Routine Prune,11,6/2/2010,,,&quot;&amp;lt;Point&amp;gt;&amp;lt;coordinates&amp;gt;-122.156749,37.440958&amp;lt;/coordinates&amp;gt;&amp;lt;/Point&amp;gt;&quot;
6,ADDISON AV,Robinia pseudoacacia,Large Tree Routine Prune,29,6/1/2010,cavity or decay; trunk decay; codominant leaders; included bark; large leader or limb decay; previous failure root damage; root decay;  beware of BEES,YES,&quot;&amp;lt;Point&amp;gt;&amp;lt;coordinates&amp;gt;-122.156299,37.441151&amp;lt;/coordinates&amp;gt;&amp;lt;/Point&amp;gt;&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href=&quot;http://w3c.github.io/csvw/examples/tree-ops-ext.csv-metadata.json&quot;&gt;metadata file&lt;/a&gt; adds the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;separator&lt;/code&gt; property to the &lt;em&gt;comments&lt;/em&gt; column:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;tableSchema&quot;: {
    &quot;columns&quot;: [
      ...
      {
        &quot;name&quot;: &quot;comments&quot;,
        &quot;titles&quot;: &quot;Comments&quot;,
        &quot;dc:description&quot;: &quot;Supplementary comments relating to the operation or tree.&quot;,
        &quot;datatype&quot;: &quot;string&quot;,
        &quot;separator&quot;: &quot;;&quot;
      }
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The effect of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;separator&lt;/code&gt; is to split the string value into multiple values and parse them using any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;datatype&lt;/code&gt; description. This is shown using slight modifications to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RDF::Tabular::Row#initialize&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RDF::Tabular::Reader#each_statement&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Wraps each resulting row
class Row
  attr_reader :values
  def initialize(row, metadata, number, source_number)
    @values = []
    skipColumns = metadata.dialect.skipColumns.to_i
    columns = metadata.tableSchema.columns
    row.each_with_index do |value, index|
      next if index &amp;lt; skipColumns
      column = columns[index - skipColumns]
      @values &amp;lt;&amp;lt; cell = Cell.new(metadata, column, self, value)
      datatype = column.datatype || Datatype.new(base: &quot;string&quot;, parent: column)


      cell_values = column.separator ? value.split(column.separator) : [value]

      cell_values = cell_values.map do |v|
        value_matching_datatype(v.dup, datatype, expanded_dt, column.lang)
      end

      cell.value = (column.separator ? cell_values : cell_values.first)

      map_values[columns[index - skipColumns].name] =  (column.separator ? cell_values.map(&amp;amp;:to_s) : cell_values.first.to_s)
    end

    # Map URLs for row
    @values.each_with_index do |cell, index|
      mapped_values = map_values.merge(
        &quot;_name&quot; =&amp;gt; URI.decode(cell.column.name),
        &quot;_column&quot; =&amp;gt; cell.column.number,
        &quot;_sourceColumn&quot; =&amp;gt; cell.column.sourceNumber
      )
      cell.set_urls(mapped_values)
    end

  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The only change to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#each_statement&lt;/code&gt; is to consider multiple cell values:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;def each_statement(&amp;amp;block)
  metadata.each_row(input) do |row|
    default_cell_subject = RDF::Node.new
    row.values.each_with_index do |cell, index|
      cell_subject = cell.aboutUrl || default_cell_subject
      propertyUrl = cell.propertyUrl || RDF::URI(&quot;#{metadata.url}##{cell.column.name}&quot;)

      if cell.column.valueUrl
        yield RDF::Statement(cell_subject, propertyUrl, cell.column.valueUrl)
      else
        Array(cell.value).each do |v|
          yield RDF::Statement(cell_subject, propertyUrl, v)
        end
      end

    end
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;common-properties-and-notes&quot;&gt;Common Properties and Notes&lt;/h3&gt;

&lt;p&gt;Common Properties and Notes are simply embedded &lt;a href=&quot;http://www.w3.org/TR/json-ld&quot; title=&quot;JSON-LD 1.0&quot;&gt;JSON-LD&lt;/a&gt; within the metadata file (although limited) to a specific &lt;a href=&quot;http://www.w3.org/TR/tabular-metadata/#json-ld-dialect&quot;&gt;dialect&lt;/a&gt; to simplify implementations. In Ruby, of course, we have available a full &lt;a href=&quot;http://rubygems.org/gems/json-ld&quot;&gt;json-ld gem&lt;/a&gt;, so turning this into RDF shouldn’t present any problems.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;This article has shown the basis for implementing the &lt;a href=&quot;http://www.w3.org/2013/csvw/wiki/Main_Page&quot;&gt;CSV on the Web&lt;/a&gt; specifications, and hopefully will aid in more implementations.&lt;/p&gt;

&lt;h2 id=&quot;update-2014-05-14&quot;&gt;Update 2014-05-14&lt;/h2&gt;

&lt;p&gt;This post has been updated to reflect the fact the metadata merging has been removed from CSVW, simplifying an implementation even further.&lt;/p&gt;
</description>
        <pubDate>Sat, 18 Apr 2015 20:14:54 +0000</pubDate>
        <link>https://greggkellogg.net/2015/04/implementing-csv-on-the-web/</link>
        <guid isPermaLink="true">https://greggkellogg.net/2015/04/implementing-csv-on-the-web/</guid>
        
        
        <category>Ruby</category>
        
        <category>Semantic Web</category>
        
      </item>
    
      <item>
        <title>CSV on the Web</title>
        <description>&lt;p&gt;As many who follow me know, I’ve long been involved in the Linked Data and Semantic Web movements. It’s been my privilege to work on several successful projects, notably &lt;a href=&quot;http://www.w3.org/TR/rdfa-core&quot; title=&quot;HTML+RDFa 1.1&quot;&gt;RDFa&lt;/a&gt;, &lt;a href=&quot;http://www.w3.org/TR/microdata-rdf&quot; title=&quot;Microdata to RDF&quot;&gt;Microdata RDF&lt;/a&gt;, and &lt;a href=&quot;http://www.w3.org/TR/json-ld&quot; title=&quot;JSON-LD 1.0&quot;&gt;JSON-LD&lt;/a&gt;. For the past several months I’ve actively been working with the W3C &lt;a href=&quot;http://www.w3.org/2013/csvw/wiki/Main_Page&quot;&gt;CSV on the Web&lt;/a&gt; Working Group to help define a mechanism for transforming tabular data into RDF and JSON.&lt;/p&gt;

&lt;p&gt;Much of the data published on the Web is not HTML, or even some other structured content. In fact, a substantial amount of information is published as tabular data (comma-separated-values or tab-separated-values, commonly &lt;em&gt;CSVs&lt;/em&gt;). This includes a vast amount of open government publications, such as records, weather and climate information, infrastructure assets, and so forth (see &lt;a href=&quot;http://www.w3.org/TR/csvw-ucr/&quot;&gt;Use Cases&lt;/a&gt; for more detail). The charter of the &lt;a href=&quot;http://www.w3.org/2013/csvw/wiki/Main_Page&quot;&gt;CSV on the Web&lt;/a&gt; Working Group is to provide technologies to promote greater interoperability of these datasets.&lt;/p&gt;

&lt;p&gt;Real data is often messy, and information contained in relational databases and large spreadsheets is often lost when It’s published as &lt;em&gt;CSVs&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Foreign Key relationships between tables&lt;/li&gt;
  &lt;li&gt;Primary Keys of tables (including composite primary keys)&lt;/li&gt;
  &lt;li&gt;Well Known Identifiers of entities used in tables&lt;/li&gt;
  &lt;li&gt;Datatypes of column data, such as date/time or numeric values&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The aim of the working group is to create a common &lt;a href=&quot;http://www.w3.org/TR/tabular-data-model/&quot; title=&quot;Model for Tabular Data and Metadata on the Web&quot;&gt;Model for Tabular Data&lt;/a&gt;, and &lt;a href=&quot;http://www.w3.org/TR/tabular-metadata/&quot; title=&quot;Metadata Vocabulary for Tabular Data&quot;&gt;Metadata Format&lt;/a&gt; for describing tabular data. Given this, validators, converters and viewers are enabled to work with datasets by using a common data model.&lt;/p&gt;

&lt;h2 id=&quot;csv-ld&quot;&gt;CSV-LD&lt;/h2&gt;

&lt;p&gt;My work started about a year ago when the Working Group was being established. The group was considering using &lt;a href=&quot;http://www.w3.org/TR/json-ld&quot; title=&quot;JSON-LD 1.0&quot;&gt;JSON-LD&lt;/a&gt; as a way of describing metadata about tables, and the work we had done on &lt;a href=&quot;http://json-ld.org/spec/latest/json-ld-framing/&quot;&gt;JSON-LD Framing&lt;/a&gt; seemed like a good fit for both a metadata and transformation specification. My thoughts are expressed in a wiki page on &lt;a href=&quot;https://www.w3.org/2013/csvw/wiki/CSV-LD&quot;&gt;CSV-LD&lt;/a&gt;; the idea was that each row of a table could map to values within a JSON-LD template which could then be turned into a JSON-LD document made from each row from the spreadsheet&lt;/p&gt;

&lt;p&gt;Looking back there are a number of over-simiplifications on this spec, but the use of JSON-LD to describe information about tabular data remains.&lt;/p&gt;

&lt;h2 id=&quot;csv-data-model&quot;&gt;CSV Data Model&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;http://www.w3.org/TR/tabular-data-model/&quot; title=&quot;Model for Tabular Data and Metadata on the Web&quot;&gt;Model for Tabular Data&lt;/a&gt; describes an abstract data model for &lt;em&gt;groups of tables&lt;/em&gt;, &lt;em&gt;tables&lt;/em&gt;, &lt;em&gt;columns&lt;/em&gt;, &lt;em&gt;rows&lt;/em&gt; and individual &lt;em&gt;cells&lt;/em&gt;. As such, it becomes a useful mechanism to refer to information when performing validation or conversion of &lt;em&gt;CSVs&lt;/em&gt;. In practice, a complete in-memory data model doesn’t typically need to be created, but it serves a useful purpose: Each entity in this model describes its relationship with other entities using &lt;em&gt;core annotations&lt;/em&gt;; for example, the set of &lt;em&gt;tables&lt;/em&gt; in a &lt;em&gt;group of tables&lt;/em&gt;, the &lt;em&gt;rows&lt;/em&gt; and &lt;em&gt;columns&lt;/em&gt; in a &lt;em&gt;table&lt;/em&gt;, and the &lt;em&gt;cells&lt;/em&gt; within both &lt;em&gt;rows&lt;/em&gt; and &lt;em&gt;columns&lt;/em&gt;. The model also describes other useful information, such as the &lt;em&gt;datatypes&lt;/em&gt; of a &lt;em&gt;cell value&lt;/em&gt;, and if the &lt;em&gt;cell&lt;/em&gt; contains multiple values (using an internal &lt;em&gt;separator&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;A &lt;em&gt;converter&lt;/em&gt;, such as a &lt;a href=&quot;http://w3c.github.io/csvw/csv2rdf/&quot; title=&quot;Generating RDF from Tabular Data on the Web&quot;&gt;CSV2RDF&lt;/a&gt; or &lt;a href=&quot;http://w3c.github.io/csvw/csv2json/&quot; title=&quot;Generating JSON from Tabular Data on the Web&quot;&gt;CSV2JSON&lt;/a&gt; converter, can then logically iterate over these entities to generate the resulting information. A &lt;em&gt;validator&lt;/em&gt; can use information about datatypes to validate cell values and foreign key relationships to verify the integrity of published information. A &lt;em&gt;viewer&lt;/em&gt; can use information about character sets, table direction and text direction to properly present information originally published as &lt;em&gt;CSVs&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Creating a data model from &lt;em&gt;CSVs&lt;/em&gt; is the process of either starting with metadata describing those &lt;em&gt;CSVs&lt;/em&gt;, or locating metadata given a &lt;em&gt;CSV&lt;/em&gt;. The &lt;a href=&quot;http://www.w3.org/TR/tabular-data-model/&quot; title=&quot;Model for Tabular Data and Metadata on the Web&quot;&gt;Model for Tabular Data&lt;/a&gt; describes the process of locating such metadata and reconciling multiple metadata files that may be encountered. The &lt;a href=&quot;http://www.w3.org/TR/tabular-metadata/&quot; title=&quot;Metadata Vocabulary for Tabular Data&quot;&gt;Metadata Format&lt;/a&gt; then describes the structure of this data (syntactically, as a &lt;a href=&quot;http://www.w3.org/TR/json-ld&quot; title=&quot;JSON-LD 1.0&quot;&gt;JSON-LD&lt;/a&gt; formatted document) and working with it to create the basis of the &lt;em&gt;core annotations&lt;/em&gt; of the &lt;em&gt;annotated data model&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As an example, I recently worked with others to release the &lt;a href=&quot;http://rubygems.org/gems/rdf-vocab&quot;&gt;rdf-vocab&lt;/a&gt; Ruby gem, which includes a Ruby version of different RDF Ontologies/Vocabularies used for reasoning on things such as the &lt;a href=&quot;http://linter.structured-data.org/&quot;&gt;Structured Data Linter&lt;/a&gt;. One vocabulary we very much wanted to include as the &lt;a href=&quot;http://www.iana.org/assignments/link-relations/link-relations.xhtml&quot;&gt;IANA Link Relations&lt;/a&gt;. This is not published as any kind of RDF dataset, much less as an RDFS or OWL vocabulary definition. In fact, this has prevented it from being used in different standards work, as the link relation for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;describes&lt;/code&gt; cannot easily be dereferenced to find It’s definition. Formally, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;describes&lt;/code&gt; link relation maps to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://www.iana.org/assignments/link-relations/describes&lt;/code&gt; URI, but dereferencing this results in an HTTP 404 status. However, this doesn’t need to get in the way of defining an RDFS vocabulary based on this dataset. Thankfully, the link relations are published in other formats, including &lt;a href=&quot;http://www.iana.org/assignments/link-relations/link-relations-1.csv&quot;&gt;csv&lt;/a&gt;. This allows us to construct a &lt;a href=&quot;https://github.com/ruby-rdf/rdf-vocab/blob/develop/etc/iana-metadata.json&quot;&gt;metadata description&lt;/a&gt; of this dataset:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;@context&quot;: &quot;http://www.w3.org/ns/csvw&quot;,
  &quot;url&quot;: &quot;http://www.iana.org/assignments/link-relations/link-relations-1.csv&quot;,
  &quot;tableSchema&quot;: {
    &quot;aboutUrl&quot;: &quot;{name}&quot;,
    &quot;lang&quot;: &quot;en&quot;,
    &quot;columns&quot;: [
      {&quot;name&quot;: &quot;name&quot;, &quot;title&quot;: &quot;Relation Name&quot;, &quot;propertyUrl&quot;: &quot;rdfs:label&quot;},
      {&quot;name&quot;: &quot;comment&quot;, &quot;title&quot;: &quot;Description&quot;, &quot;propertyUrl&quot;: &quot;rdfs:comment&quot;},
      {&quot;name&quot;: &quot;type&quot;, &quot;title&quot;: &quot;Reference&quot;, &quot;propertyUrl&quot;: &quot;rdf:type&quot;, &quot;valueUrl&quot;: &quot;rdf:Property&quot;},
      {&quot;title&quot;: &quot;Notes&quot;, &quot;suppressOutput&quot;: true}
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This says that there is a table located at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://www.iana.org/assignments/link-relations/link-relations-1.csv&lt;/code&gt; with a &lt;em&gt;schema&lt;/em&gt;. Each row identifies a different &lt;em&gt;subject&lt;/em&gt; using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aboutUrl&lt;/code&gt; property. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;{name}&quot;&lt;/code&gt; value is a &lt;a href=&quot;https://tools.ietf.org/html/rfc6570&quot;&gt;URI template&lt;/a&gt; that creates a URI from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; variable relative to the location of the &lt;em&gt;CSV&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Each column is given a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;title&lt;/code&gt;, along with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;propertyUrl&lt;/code&gt; which is used to relate the &lt;em&gt;subject&lt;/em&gt; with the value of a given cell. The first two columns are textual, and result in an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RDF Literal&lt;/code&gt; when mapped to RDF. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lang&lt;/code&gt; property defines the overall language to apply to plain literals in this dataset. The third column is turned into a URI using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;valueUrl&lt;/code&gt; property and the fourth column is simply ignored; note that the cell contents of the third column aren’t actually used to create the value, and the value is hard-coded as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rdf:Property&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Mapping this on the CSV, for example, turns the first row into the following RDF:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;http://www.iana.org/assignments/link-relations/about&amp;gt; rdfs:label &quot;about@en&quot;;
  rdfs:comment &quot;Refers to a resource that is the subject of the link's context.&quot;@en;
  rdf:type rdf:Property .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Within the &lt;a href=&quot;http://rdf.rubyforge.org/&quot;&gt;RDF.rb&lt;/a&gt; tool chain, this allows the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RDF::Vocab::IANA.about&lt;/code&gt; to refer to this property definition. The reasoner knows It’s a property, because It’s type if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rdf:Property&lt;/code&gt;. The completely transformed CSV can be found &lt;a href=&quot;https://raw.githubusercontent.com/ruby-rdf/rdf-vocab/develop/etc/iana.ttl&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The group has just released new working drafts for &lt;a href=&quot;http://www.w3.org/TR/tabular-data-model/&quot; title=&quot;Model for Tabular Data and Metadata on the Web&quot;&gt;Model for Tabular Data&lt;/a&gt; and the &lt;a href=&quot;http://www.w3.org/TR/tabular-metadata/&quot; title=&quot;Metadata Vocabulary for Tabular Data&quot;&gt;Metadata Format&lt;/a&gt;, along with &lt;a href=&quot;http://w3c.github.io/csvw/csv2rdf/&quot; title=&quot;Generating RDF from Tabular Data on the Web&quot;&gt;CSV2RDF&lt;/a&gt; and &lt;a href=&quot;http://w3c.github.io/csvw/csv2json/&quot; title=&quot;Generating JSON from Tabular Data on the Web&quot;&gt;CSV2JSON&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;an-implementation-in-ruby&quot;&gt;An implementation in Ruby&lt;/h2&gt;

&lt;p&gt;My method for working on specifications is to develop code implementing these specifications as they are being developed. This, of necessity, means that there is a lot of work (and re-work) as the details are being worked out, but I view it as a necessary part of spec development to ensure that the result can be implemented. In this case, this is embodied in the &lt;a href=&quot;http://rubygems.org/gems/rdf-tabular&quot;&gt;rdf-tabular&lt;/a&gt; gem, which implements the &lt;a href=&quot;http://www.w3.org/TR/tabular-data-model/&quot; title=&quot;Model for Tabular Data and Metadata on the Web&quot;&gt;Model for Tabular Data&lt;/a&gt; and &lt;a href=&quot;http://www.w3.org/TR/tabular-metadata/&quot; title=&quot;Metadata Vocabulary for Tabular Data&quot;&gt;Metadata Format&lt;/a&gt; as well as both &lt;a href=&quot;http://w3c.github.io/csvw/csv2rdf/&quot; title=&quot;Generating RDF from Tabular Data on the Web&quot;&gt;CSV2RDF&lt;/a&gt; and &lt;a href=&quot;http://w3c.github.io/csvw/csv2json/&quot; title=&quot;Generating JSON from Tabular Data on the Web&quot;&gt;CSV2JSON&lt;/a&gt; and much of the validation required for these to work. As is true for all &lt;a href=&quot;http://rdf.rubyforge.org/&quot;&gt;RDF.rb&lt;/a&gt; gems, this is available in the public domain (&lt;a href=&quot;http://unlicense.org&quot;&gt;Unlicense&lt;/a&gt;) and is freely usable by anyone wishing to get a start on their own implementation.&lt;/p&gt;

&lt;p&gt;You can try this out on my &lt;a href=&quot;http://rdf.greggkellogg.net/distiller&quot;&gt;RDF Distiller&lt;/a&gt;, or using the &lt;a href=&quot;http://linter.structured-data.org/&quot;&gt;Structured Data Linter&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;test-suite&quot;&gt;Test Suite&lt;/h2&gt;

&lt;p&gt;With updated working drafts, the next phase of the CSVW Working Group will be to develop more tests. There is already a fair &lt;a href=&quot;http://w3c.github.io/csvw/tests/&quot;&gt;Test Suite&lt;/a&gt; available which probes various corner-cases of validating and converting tabular data. There are already over 80 tests defined, and more will be forthcoming in the coming weeks and months. (Disclaimer, these tests have yet to be accepted by the WG).&lt;/p&gt;

&lt;p&gt;A forthcoming blog entry will delve into the basis of a simple implementation, and what it takes to completely conform to the specification.&lt;/p&gt;
</description>
        <pubDate>Thu, 16 Apr 2015 00:00:22 +0000</pubDate>
        <link>https://greggkellogg.net/2015/04/csv-on-the-web/</link>
        <guid isPermaLink="true">https://greggkellogg.net/2015/04/csv-on-the-web/</guid>
        
        <category>CSV</category>
        
        <category>RDF</category>
        
        <category>Ruby</category>
        
        <category>Tabular Data</category>
        
        <category>W3C</category>
        
        
        <category>Ruby</category>
        
        <category>Semantic Web</category>
        
      </item>
    
      <item>
        <title>Release 1.1.0 of Ruby RDF libraries</title>
        <description>&lt;p&gt;I’m happy to announce release 1.1.0 of the Ruby RDF suite, this includes support for RDF 1.1 Concepts and syntaxes, including RDF Literal changes, N-Triples, N-Quads, TriG and JSON-LD. Additionally, the SPARQL gem has been updated to support RDF 1.1 differences (mainly differences in plain literals vs those with xsd:string datatypes and the fact that language-tagged literals now have the rdf:langString datatype).&lt;/p&gt;

&lt;p&gt;There are some incompatibilities with previous releases described below:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Support for Ruby 1.8.* has been eliminated from all gems, however the latest versions of JRuby and Rubninus are supported.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;RDF.rb: &lt;a href=&quot;https://github.com/ruby-rdf/rdf&quot;&gt;https://github.com/ruby-rdf/rdf&lt;/a&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;Works on versions of Ruby &amp;gt;= 1.9.2 (1.8.* support now dropped), this includes JRuby and Rubinius 2.1+ (true for all gems)&lt;/li&gt;
      &lt;li&gt;Support for all RDF 1.1 concepts (other than skolumization, if anyone’s really interested in this, we could add support in a future release),&lt;/li&gt;
      &lt;li&gt;Native implementation of RDF::URI (aka RDF::IRI) without using Addressable::URI; this is actually a big performance win, as URI’s typically don’t need to be parsed now,&lt;/li&gt;
      &lt;li&gt;RDF::Graph cannot take a context (name) unless it is a projection of a named graph from an RDF:: Repository (aka RDF::Dataset),&lt;/li&gt;
      &lt;li&gt;Support for 1.1 versions of N-Triples and N-Quads&lt;/li&gt;
      &lt;li&gt;Support for changes to Literal semantics, meaning that all literals have a datatype. #plain? and #simple? accessors still exist, which have expected results.&lt;/li&gt;
      &lt;li&gt;RDF::Query#execute now accepts a block and returns RDF::Query::Solutions. This allows enumerable.query(query) to be have like query.execute(enumerable) and either return an enumerable of yield each solution.&lt;/li&gt;
      &lt;li&gt;RDF::Queryable#query returns a concrete Enumerator extending RDF::Queryable and RDF::Enumerable or RD::Query::Solutions; this improves performance when accessing enumerator methods as they’re not extended dynamically (see issue #123: “Performance and Kernel#extend”)&lt;/li&gt;
      &lt;li&gt;RDF::Util::File.open_file (used for Mutable.load, among others) no honors 303 and Location: headers to maintain the source identifier and try to manage all input data as UTF.&lt;/li&gt;
      &lt;li&gt;RDF::StrictVocabulary is now added as a sub-class of RDF::Vocabulary; most built-in vocabularies are now strict, meaning that an attempt to access a term not defined in the vocabulary will raise an error. Many more vocabuarlies added including iCal, Media Annotations, Facebook OpenGraph, PROV, SKOS-XL, Data Vocabulary, VCard, VOID, Power-S, XHV and schema.org.&lt;/li&gt;
      &lt;li&gt;New vocabulary definitions have been added for ICal, Media Annotations (MA), Facebook OpenGraph (OG), PROV, SKOS-XL (SKOSXL), Data Vocabulary (V), VCard, VOID, Powder-S (WDRS), and XHV.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;RDF::N3: &lt;a href=&quot;https://github.com/ruby-rdf/rdf-n3&quot;&gt;https://github.com/ruby-rdf/rdf-n3&lt;/a&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;No longer detects formats when a specific content type is not known; this prevents problems interpreting Turtle as N3.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;RDF::RDFXML: &lt;a href=&quot;https://github.com/ruby-rdf/rdf-rdfxml&quot;&gt;https://github.com/ruby-rdf/rdf-rdfxml&lt;/a&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;Now fully supports JRuby; previously, the writer only worked on MRI and Rubinius. Writer now uses Haml templates, and extends the RDFa writer.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;RDF::Turtle: &lt;a href=&quot;https://github.com/ruby-rdf/rdf-turtle&quot;&gt;https://github.com/ruby-rdf/rdf-turtle&lt;/a&gt;, RDF::TriG: &lt;a href=&quot;https://github.com/ruby-rdf/rdf-trig&quot;&gt;https://github.com/ruby-rdf/rdf-trig&lt;/a&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;Full support for RDF 1.1 specifications&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;SPARQL: &lt;a href=&quot;https://github.com/ruby-rdf/sparql&quot;&gt;https://github.com/ruby-rdf/sparql&lt;/a&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;All query operators now accept a block for returning solutions in addition to returning the RDF::Query::Solutions.&lt;/li&gt;
      &lt;li&gt;Specific Queryable implementations can now optimize any part of the SPARQL Algebra execution chain by implementing the appropriate operator as all calls go through the RDF::Queryable object. This can be used by specific storage adaptors to implement part or all of the query chain using implementation-specific optimizations.&lt;/li&gt;
      &lt;li&gt;Minor test harness changes to tollerate RDF 1.1 changes.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Rack::LinkedData, Sinatra::LinkedData, Rack::SPARQL, Rack::Sinatra&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;All updated for latest versions of Rack and Sinatra. Note that Sinatra does not support returning the enumerable without a content type for content-negotiated serialization of the results, as Sinatra defaults results to text/html. Use linkeddata_options (or sparql_options) to set desired content type or format of result. Prioritized ACCEPT types provided through environment.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All gems now support only Ruby &amp;gt;= 1.9.2, JRuby and Rubinius.&lt;/p&gt;

&lt;p&gt;This includes the following individual gems:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Core RDF and repositories:&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;rdf&lt;/li&gt;
      &lt;li&gt;rdf-aggregate-repo&lt;/li&gt;
      &lt;li&gt;rdf-do&lt;/li&gt;
      &lt;li&gt;rdf-isomorphic&lt;/li&gt;
      &lt;li&gt;rdf-mongo&lt;/li&gt;
      &lt;li&gt;rdf-spec&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;RDF Serialization formats&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;json-ld&lt;/li&gt;
      &lt;li&gt;rdf-json&lt;/li&gt;
      &lt;li&gt;rdf-microdata&lt;/li&gt;
      &lt;li&gt;rdf-n3&lt;/li&gt;
      &lt;li&gt;rdf-raptor&lt;/li&gt;
      &lt;li&gt;rdf-rdfa&lt;/li&gt;
      &lt;li&gt;rdf-rdfxml&lt;/li&gt;
      &lt;li&gt;rdf-trig&lt;/li&gt;
      &lt;li&gt;rdf-trix&lt;/li&gt;
      &lt;li&gt;rdf-turtle&lt;/li&gt;
      &lt;li&gt;rdf-xsd&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Querying&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;sparql&lt;/li&gt;
      &lt;li&gt;sparql-client&lt;/li&gt;
      &lt;li&gt;spira&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Rollup releases, including most of the above gems&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;linkeddata&lt;/li&gt;
      &lt;li&gt;rack-linkeddata&lt;/li&gt;
      &lt;li&gt;sinatra-linkeddata&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All versions of this are running on my distiller: &lt;a href=&quot;http://rdf.greggkellogg.net/&quot;&gt;http://rdf.greggkellogg.net/&lt;/a&gt;. Any comments or issues found prior to release are appreciated.&lt;/p&gt;

&lt;p&gt;I’d like to thank David Butler, Judson Lester, Justin Coyne, Slava Kravchenko, and Aymeric Brisse in particular for their active support in maintaining the Ruby RDF eco-system.&lt;/p&gt;
</description>
        <pubDate>Fri, 06 Dec 2013 20:59:03 +0000</pubDate>
        <link>https://greggkellogg.net/2013/12/release-1-1-0-of-ruby-rdf-libraries/</link>
        <guid isPermaLink="true">https://greggkellogg.net/2013/12/release-1-1-0-of-ruby-rdf-libraries/</guid>
        
        
        <category>Ruby</category>
        
        <category>Semantic Web</category>
        
      </item>
    
      <item>
        <title>Philippines September 2013</title>
        <description>&lt;p&gt;I had a great dive in the Philippines diving at &lt;a href=&quot;http://atmosphereresorts.com&quot;&gt;Atmosphere Resort&lt;/a&gt; in Negros Oriental and &lt;a href=&quot;http://amunini.com&quot;&gt;Amun Ini&lt;/a&gt; in Bohol. This was really a great opportunity for some warm-water macro-photography, and as I had not even brought a wide-angle lens, this is where I &lt;em&gt;focused&lt;/em&gt;. Enjoy the &lt;a href=&quot;https://lightroom.adobe.com/gallery/7b25cc9c355b4a5dbc0e0e2c81bdd444/albums/33183a6765534ef68446718b9f2e1d66/assets&quot;&gt;photo gallery&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://lightroom.adobe.com/gallery/7b25cc9c355b4a5dbc0e0e2c81bdd444/albums/33183a6765534ef68446718b9f2e1d66/assets&quot; jscontroller=&quot;false&quot; rel=&quot;qtposter&quot;&gt;&lt;img alt=&quot;Philippines Photo Gallery&quot; src=&quot;/galleries/Philippines-2013-09/content/images/large/_MG_8582.jpg&quot; style=&quot;width: 535px; height: 311px;&quot; /&gt; &lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Fri, 27 Sep 2013 16:37:13 +0000</pubDate>
        <link>https://greggkellogg.net/2013/09/philippines-september-2013/</link>
        <guid isPermaLink="true">https://greggkellogg.net/2013/09/philippines-september-2013/</guid>
        
        
        <category>Diving</category>
        
        <category>Photography</category>
        
      </item>
    
      <item>
        <title>RDF.rb and SPARQL gem updates</title>
        <description>&lt;p&gt;&lt;span itemprop=&quot;name&quot; style=&quot;display:none&quot;&gt;RDF.rb and SPARQL updates&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span itemprop=&quot;description&quot;&gt;Version 1.0.6 of RDF.rb and 1.0.7 of SPARQL gems released.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;I recently pushed updates to &lt;a href=&quot;http://rubygems.org/gems/rdf&quot;&gt;RDF.rb&lt;/a&gt; and &lt;a href=&quot;http://rubygems.org/gems/sparql&quot;&gt;SPARQL&lt;/a&gt; gems. These updates contain some useful new features:&lt;/p&gt;

&lt;h2 id=&quot;rdfrb&quot;&gt;RDF.rb&lt;/h2&gt;

&lt;p&gt;The main RDF gem has many updates to bring it closer to the coming update to the RDF 1.1 specifications (&lt;a href=&quot;http://www.w3.org/TR/rdf11-concepts/&quot;&gt;RDF Concepts&lt;/a&gt;, &lt;a href=&quot;http://www.w3.org/TR/rdf11-mt/&quot;&gt;RDF Semantics&lt;/a&gt;, &lt;a href=&quot;http://www.w3.org/TR/turtle/&quot;&gt;Turtle&lt;/a&gt;, &lt;a href=&quot;http://www.w3.org/TR/trig/&quot;&gt;TriG&lt;/a&gt; &lt;a href=&quot;http://www.w3.org/TR/n-triples/&quot;&gt;N-Triples&lt;/a&gt;, &lt;a href=&quot;http://www.w3.org/TR/n-quads/&quot;&gt;N-Quads&lt;/a&gt;, and &lt;a href=&quot;http://json-ld.org/spec/latest/&quot;&gt;JSON-LD&lt;/a&gt;). Notable changes since the 1.0 release are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Make distinction between Plain and Simple literals; Simple literals have no language, plain literals may also have a language. And, in preparation for RDF 1.1, literals having a datatype of xsd:string are considered Simple literals. Language-tagged literals may have a datatype of rdf:langString.&lt;/li&gt;
  &lt;li&gt;Improved support for queries using hash patterns (thanks to @markborkum).&lt;/li&gt;
  &lt;li&gt;Update &lt;a href=&quot;http://www.w3.org/TR/n-triples/&quot;&gt;N-Triples&lt;/a&gt; (and &lt;a href=&quot;http://www.w3.org/TR/n-quads/&quot;&gt;N-Quads&lt;/a&gt;) readers and writers to support the RDF 1.1 version, including new escape sequences and support for UTF-8, in addition to ASCII. When writing characters are escaped depending on the specified encoding or that inferred from the output file.&lt;/li&gt;
  &lt;li&gt;Term and Statement comparison is dramatically improved improving statement insertion and query performance.&lt;/li&gt;
  &lt;li&gt;Other literal changes required to support SPARQL 1.1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the 1.1 branch:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;RDF::URI re-written to not require Addressable. This improves general performance of using URIs by about 50% (depends on 1.9+ features, so not included in the 1.0 branch).&lt;/li&gt;
  &lt;li&gt;Support for Ruby versions less than 1.9.2 is dropped.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;sparql&quot;&gt;SPARQL&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;http://rubygems.org/gems/sparql&quot;&gt;SPARQL&lt;/a&gt; gem is not based on the SPARQL 1.1 grammar, and now includes some features from SPARQL 1.1, including all functions and builtins and variable bindings. Look for new features to be added incrementally; once a critical mass is reached, I’ll update the gem version to 1.1 to reflect that this is essentially a 1.1 compatible version of SPARQL. Eventually this will include SPARQL Update and Federated Queries as well.&lt;/p&gt;

&lt;h2 id=&quot;other-gems&quot;&gt;Other gems&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://rubygems.org/gems/json-ld&quot;&gt;JSON::LD&lt;/a&gt; is released as version 1.0.0 and is full compatible with the last-call version of the &lt;a href=&quot;http://json-ld.org/spec/latest/&quot;&gt;JSON-LD&lt;/a&gt; specifications, including support for framing.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://rubygems.org/gems/rdf-turtle&quot;&gt;RDF::Turtle&lt;/a&gt; is fully compatible with the RDF 1.1 version.
    &lt;ul&gt;
      &lt;li&gt;Also includes a &lt;a href=&quot;https://developers.google.com/freebase/data&quot;&gt;Freebase&lt;/a&gt;-specific reader for fastest performance reading Freebase dumps.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://rubygems.org/gems/rdf-rdfa&quot;&gt;RDF::RDFa&lt;/a&gt; is compatible with &lt;a href=&quot;http://www.w3.org/TR/rdfa-core/&quot;&gt;RDFa Core 1.1&lt;/a&gt; and &lt;a href=&quot;http://www.w3.org/TR/rdfa-in-html/&quot;&gt;HTML+RDFa 1.1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://rubygems.org/gems/rdf-trig&quot;&gt;RDF::TriG&lt;/a&gt; is released as a 1.0.0 version, based on the RDF 1.1 note&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://rubygems.org/gems/rdf-raptor&quot;&gt;RDF::Raptor&lt;/a&gt; now uses Raptor 2.0, and is fully compatible with the latest version of &lt;a href=&quot;http://librdf.org/raptor/&quot;&gt;Redland/Raptor&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Sat, 11 May 2013 23:12:21 +0000</pubDate>
        <link>https://greggkellogg.net/2013/05/rdf-rb-and-sparql-gem-updates/</link>
        <guid isPermaLink="true">https://greggkellogg.net/2013/05/rdf-rb-and-sparql-gem-updates/</guid>
        
        
        <category>Ruby</category>
        
        <category>Semantic Web</category>
        
      </item>
    
  </channel>
</rss>
