ちょっとしたメモ

JSONではじめるRDF/Turtle(3) - 型付ノード

JSONは基本的に「名前:値」のペアでデータを表現するが、RDFは「主語‐述語‐目的語」のトリプルが単位になる。ここで、JSONのオブジェクト記法 {} をRDF/Turtleの [] と読み替え、主語が空白ノードであるトリプルとして扱うことで、両者はあるていど相互に往き来することが可能だ。しかし、リソースに「型」情報を持たせたRDF/XMLの「型付ノード要素」を考えるとき、この読み替えには多少の工夫が必要になる。

改めて、空白ノードを主語にした最初のグラフを見てみよう。

[]--studentid-->'10108068'; --name-->'John Barleycorn'

この主語リソースには、2つのプロパティがあるが、特に何らか「型」は持っていない。このノードは、RDF/XMLでは普通に <rdf:Description> 要素で記述される。

[例1]

<rdf:Description>
  <studentid>10108068</studentid>
  <name>John Barleycorn</name>
</rdf:Description>

この主語が「学生」という「型」を持つ(Studentクラスのインスタンスである)ことを表現したくなったとしよう。このとき、RDF/XMLでは「型付ノード要素」を利用することができる。<rdf:Description> の代わりに <Student> 要素を記述するという方法だ。

[例2]

<Student>
  <studentid>10108068</studentid>
  <name>John Barleycorn</name>
</Student>

RDF/XMLではStudentはクラスとして扱われるので、型(rdf:type)を表すトリプルが一つ加わって、次のグラフが得られる(このように型情報を持つノードを型付ノードと呼ぶ)。

[]--rdf:type-->[Student]; --studentid-->'10108068'; --name-->'John Barleycorn'

さて、一方で、例2のような入れ子構造のXMLをJSONに翻訳すると、一般には次のような形になるだろう。

[例3]

{
  "Student": {
    "studentid": "10108068",
    "name": "John Barleycorn"
  }
}

これを今までと同様に単純にTurtleに置き換えるとどうなるか。

[例4]

[
  :Student [
    :studentid "10108068";
    :name "John Barleycorn"
  ]
] .

JSONとTurtleの対応関係は本来この通りなのだが、実はこれではRDFグラフが例2とは異なったものになってしまう(プロパティを修飾名で略記)。

[]--Student-->[]--studentid-->'10108068'; --name-->'John Barleycorn'

元のグラフではrdf:typeの目的語としてクラスを表していたStudentが、ここではプロパティに置き換わってしまっている。Turtleでは [] が入れ子になるとその分だけ空白ノードが増えていき、述語部分がクラスとして扱われることはないのだ。このグラフは、RDF/XMLでいえば、次のようにrdf:parseType="Resource"を用いたものに相当する。

[例5]

<rdf:Description>
  <Student rdf:parseType="Resource">
    <studentid>10108068</studentid>
    <name>John Barleycorn</name>
  </Student>
</rdf:Description>

例2のRDFを表現するTurtleは、グラフの3つのトリプルをそのまま書く。

[例6]

[
  a :Student;
  :studentid "10108068";
  :name "John Barleycorn"
] .

ここで、Turtleの a は、rdf:type の省略記法で、この空白ノードがStudentクラスのインスタンスであることを表す(N3で用いる a と同じ)。rdf:type と書くのに比べてコンパクトであることに加え、他で必要なければrdf:の名前空間を宣言しなくてよいので、いっそう簡潔に表現できる便利な道具だ。

まとめると、

  1. RDFではしばしば型情報をもつ型付ノードが現れる
  2. これを記述するとき、TurtleではXML/RDFの「型付ノード要素」のような構文はなく、型を示すトリプルを素直に加える
  3. その型情報トリプル記述の簡便法として、 a が用意されている

ということ。以上が、JSON経由で回り道をしながらの、型付ノードとTurtleの紹介だ。

今度は、JSONからRDF/Turtleを取り出すという側面から型付ノードを考えてみよう。

例3のJSONから例6のTurtleを得るには、Studentがクラスを表していることを知る必要がある。しかし、XMLの要素がプロパティかクラス(型付ノード要素)かということはRDF側のみの理屈であるのと同様、JSONのプロパティはどこまで行ってもプロパティであって、それをRDFクラスとして扱うかどうかを決める方法は、JSONの構文にはない。RDF/XMLに準じて、"rdf:parseType": "Resource" といったハッシュ値をデータに加えておけば区別は可能になるが、そもそもRDFを念頭に置いていない普通のJSONデータをRDF/Turtleとして扱おうというのだから、これも非現実的だ。

一つの案としては、JSONオブジェクトのプロパティ名が大文字で始まっていたらクラスと見なし、Turtleの変換に際して異なる扱いをするという方法が考えられる。RDFでは、クラス名を大文字で始め、プロパティ名は小文字で始めることが多いからだ。しかしXML一般では、要素名の最初は常に大文字ということも珍しくないから、これらを全てクラス扱いするのではなく、“入れ子になって連続したら内側は通常通りRDFのプロパティとみなす”といった補助ルールも用意する必要があるだろう。

  • 大文字で始まるJSONプロパティは、RDFのクラスとして扱う。
  • ただし大文字で始まるプロパティが入れ子になったら、内側はRDFプロパティとして扱う。

ウェブサービスなどで用いられるXMLを変換したJSONでは、これがあてはまるケースがしばしば見られる。

[例7]

{
  "ListingInfo": {
    "Request": {
      "Parameters": {
        "Parameter": {
          "name": "enc",
          "value": "Shift_JIS"
        }
      }
    }
  }
}

このJSONデータを、大文字ルールを採用してTurtleに変換してみたものが次の例だ。

[例8]

[
  a :ListingInfo;
  :Request [
    a :Parameters;
    :Parameter [
      :name "enc";
      :value "Shift_JIS"
    ]
  ]
] .

RDFのグラフを描くと、次のようになってクラス(型)とプロパティの関係は結構うまく行っているように見える。

[]--rdf:type-->[ListingInfo]; --Request-->[]--rdf:type-->[Parameters];--Parameter-->[]--name-->'enc'; --value-->'Shift_JIS'

ややこしい条件判断などせずに、単純にJSONのプロパティを全てRDFプロパティにしていくほうがいいという考え方もあるだろう。ただ、そうした形で変換したRDFは、元のデータ設計の考えが反映されなかったり、冗長で使い物にならないことが多い。いろいろ試してみたところでは、特にXML由来のJSONからRDFをうまく取り出すには多少こうした工夫が必要に思われる。そして、ここをクリアすれば、それなりに実用的に使えるんじゃないかという気もしている。

関連メモ:
map - genre: rdf, js. at