[8] [DFN[N-Triples]]
は、
[[RDF]]
の記述形式の1つです。


* 仕様書

[REFS[
- [7] [CITE@en[RDF 1.1 N-Triples]], [TIME[2017-10-02T10:49:40.000Z]], [TIME[2021-01-11T07:07:48.024Z]] <https://www.w3.org/TR/n-triples/>
]REFS]


* 構文

[26] 
適合[DFN[N-Triples[RUBY[文書][ぶんしょ][document]]]]
([DFN[[CODE[ntriplesDoc]]]])
は、
仕様書の該当する文法と制約に適合する
[[Unicode文字列]]です。
[[N-Triples文書]]は、
[[RDFグラフ]]を[[直列化]]したものです。
[SRC[>>7]]

[19] 
構文にはある程度の自由度がありますが、
実装は[[正準形]]である 
[DFN[Canonical N-Triples]]
を出力することが[RUBYB[[[推奨]]][encourage]]されています。
[SRC[>>7]]

[27] 
適合[DFN[[RUBY[正準][せいじゅん][Canonical]]N-Triples[RUBYB[文書][document]]]]は、
[[Canonical N-Triples]]
の追加の制約に従う[[N-Triples文書]]です。
[SRC[>>7]]

[38] [[N-Triples文書]]は、
0個[[以上]]の[[三項組]]を、
[[改行]]で区切ったものです。
ただし、先頭行と最終行は[[空行]]にできます。
[SRC[>>7]]

[71] 
[[構文解析器]]は、
[[三項組]]を処理した結果で構成される[[RDFグラフ]]を返します。
[SRC[>>7]]

[FIG(railroad)[ [39] [[N-Triples文書]]
= ?
== *
=== [VAR[空白]]
== [VAR[三項組]]
= *
== *
=== [VAR[空白]]
== [VAR[改行]]
== *
=== [VAR[空白]]
== [VAR[三項組]]
= ?
== *
=== [VAR[空白]]
== [VAR[改行]]
= *
== [VAR[空白]]
]FIG]

[49] 
[[改行]]は、
[CODE[U+000D]],
[CODE[U+000A]]
の1つ[[以上]]の列です。
[SRC[>>7]]

;; [50] この定義では[[空行]]は認められますが、
[[空白]]だけが含まれる[[行]]は認められません。

[FIG(railroad)[ [51] [VAR[改行]]
= +
== |
=== [CODE[U+000D]]
=== [CODE[U+000A]]

]FIG]

[REFS[
- [87] 改行の文字一覧 <https://chars.suikawiki.org/set/%24rdf11%3Antriples%3AEOL-char>
]REFS]

[77] 
[[構文解析器]]が [[N-Triples文書]]でない [[Unicode文字列]]を与えられた時、
どう動作するべきかは不明です。

** 三項組

[10] 
[RUBYB[単純三項組][simple triple]]は、
([[主語]]、[[述語]]、[[目的語]]) の[RUBYB[[[語]]][term]]を、
[[空白]]で区切って、
最後に
[CODE[.][FULL STOP]]
を付けたものです。
[SRC[>>7]]

[20] 
正準形では、
3項の間の[[空白]]は [CODE[U+0020]] 1つでなければ[MUST[なりません]]。
それ以外はあっては[MUST[なりません]]。
[SRC[>>7]]

[70] 
[[構文解析器]]は、
[[主語]]、[[述語]]、[[目的語]]を処理した結果から構成される[[三項組]]を返します。
[SRC[>>7]]


[FIG(railroad)[[40] [VAR[三項組]]
= [VAR[主語]]
= *
== [VAR[空白]]
= [VAR[述語]]
= *
== [VAR[空白]]
= [VAR[目的語]]
= *
== [VAR[空白]]
= [CODE[.][FULL STOP]]

]FIG]

[41] 
[[主語]]は、
[[IRI]]
または[[空白節点ラベル]]です。
[SRC[>>7]]

[FIG(railroad)[ [44] [VAR[主語]]
= |
== [VAR[IRI]]
== [VAR[空白節点ラベル]]
]FIG]

[42] 
[[述語]]は、 [[IRI]] です。 [SRC[>>7]]

[FIG(railroad)[ [45] [VAR[述語]]
= [VAR[IRI]]
]FIG]

[43] 
[[目的語]]は、 [[IRI]] または [[空白節点ラベル]]または[[リテラル]]です。
[SRC[>>7]]

[FIG(railroad)[ [46] [VAR[目的語]]
= |
== [VAR[IRI]]
== [VAR[空白節点ラベル]]
== [VAR[リテラル]]
]FIG]


[18] 
[[空白節点]]は、
[CODE[_:]] に[[空白節点ラベル]]を続けて記述します。
同じ[[空白節点ラベル]]を持つもの同士が同じ[[空白節点]]と解釈されます。
[SRC[>>7]]

[69] 
[[構文解析器]]は、
[[空白節点ラベル]]の [CODE[_:]]
の後の[[文字列]]を[VAR[鍵]]とします。
[CODE[bnodeLabels]] [ [VAR[鍵]] ]
があれば、それを使います。
なければ、それを新しい[[空白節点]]とします。
[SRC[>>7]]


** 空白

[35] 
[RUBYB[[[空白]]][white space]]は、
[CODE[U+0009]],
[CODE[U+0020]],
[[注釈]]です。
[SRC[>>7]]

[36] 
[[空白]]は、[[終端記号]]間の区切りとして挿入できます。
仕様書にはそれがなければ誤認識されるところで使える [SRC[>>7]]
としか書かれていないのですが、それ以外でも挿入できそうな[[ふいんき]]です。

[21] 
正準形では、
[[三項組]]に関するもの (>>20) を除き、
字句間の[[空白]]を挿入しては[MUST[なりません]]。
[SRC[>>7]]

[FIG(railroad)[ [78] [[空白]]
= |
== [CODE[U+0009]]
== [CODE[U+0020]]
== [VAR[注釈]]
]FIG]

[REFS[
- [103] 空白の文字の一覧
<https://chars.suikawiki.org/set/%24rdf11%3Antriples%3Awhite-space>
]REFS]

[37] 
[RUBYB[注釈][comment]]は、
[CODE[#]]
から次の[[改行]]まで、なければ[[ファイル末]]までです。
[SRC[>>7]]

[22] 
正準形では、
[[注釈]]を挿入しては[MUST[なりません]]。
[SRC[>>7]]

[FIG(railroad)[ [79] [[注釈]]
= [CODE[#]]
= *
== [VAR[改行以外の文字]]
= ?
== [VAR[改行]]
]FIG]

[80] 
仕様書は行間を読むことを求めて明記していないようですが、
[[字句]]間の[[空白]]は[[構文解析器]]が[[字句化]]段階で捨てて、無視します。

** リテラル


[12] 
[[リテラル][RDFリテラル]]は、
[[字句形]]の後に、
[[言語タグ]]か[[データ型IRI]]を書くか、
何も書きません。
[SRC[>>7]]

[67] 
[[構文解析器]]は、構成する[[字句]]から[[三項組]]を得ます。
[SRC[>>7]]

[FIG(list members)[ [68] [[三項組]]
: [F[字句形]] : [VAR[字句形]]から得た[[字句形]]
: [F[データ型IRI]] : [VAR[リテラル]]から決まる[[データ型]]
: [F[言語タグ]] : [VAR[言語タグ]]から決まる[[言語タグ]] (あれば)
]FIG]

[FIG(railroad)[ [47] [[リテラル]]
= [VAR[字句形]]
= ?
== |
=== =
==== *
===== [VAR[空白]]
==== [CODE[^^]]
==== *
===== [VAR[空白]]
==== [[IRI]]
=== =
==== *
===== [VAR[空白]]
==== [[言語タグ]]


]FIG]

[13] 
[[字句形]]は、
[CODE["]] で囲んで書きます。
[[数値エスケープシーケンス]]か[[文字列エスケープシーケンス]]を使えます。
[SRC[>>7]]

[14] 
[[リテラル]]では、
[CODE["]],
[CODE(charname)@en[CR]],
[CODE(charname)@en[LF]],
[CODE[\]]
をそのまま書けません。
[SRC[>>7]]

[81] 
[[N-Triples]] としての要件ではありませんが、
[[RDFリテラル]]としてのデータモデル側の規定で、
[[字句形]]は [[NFC]] である[SHOULD[べき]]とされています。
[SEE[ [[RDFリテラル]] ]]
[[NFC]] は破壊的な操作で、任意の[[自然言語]]文を扱うのは危険です。
[SEE[ [[正規化]] ]]
[[N-Triples]] としては何の規定もないので素通しするのが妥当な実装でしょうが、
その前後の [[RDF]] としての処理の段階でどう扱われるか不安が残ります。

[64] 
[[構文解析器]]は、
[CODE["]] の間の[[文字列]]を取り出し、
[[エスケープシーケンス]]を
[[unescape]]
して、
[[字句形]]を得ます。
[SRC[>>7]]

[FIG(railroad)[ [63] [VAR[字句形]]
= [CODE["]]
= *
== |
=== [VAR[リテラルの文字]]
=== [VAR[ECHAR]]
=== [VAR[UCHAR]]
= [CODE["]]

]FIG]

[REFS[
- [88] リテラルの文字一覧
<https://chars.suikawiki.org/set/%24rdf11%3Antriples%3ASTRING_LITERAL_QUOTE-char>
]REFS]

[15] 
[[言語タグ]]を書くときは、前に [DFN[[CODE[@]]]] を書きます。
[SRC[>>7]]

[82] [[RDFリテラル]]としてのデータモデルの規定では、
[[整形式]]の[[IETF言語タグ]]でなければならないとされています。
[[N-Triples]] としてはそれよりも緩い構文になっており、
[[N-Triples]] の実装はそれを扱える必要があるのでしょうが、
その前後の [[RDF]] としての処理で、非[[整形式]]の[[言語タグ]]がどう扱われるか不確かです。

[65] 
[[構文解析器]]は、
[CODE[@]]
の後の[[文字列]]を取り出し、
[[言語タグ]]を得ます。
[SRC[>>7]]

[FIG(railroad)[ [48] [VAR[言語タグ]]
= [CODE[@]]
= +
== [[ASCII英字]]
= *
== [CODE[-]]
== +
=== [[ASCII英数字]]
]FIG]

[REFS[
- [101] 言語タグの最初の部分タグの文字の一覧
<https://chars.suikawiki.org/set/%24rdf11%3Antriples%3ALANGTAG-first>
- [102] 言語タグの2つ目以降の部分タグの文字の一覧
<https://chars.suikawiki.org/set/%24rdf11%3Antriples%3ALANGTAG-nonfirst>
]REFS]

[16] 
[[データ型IRI]]を書くときは、
前に [DFN[[CODE[^^]]]] を書きます。
[SRC[>>7]]

[17] 
[[データ型IRI]]も[[言語タグ]]もないときは、
[[単純リテラル]]を表し、
[[データ型]]は 
[CODE[http://www.w3.org/2001/XMLSchema#string]]
となります。
[SRC[>>7]]

[66] [[言語タグ]]があるときは、
[[データ型]]は
[CODE[rdf:langString]]
となります。
[SRC[>>7]]

** IRI

[11] 
[[IRI]]
は、
[[絶対IRI]]
を
[CODE[<]]
と
[CODE[>]]
で囲んで書きます。
[[数値エスケープシーケンス]]を使えます。
[SRC[>>7]]

[53] 
構文上は[[空文字列]]も[[相対IRI]]も書けますが、
[[絶対IRI]]を書くという規定になっています。

[54] 
[[IRI]] では、
[[CL]],
[CODE[U+0020]],
[CODE[<]],
[CODE[>]],
[CODE["]],
[CODE[{]],
[CODE[}]],
[CODE[|]],
[CODE[^]],
[CODE[`]],
[CODE[\]]
はそのままでは書けません。
[SRC[>>7]]


[83] 
[[絶対IRI]]でないものを [[N-Triples]] として構文的には扱えるので、
[[N-Triples]] の実装はそれを扱えないといけないと思われますが、
その前後の [[RDF]] としての処理でこれがどうなるのかは不明です。


[62] 
[[構文解析器]]は、
[CODE[<]] と [CODE[>]]
の間の[[文字列]]を取り出し、
[[エスケープシーケンス]]を
[[unescape]]
して、
[[IRI]]
を得ます。
[SRC[>>7]]

[FIG(railroad)[ [52] [VAR[IRI]]
= [CODE[<]]
= *
== |
=== [VAR[IRIの文字]]
=== [VAR[UCHAR]]
= [CODE[>]]

]FIG]

[REFS[
- [89] IRIの文字一覧
<https://chars.suikawiki.org/set/%24rdf11%3Antriples%3AIRIREF-char>
]REFS]



** エスケープシーケンス

[75] 
[[エスケープシーケンス]]は [[Turtle]]
と同じと規定されています [SRC[>>7]]。


[33] 
[[MIME型]]を [CODE(MIME)@en[text/plain]]
とするときは、
[[US-ASCII]]
以外の文字は[[エスケープシーケンス]]としなければ[MUST[なりません]]。
[SRC[>>7]]

[84] という文書に対する要件はありますが、
[[構文解析器]]が[[非ASCII文字]]に遭遇した時どう処理するべきか不明です。

-*-*-

[55] 
[DFN[[CODE[UCHAR]]]]
は、
[CODE[\u]] の後に4桁の[[十六進数]]を続けたものか、
[CODE[\U]] の後に8桁の[[十六進数]]を続けたものです。
[SRC[>>7]]

[23] 
正準形では、
[[十六進数]]は[[大文字]]でなければ[MUST[なりません]]。
[SRC[>>7]]

[24] 
正準形では、
[[文字]]を [CODE[UCHAR]] としては[MUST[なりません]]。
[SRC[>>7]]

[85] [[構文解析器]]が、
[CODE[U-00110000]] [[以上]]の値が与えられたときや、
[[サロゲート符号点]]が与えられた時、どうするべきかは不明です。
[[Turtle]] の仕様書は
「A Unicode character in the range U+0000 to U+10FFFF inclusive」
と意味を定義しているので、それらの意味は未定義なのですが、
構文上それを禁止する規定もありません。

[58] [[リテラル]]の[[字句形]]と [[IRI]] で使えます。

[FIG(railroad)[ [56] [VAR[UCHAR]]
= |
== =
=== [CODE[\u]]
=== [VAR[十六進数]]
=== [VAR[十六進数]]
=== [VAR[十六進数]]
=== [VAR[十六進数]]
== =
=== [CODE[\U]]
=== [VAR[十六進数]]
=== [VAR[十六進数]]
=== [VAR[十六進数]]
=== [VAR[十六進数]]
=== [VAR[十六進数]]
=== [VAR[十六進数]]
=== [VAR[十六進数]]
=== [VAR[十六進数]]

]FIG]

[REFS[
- [90] 十六進数の文字一覧
<https://chars.suikawiki.org/set/%24rdf11%3Antriples%3AHEX>
]REFS]

[57] 
[DFN[[CODE[ECHAR]]]]
は、
[CODE[\t]],
[CODE[\b]],
[CODE[\n]],
[CODE[\r]],
[CODE[\f]],
[CODE[\"]],
[CODE[\']],
[CODE[\\]]
のいずれかです。
[SRC[>>7]]

[59] [[リテラル]]の[[字句形]]で使えます。


[25] 
正準形では、
[CODE["]],
[CODE[\]],
[CODE(charname)@en[CR]],
[CODE(charname)@en[LF]]
''以外''の[[文字]]を
[CODE[ECHAR]]
としては[MUST[なりません]]。
[SRC[>>7]]

[REFS[
- [100] [CODE[ECHAR]] の2文字目の一覧
<https://chars.suikawiki.org/set/%24rdf11%3Antriples%3AECHAR-2>
]REFS]

* 文字コード

[34] [[UTF-8]] で符号化します。 [SRC[>>7]]

[72] 
[[UTF-8]] として不正な入力が与えられた時の[[構文解析器]]の挙動は規定がなく不明です。

* 処理

[28] 
適合[DFN[N-Triples[RUBYB[構文解析器][parser]]]]は、
[[応用]]のために[[N-Triples文書]]を読む能力を擁するシステムです。
何らかの形の [[API]] によって、[[応用]]に対して、
[[N-Triples文書]]として[[直列化]]された [[RDFグラフ]]の情報を提供します。
[SRC[>>7]]

[60] 
[[構文解析器]]は、次の状態を持ちます。

[FIG(list members)[ [61] [[N-Triples構文解析器]]

: [DFN[[F[[CODE[bnodeLabels]]]]]] : 
[[文字列]]から[[空白節点]]への[[写像]]。

]FIG]


[76] 
[[正準N-Triples文書]]が規定されていますが、相当する[[構文解析器]]は規定されていません。
[[正準形]]しか受理しない実装は想定されていないようです。



* MIME型

[30] [[MIME型]]は [DFN[[CODE[application/n-triples]]]]
です。
[SRC[>>7]]


[32] 
歴史的に [CODE(MIME)@en[text/plain]] も使われてきました。
その場合構文上の制約があります (>>33)。
ただしそれは[[N-Triples文書]]ではないとされます。
[SRC[>>7]]



[31] 
[[N-Triples]] 
は
[[Turtle]]
の[[部分集合]]であることから、
[[N-Triples文書]]の[[MIME型]]を
[CODE(MIME)@en[text/turtle]]
としても[MAY[よい]]とされます。
ただしそれは
[[N-Triples文書]]ではないとされます。
[SRC[>>7]]
([[哲学]])

* 識別子

[29] 識別用の [[URL]]
は
[DFN[[CODE[http://www.w3.org/ns/formats/N-Triples]]]]
とされています。
[SRC[>>7]]

[73] 
[[拡張子]]は
[DFN[[CODE[.nt]]]]
です。
[SRC[>>7]]

[74] [[Macintoshファイル型]]は [CODE[TEXT]]
です。
[SRC[>>7]]


* 関連

[9] 
[[N3]]
の[[部分集合]]とされています。

* 歴史

[6] 
[[RDF 1.0]]
時代はテスト記述用のおまけのような扱いだったのが、
[[RDF 1.1]]
で独立した[[W3C勧告]]に格上げされたようです。


[1] [CITE@en[RDF 1.1 N-Triples]]
( ([TIME[2013-11-06 00:20:56 +09:00]] 版))
<http://www.w3.org/TR/2013/CR-n-triples-20131105/>

[2] [CITE@en[RDF 1.1 N-Triples]]
( ([TIME[2014-02-18 21:53:43 +09:00]] 版))
<http://www.w3.org/TR/2014/REC-n-triples-20140225/>

[3] [CITE@en[RDF 1.1 N-Triples]]
( ([TIME[2014-02-18 21:53:43 +09:00]] 版))
<http://www.w3.org/TR/n-triples/>

[4] [CITE@en[RDF Test Cases]]
( ([TIME[2014-02-25 15:16:38 +09:00]] 版))
<http://www.w3.org/TR/2004/REC-rdf-testcases-20040210/#ntriples>

[FIG(quote)[
[FIGCAPTION[
[5] [CITE@en-US[Documentation | HyperGraphQL]]
([TIME[2018-04-06 04:03:29 +09:00]])
<http://hypergraphql.org/documentation>
]FIGCAPTION]

> Pure RDF content types
> application/rdf+xml
> application/turtle
> text/turtle
> application/ntriples
> text/ntriples
> application/n3
> text/n3

]FIG]


[86] 単純な構文なのに仕様書の規定はがばがばやないか


- [92] [CITE@en[RDF1.1 Errata - Semantic Web Standards]], [TIME[2021-01-11T04:54:57.000Z]], [TIME[2021-01-11T09:55:21.084Z]] <https://www.w3.org/2001/sw/wiki/RDF1.1_Errata>
- [91] [CITE@en[Proposed fixed version of N-Triples https://www.w3.org/TR/n-triples/ Section 7]], [[Peter F. Patel-Schneider]], [TIME[2017-06-29 18:15:55 +09:00]], [TIME[2020-01-17T16:59:52.000Z]], [TIME[2021-01-11T09:54:49.416Z]] <https://lists.w3.org/Archives/Public/public-rdf-comments/2017Jun/0000.html>
- [94] [CITE@en[Are spaces allowed between terms in N-Triples 1.1?]], [[Wouter Beek]], [TIME[2017-06-29 00:14:33 +09:00]], [TIME[2020-01-17T19:50:34.000Z]], [TIME[2021-01-11T09:57:44.336Z]] <https://lists.w3.org/Archives/Public/semantic-web/2017Jun/0065.html>

[93] 
構文に関する規定の欠陥のいくつかは[[メーリングリスト]]に投稿され [SRC[>>91, >>94]]、
[[Errata]] にも掲載されていますが [SRC[>>92]]、
仕様書本体はその後長年放置されています。

[95] [[WG]] も放置したまま解散してしまったようだし...

[96] 
それにしても一度でも誰かが実装すれば気づきそうな誤りばかりなのですが、
[[W3C勧告]]のレビュープロセスはいつもがばがばですね...

[97] 
誰も実装してないのかな、と思いきや実装していて互換性がないみたいですよww [SRC[>>94]]

[98] [CITE@en[N-Triples Implementation Report]], [TIME[2014-02-20T21:23:04.000Z]], [TIME[2021-01-11T09:59:50.087Z]] <https://www.w3.org/2013/N-TriplesReports/index.html>

[99] 
[[リテラル]]も [[IRI]] も絶対に[[改行]]を生で含むことがないのだから、
1行1文にしてしまえば [[Unix]] 系の行指向のツールでも処理しやすくなったんじゃないですかね?


