SUZ-LAB
構造化データ

JSON-LD 入門 — Web の意味を機械に渡す構造化データ

JSON-LD とは何か(Linked Data と RDF グラフ、@context / @id / @type の役割)を具体例で解説し、Web でどう使われているか——検索のリッチリザルト、Microdata / RDFa との比較、@id で結ぶ Site-wide / Page-level 設計、よくあるエラーと検証ツール——までを一気に押さえます。最後に、このサイト自身が JSON-LD をどう実装しているかを実例として開きます。

Web には人間向けの見た目(HTML+CSS)と、機械向けの意味(構造化データ)の 2 つの層がある。 後者を担う事実上の標準が JSON-LD(JavaScript Object Notation for Linked Data)だ。 検索エンジンのリッチリザルト、ナレッジグラフ、SNS のカード、AI エージェントのデータ取得—— どれも「そのページが何について書かれているか」を機械可読で受け取れることが前提になっている。

この記事は、JSON-LD の仕組み(何を表しているのか)と、Web での使われ方 (どこに置き、何を得るのか)を具体例で解説する。最後に、このサイト自身が JSON-LD を どう出しているかを開き、机上の理論ではなく動いている実装として見せる。

JSON-LD とは — 「JSON のまま」意味を足す

セマンティック Web/Linked Data の狙いは、バラバラのサイトに散る情報を、標準化された 識別子でつなぎ、機械がリンクをたどって新しいデータを発見できるようにすることだ。 初期の XML ベースの記法は表現力は高かったが、開発者には重すぎて普及しなかった。 そこで 今日の Web で当たり前になった JSON の書き味そのままに、高度な意味づけを載せられる シリアライズ形式として設計されたのが JSON-LD で、2020 年 7 月に W3C 勧告「JSON-LD 1.1」が出ている。

JSON-LD が表すのは 方向を持つラベル付きの有向グラフだ。

  • ノード(主語・目的語)= リソース(組織・記事・人など)
  • エッジ(述語)= リソース間の関係(publisherauthor など)

主語・述語・目的語をすべて IRI(国際化された URI)でラベル付けするので、 名前の衝突なく、分散した Web スケールで情報を結合できる。JSON-LD ドキュメントは、この グラフを木構造の JSON にマッピングしたものだ、と捉えるとよい。

最小の例

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "TechArticle",
  "@id": "https://suz-lab.co.jp/topics/json-ld-structured-data",
  "headline": "JSON-LD 入門",
  "author": { "@type": "Organization", "name": "SUZ-LAB" }
}
</script>

@ で始まる キーワードが意味の骨格を決める。主要なものは次の通り。

キーワード役割
@context各キーを Schema.org 等の語彙(IRI)へ紐付ける「辞書」。外部ファイルも参照できる
@typeオブジェクトの型(OrganizationTechArticle など)や値のデータ型
@idそのノードを一意に識別する URI。別ブロックからの参照キーにもなる(後述)
@graph複数の独立ノードをまとめる入れ物。名前付きグラフの識別にも使う
@value / @language値に言語やデータ型を紐付ける「値オブジェクト」を作る(BCP 47 準拠)
@vocab / @base既定の語彙 URI と、相対 URI を解決する基準 IRI

@typetype@idid のように、@context でエイリアスを張ればアットマーク無しでも書ける。

データモデリングの勘所 — 配列の順序と数値精度のワナ

W3C のベストプラクティスが繰り返し強調するのは「開発者フレンドリーな JSON」であること。 その上で、RDF グラフに変換される都合から来る 2 つの落とし穴に注意する。

  • 配列は既定で「順不同(Set)」。JSON の配列は順序を持つが、RDF は順不同のトリプル集合 として扱うため、変換時に順序が消える。順序が意味を持つなら @context"@container": "@list" を宣言して rdf:List だと解釈させる。
  • 数値の精度欠損。多くの言語は数値を IEEE 754 倍精度で扱うので、大きな整数や精密な小数は 往復で誤差が出る。金融・学術など厳密な値は、あえて文字列で包み @typexsd:decimal / xsd:integer へ**型強制(Type Coercion)**するのが定石。
  • 文字列ではなく「実体」で書く。プロパティ値に名前の文字列を置くのではなく、@type@id を持つオブジェクトにして実体化する。双方向・循環参照は、一方はネスト・逆方向は @id 参照だけ、にして無限ループを避ける。

Web での使われ方① — 3 つの構造化データ方式

HTML に構造化データを埋める規格は歴史的に 3 つある。JSON-LD が支配的な理由は設計思想にある。

観点JSON-LDMicrodataRDFa
書き方<script> に独立した JSON ブロックHTML タグに itemprop 属性HTML タグに property 属性
表示(DOM)との結合非結合。デザイン変更で壊れない強結合。マークアップ変更で壊れやすい強結合。冗長で壊れやすい
Google の推奨最優先で推奨サポートするが新規は非推奨寄り事実上レガシー
利用サイト内シェア(WDC 2023)66%48%5%
平均トリプル数/ページ5536

決定的なのは 関心の分離だ。JSON-LD は <script type="application/ld+json"> に意味を カプセル化するので、<head> でも <body> でも好きな場所に置け、見た目に 1px も干渉しない。 Microdata / RDFa は「ビュー」と「データ」を同じタグに縛るため、フロントを少し直しただけで 構造化データが巻き込まれて壊れる。WebDataCommons の大規模調査(約 34 億ページ)でも、 JSON-LD だけがトリプル密度を伸ばし続けており、単なる SEO テクニックを超えて サイト間をつなぐデータ基盤として選ばれていることが読み取れる。

Web での使われ方② — 検索のリッチリザルトと @id 設計

検索エンジンにコンテンツの意味(価格・在庫・著者・パンくずなど)を明示的に渡すと、 星評価・画像カード・FAQ などの リッチリザルトの対象になる。ここで効くのが @id を使った Site-wide / Page-level の分離だ。

  • Site-wide(全ページ共通): WebSite / Organization を、正規 URL にアンカーを足した 不変の @id(例 https://example.com/#organization)で一度だけ定義する。
  • Page-level(各ページ固有): WebPage / Article / Product など、その URL 固有の情報だけを 書き、組織などは再宣言せず { "@id": "https://example.com/#organization" }参照する。

これで「同じ組織」がグラフ上の 1 ノードに束ねられ、全ページの記事が同じ発行元を指す。 成立条件は厳格で、@id / url は canonical URL と 1 文字単位で一致していなければならない (www の有無・HTTPS・末尾スラッシュ)。ズレると内部でリレーションが切れて孤立する。

このサイトは公開時に、canonical を「www 無し・HTTPS・末尾スラッシュ無し」の 1 本に正規化する 判断をしている。その経緯は 器を世に出すまで(Vercel とドメイン接続) に残した。JSON-LD の @id 一致は、この canonical 規律の上に乗っている。

よくある 10 のエラーと検証ツール

構造化データは放置すると「不整合なパッチワーク」に劣化する。代表的な失敗:

  • Organization の重複宣言(全ページでフル宣言)→ Site-wide で 1 回、以後は @id 参照に。
  • 末尾スラッシュ/www の不一致 → canonical の文字列をそのままコピーして出す。
  • ゴースト FAQ(HTML に無い Q&A を JSON-LD にだけ書く)→ スパム扱い。表示と一致させる。
  • 末尾カンマ・スマートクォート → 厳格な JSON パースエラーで丸ごと無視される。
  • 相対 URL の画像https:// から始まる絶対 URL を強制する。

検証は 3 層で行う。構文(JSON として妥当か)→ 語彙(Schema.org の型・プロパティが正しいか) → ポリシー(Google が各機能に課す必須フィールドを満たすか)。ツールは用途で使い分ける。

  • Rich Results Test(Google)… 検索機能への適合。ただし JSON-LD 内の // コメントを 独自に無視して「合格」にしてしまう——標準 JSON(RFC 8259)ではコメントは構文違反なので、 本番の標準パーサーではパースエラーになって弾かれる。本番出力はコメント無しの純粋な JSON にする。
  • Schema Markup Validator(Schema.org)… 800 以上の全クラスを中立に語彙検証。
  • JSON-LD Playground(W3C)… 展開/圧縮/フレーミングなど API 変換の挙動を観察。

このサイト自身の JSON-LD

ここまでの理論は、このサイト(apps/web)がそのまま実装している。抽象論ではなく 動いている実例として見てほしい——JSON-LD の記事が、JSON-LD で記述されている。 自分の主張を、自分で使って証明する——この姿勢は ドッグフーディングの情報設計版だ。

1. Site-wide を @id で 1 ノードに束ねる。 ルートレイアウトが全ページ共通で OrganizationWebSite を出し、#organization / #website@id で相互参照する。

// src/lib/structured-data.ts(要約)
export function siteStructuredData() {
  const orgId = `${SITE.url}/#organization`;
  return [
    { "@type": "Organization", "@id": orgId, name: SITE.name, url: SITE.url, /* … */ },
    { "@type": "WebSite", "@id": `${SITE.url}/#website`, publisher: { "@id": orgId } },
  ];
}

2. Page-level は再宣言せず参照する。 各実験ログは BlogPosting、この解説記事は TechArticle として出し、発行元は組織を再宣言せず publisher: { "@id": ".../#organization" } で指す。 まさに本文で説いた Site-wide / Page-level の分離だ。

// この記事(TechArticle)の構造化データ(要約)
{
  "@type": "TechArticle",
  headline: topic.title,
  isPartOf: { "@id": `${SITE.url}/#website` },       // サイトに属する
  publisher: { "@id": `${SITE.url}/#organization` }, // 組織は @id 参照で 1 ノードに
}

3. 値の出所は 1 か所、JSON-LD は「写すだけ」。 URL・組織名・SNS リンクといった値は content/site-config.ts を唯一の出所にし、structured-data.ts は Schema.org の形に写して URL を絶対化するだけ——文言をコードに直書きしない。これはこのサイト全体の設計方針でもある。

4. 型はコンテンツの性質で選ぶ。 制作物ショーケースの画像ギャラリーImageGallery として 出している(/showcase)。時系列の記録は BlogPosting、常設の技術解説は TechArticle、と型を描き分けることで、機械にも「これは記事、これは作品集」と伝わる。

@id を「唯一のつなぎ目」にしてリンクの二重管理を消す発想は、このサイトが VMOST → Roadmap → Log を一本の線でつないだ ときと同じだ。 人手のリンクは必ずドリフトする——安定した ID を 1 つ決めて機械的に突き合わせる、という 情報設計の原則が、ページ内の導線でも、検索エンジンへ渡すグラフでも一貫して効いている。

1.1 の進化と、その先

JSON-LD 1.1 は複雑な API 設計の制約を大きく外した。スコープ適用コンテキスト(親子で同じ プロパティ名を別語彙に安全にマッピング)、Protected Term(重要な定義を後続の上書きから保護)、 @nest / @included(意味を持たない中間ラッパーを飛ばす)、そして フレーミング(乱雑なグラフを、クライアントが要求する決定論的な木へ整形する)などだ。

その先では、セキュリティ強化の JSON-LD 1.2、人が書きやすい YAML-LD、IoT 向けの コンパクトバイナリ CBOR-LD といった周辺エコシステムが動いている。とはいえ Web で 95% の 場面は、この記事で押さえた @context / @type / @id と Site-wide/Page-level の @id 連結で足りる。


まとめ。 JSON-LD は「JSON のまま意味を足す」ことで、セマンティック Web を実務に降ろした。 Web では主に検索の構造化データとして使われ、勝ち筋は 表示から独立した <script> ブロック@id による Site-wide/Page-level の連結にある。canonical を 1 本に正規化し、値の出所を 1 か所にまとめ、型をコンテンツの性質で選ぶ——このサイトはその通りに実装している。 考え方の全体像は VMOST とは、実装の記録は 実験ログ にある。

#JSON-LD#構造化データ#SEO#Schema.org#Next.js#Web

ほかの解説トピック

Topics 一覧