hermapi

This WordPress.com site is the cat’s pajamas

D3D12 関連 バージョン管理用メモ

Direct3D のバージョンが訳わからなくなってきたので、調べものしつつメモってます。(更新中)
参照先があちこち散らばってるっぽいのと、ナンバリングが複数あってどれが何やら……。

参照先(増えるかも)

Core interfaces (Direct3D 12 Graphics) – Win32 apps | Microsoft Docs
D3D12.h header – Win32 apps | Microsoft Docs
DirectX-Specs | Engineering specs for DirectX features. (microsoft.github.io)

DXGI overview – Win32 apps | Microsoft Docs
DXGI Reference – Win32 apps | Microsoft Docs

Direct3D feature levels – Win32 apps | Microsoft Docs
Hardware Feature Levels – Win32 apps | Microsoft Docs

DXGI のプログラミングガイド – Win32 apps | Microsoft Docs


DXGI

Factory

Device

Adapter

Output

SwapChain


Device

  • ID3D12Device
    Windows 10
    コマンドアロケータ、コマンドリスト、コマンドキュー、リソース、パイプラインステートオブジェクト、ヒープ、ルートシグニチャ、サンプラ等多くのリソースを生成する。
  • ID3D12Device1
    Windows 10 Anniversary Update
    パイプラインライブラリ、フェンスコレクション、オブジェクトGPU常駐。
  • ID3D12Device2
    Windows 10 Creator Update
    パイプラインステートストリーム記述からパイプラインステートオブジェクトを生成する。
  • ID3D12Device3
    Windows 10 Fall Creators Update
    GPUヒープの非同期登録、既存オブジェクトのアドレス再使用、ファイルマッピングされたシステムメモリのGPU内保持
  • ID3D12Device4
    Windows 10 Fall Creators Update
    CommandList拡張1 、CommandResource拡張1 、Heap拡張1、保護されたリソースセッション、ReservedResource拡張1 、ResourceAllocationInfo拡張1
  • ID3D12Device5
    Windows 10 version 1809
    レイトレーシング、LifetimeTracker、MetaCommand 、StateObject 、実行時デバイス削除
  • ID3D12Device6
    Windows 10 version 1809 [19H1]
    バックグラウンドプロセスモード
  • ID3D12Device7
    低CPUオーバヘッドなステートオブジェクトの追加、保護されたリソースセッション拡張1
  • ID3D12Device8
    コミット済みリソース生成拡張2、配置済みリソース拡張1、サンプラフィードバックUAV生成、複製可能フットプリント拡張1、ResourceAllocationInfo拡張2

Command List


Pipeline Library


Fence


Root Signature


Object

Device Child

Pageable


Resource

  • ID3D12Resource
    CPU と GPU の読み書き可能な物理メモリまたはヒープ

Command Allocator

Command List

Command Queue

Command Signature

Descriptor Heap

Heap

Query Heap

  • ID3D12QueryHeap
    インデックス参照されたクエリヒープ配列の管理。

Pipeline State


Tools

Protected Session

Meta Command

  • ID3D12MetaCommand
    (Device5)
    ハードウェアベンダーに依存しない拡張アルゴリズム

Device Remove Extended

Lifetime

State Object

  • ID3D12StateObject
    (Device5) レイトレーシング用
    ドライバに直接与えられシェーダを含む構成状態の可変量
  • ID3D12StateObjectProperties
    (Device5) レイトレーシング用
    ID3D12StateObject のプロパティ値

Azure DevOps に誤ってチェックインしたデータを削除したい

保留中の変更をチェックインする際に不要なデータの除外をうっかり忘れた

※TeamFoundation で管理中のプロジェクトでやらかした想定です

バージョン管理から根こそぎデータの存在を消し飛ばしたい

データサイズが巨大とか、残しておきたくないとか、その文字列アップしたらヤバイやろとか色々なシチュエーションは考えられ。

実際は何度か遭遇したことがあったけれど、追ってデータ削除状態で上書きでしのいでいました。今回はそういうわけにもいかなく。

どうやって削除するかをネット情報彷徨いましたがなかなか見つからなかったので、うまくいった方法をまとめておきましょう。そうしましょう。

削除手順

VisualStudio のバージョン管理でやっておくこと

  1. 削除状態を上書きチェックインして、最新状態にはそのデータの存在がないようにする
  2. ソース管理エクスプローラで、接続しているサーバのURLを確認
    [組織名].visualstudio.com\[組織名]
    みたいな感じになっていると思われ
  3. 同じくソース管理フォルダーのパス表記も確認
    $/[プロジェクト名]
    みたいになっているはず

コマンドプロンプトでやること

スタートメニューから VisualStudio 2019 のフォルダを探して Developer Command Prompt for VS 2019 を起動する

※コマンドプロンプトとか PowerShell とか、VS のコマンドウィンドウとかではない

**********************************************************************
** Visual Studio 2019 Developer Command Prompt v16.0.3
** Copyright (c) 2019 Microsoft Corporation **********************************************************************

tf vc help 等のコマンドが動作するか確認する

C:\Program Files (x86)… > tf vc help

こんな感じのがでてきたら動作OK

Microsoft (R) TF – Team Foundation バージョン管理ツール、バージョン 16.133.28815.1
Copyright (C) Microsoft Corporation. All rights reserved.

tf vc dir /collection:[サーバURL] でプロジェクト一覧を出してみる

C:\Progr… > tf vc dir /collection:aaaa.visualstudio.com\aaaa

$/:
$project1
$project2

/recursive オプションを付けると再帰的一覧が表示できる

C:\Progr… > tf vc dir /collection:aaaa.visualstudio.com\aaaa /recursive

$/:
$project1
$project2

$/project1:
$test
test.sln
test.vssscc


$/project2:
$testA
testA.sln

これを元に削除したいデータのパスを手繰る
tf vc dir [$/ディレクトリパス名/サブディレクトリ]

/deleted オプションで削除済みも一覧に表示されるようになる
※削除項目は 末尾に;X000 のような削除マーカが記載される

C:\Progr… > tf vc dir $/project1 /collection:aaaa.visualstudio.com\aaaa /deleted

/$project1:
$test
$test2;X125
test.sln
test.vssscc

破棄したいディレクトリを特定できたら、 destory コマンドを実行する

/preview オプションで破棄対象の一覧が表示できる(破棄は実行されない)

tf vc destory [特定したディレクトリパス] /preview

C:\Progr… > tf vc destory $/project1/test2 /collection:aaaa.visualstudio.com\aaaa /preview

破棄: $/project1/test2;X159
破棄: $/project1/test2/test2.csproj;X159

破棄対象のデータに問題がないことを確認できたら /preview オプションなしで実行

C:\Progr… > tf vc destory $/project1/test2 /collection:aaaa.visualstudio.com\aaaa

$/project1/test2 およびそのすべての子を破棄しますか? (Yes/No)

確認が来るので

yes

で継続

破棄: $/project1/test2;X159
破棄: $/project1/test2/test2.csproj;X159

これで、データが完全にファイル管理から消える

確認

Azure DevOps に接続して、レポジトリのファイル、チェンジセットで
指定したデータの存在が消し飛んでいることを確認する

参考URL

Destroy コマンド
https://docs.microsoft.com/ja-jp/previous-versions/visualstudio/visual-studio-2010/bb386005(v=vs.100)

【TFS】 Team Foundation Server に巨大ファイルをチェックインしてしまったときの対処
https://tech.d-itlab.co.jp/programming/352/

Direct3D12 リファレンス日本語版欲しい index

Direct3D12の英語文書をどうにかするチャレンジ、一か月ぐらい停滞してますね。

どの辺の翻訳が済んでいるのか、何を調べ済みなのか訳わからなくなってきたので、箇条書きページを作っておきます。(随時更新、できるといいね)

あれ……なんか全然翻訳できてない気配が。コマンドリストとかの翻訳も手元にあったはずなのに、記事になっていない件。(5月 19, 2017)

  1. Direct3D12 関連の基本的な用語についてまとめ
  2. インタフェース 継承ツリー
  3. リソースバインディング

 

 

 

 

Direct3D12 リファレンス日本語版欲しい 09

さて、今回のネタで日本語翻訳メモは尽きます。empty battery low…
膨大な英語文書を前に ばったりとひれ伏す naiherm の無残な姿があったそうな。

デスクリプタ、デスクリプタテーブル、コマンドリスト、コマンドキュー あたりの文書もきっちり翻訳すべきなんだろうけれど、https://hermapi.wordpress.com/2017/04/08/direct3d12memo/ 
でざっくりまとめで息絶えました。

Root Signatures

https://msdn.microsoft.com/en-us/library/windows/desktop/dn899208(v=vs.85).aspx

ルートシグニチャはグラフィックスパイプラインにどのようなタイプのリソースが関連付けられているのかを定義します。

Root Signatures Overview

ルートシグニチャはアプリごとに設定され、リソースやシェーダを必要とするコマンドリストとリンクします。グラフィックスコマンドリストは、グラフィックスとコンピュートルートシグニチャの両方を持ちます。コンピュートコマンドリストは、シンプルにコンピュートルートシグニチャを一つだけ持ちます。これらのルートシグニチャはそれぞれが独立しています。

Using a Root Signature

Direct3D12 リファレンス日本語版欲しい 08 で一部翻訳済み。

ルートシグニチャはデスクリプタテーブルのコレクションを自由にアレンジするために定義します。これにはレイアウトやルート定数ルートデスクリプタも含まれます。それぞれのエントリは上限コストがあるので、アプリケーションはどのタイプのエントリにコストを多くかけられるのかのトレードオフバランスを割り振ることができます。

Create a Root Signature

ルートシグニチャはネストされた構造体を含む構造体の複合化されたデータです。これらはデータ構造体を使用してプログラムで定義することができます。(ヘルパ initialize メンバのメソッドがあります)  HLSLを作成することもできます。この方法では、コンパイラがレイアウトがシェーダとの互換性があるかを早急に検証できるというアドバンテージを得られます。

Root Signature Limits

Direct3D12 メモ で一部翻訳済み。

ルートシグニチャは主要な「現実資産」なので厳密な上限とコストについての熟考が必要となります。

Using Constants Directory in the Root Signature

アプリケーションは、ルートシグニチャ内にルート定数を定義することができ、この値は32ビット値となります。HLSLは定数バッファとして表現されます。

Note: 歴史的な理由で定数バッファは 4×32ビット値として表現されます。

Using Descriptor Directry in the Root Signature

アプリケーションは、デスクリプタヒープ上に配置しなくても済むようルートシグニチャにデスクリプタを配置することができます。これらのデスクリプタはルートシグニチャ内の大きなスペースを使用します。(ルートシグニチャの制限 の項目も参照) なので、アプリケーションはこの方法での配置は控えめにしなくてはなりません。

Example Root Signatures

Direct3D12 リファレンス日本語版欲しい 07 で一部翻訳済み

このセクションでは、からっぽから全領域使用までルートシグニチャが変化する様子を確認することができます。

Specifying Root Signatures in HLSL

HLSL シェーダモデル5.1 を C++コードでルートストレージに定義する方法について。

Root Signature version 1.1

バージョン1.1の目的は、デスクリプタヒープの変更またはデータデスクリプタの位置の変更を要しない場合に、このことをドライバに指示することができるようにすることです。同じデスクリプタまたは静的メモリを使用することが可能であることをドライバに伝達するためのオプションが許可されます。

 

 

 

Direct3D12 リファレンス日本語版欲しい 08

リファレンス多すぎてどこを読んだらいいのかだんだんワケワカランになってまいりました。

とりあえずルートシグニチャ(ルート署名)。これとっても大事っぽい。これがないと何もできないハズなので資料を読み進めていくことにしました。つーわけで、手元に残っている最後っぽい走り書きはコレ。

途中で心折れてる気配。

Using a Root Signature

ルートシグニチャの使い方

https://msdn.microsoft.com/en-us/library/windows/desktop/dn903950(v=vs.85).aspx

ルートシグニチャ(ルート証明)は、ルート定数、ルートデスクリプタ、デスクリプタテーブルのレイアウトを独自アレンジするための定義です。それぞれの要素にはコスト上限があるので、アプリケーションはルートシグニチャ内にそれぞれの要素をどれくらい配置するかトレードオフすることができます。

ルートシグニチャはAPIでマニュアル指定で作成することができるオブジェクトです。PSO(パイプラインステートオブジェクト)上のすべてのシェーダは、PSOで指定されているルートレイアウトと互換になっている必要があり、互換ではない場合、それぞれのシェーダは他のルートレイアウトに埋め込まれていなければなりません。この条件を満たさない場合PSOの生成は失敗します。シェーダを制作する際に、ルートシグニチャでの定義を知る必要はなく、シェーダが必要とされるタイミングでルートシグニチャは直接シェーダを制作することができます。既存のシェーダアセット(資産)は、ルートシグニチャの互換性のために変更する必要はありません。シェーダモデル5.1では、(シェーダ内に動的インデックス記述ができるので)拡張柔軟性があります。また、既存のシェーダでも必要に応じて追加することが可能です。

Command List Semantic

コマンドリストを開始すると、ルートシグニチャは未定義状態になります。グラフィクスシェーダはコンピュートシェーダから分割したルートシグニチャを所持し、それぞれ独自にコマンドリストが割り当てられます。ルートシグニチャは、コマンドリストまたはバンドルにセットされます。(これは現在のPSOで Draw/Dispath したものに合致します。) それ以外の場合の動作は未定義となります。 Draw/Dispath が完了するまでの期間、ルートシグニチャは不整合状態です。例えば、ルートシグニチャ互換に切り替わる前に、非互換のPSOが設定されるなどの状態があります。PSOを設定してもルートシグニチャは変更されません。アプリケーションは必要に応じてルートシグニチャを切り替える専用APIを呼び出す必要があります。

1度ルートシグニチャがコマンドリストに設定されると、レイアウトはアプリケーションが指定している場合にはバインディングと定義され、次回のDraw/Dispath 呼び出しでもコンパイル済みの同じレイアウトとして PSO が使用可能になります。

(以下翻訳省略……)

Direct3D12 リファレンス日本語版欲しい 07

さて、翻訳記事ぼちぼち残弾がなくなりそうですが、もうちょっとだけ手元に手書きメモが残っているので記録しておきましょうか。自分と同じ迷える子羊が少しでも助かりますようにっ。

ルートシグニチャはリソースを管理するための仕組みとして大切な要素のようなので、そのあたりで図が多くて初心者用の解説っぽいリファレンスを読んでみました。

https://msdn.microsoft.com/en-us/library/windows/desktop/dn899123(v=vs.85).aspx

※複合ルートシグニチャの例、ストリーミングシェーダリソースビューの例については翻訳を省略しました。このドキュメントを読み解く必要はかなり先かなと。

 

ルートシグニチャの使用例 (Example Root Signatures)

空のルートシグニチャ (An empty root signature)

 

空のルートシグニチャは、一見使えなさそうですが、些細なレンダリングパスに使用することができます。インプットアセンブラ、ごくわずかな頂点やピクセルシェーダなど、他のデスクリプタにアクセスを必要としないものです。ブレンドステージやレンダリングターゲット、深度ステンシルステートなどにも使用可能です。

単一の定数 (One constant)

APIバインドスロット ルート要素 HLSLバインドスロット
1 0 uint b0

APIバインドスロットは、コマンドリストレコード数でバインドされたパラメータを引数としています。このAPIバインドスロット番号は、ルートシグニチャ内のパラメータの順番を基にしているということが暗示されています。(初回は常に0)HLSLバインドスロットは、ルートパラメータが参照を行うたびに上がります。これはハードウェアは感知しませんが、イメージを評価しハードウェアは単なるDWORD定数であるとしてみなします。

コマンドリストに登録するときに定数がバインドされそれと同時にコマンドはその内容を使用することができます。

pCmdList->SetComputeRoot32BitConstant( 0, seed );
// 0 はパラメータインデックスで、 seed は シェーダに使用されます。

ルート定数バッファビューの追加 (Adding a root Constant Buffer View)

APIバインドスロット ルート要素 HLSLバインドスロット
1 0 uint b3
2 1 float b1
3 2 root
CBV
b0
4

この例では、2つのルート定数とルート定数バッファ(2DWORDコスト)を表現します。定数バッファビューをバインドするには以下のコマンドを使用します。

NOTE:はじめの2パラメータにはイメージが格納されています。定数配列はCBVとしてシェーダのb0に割り当てられます。

pCmdList->SetGraphicsRootConstantBufferView(2,GPUVAForCurrDynamicConstants);

デスクリプタテーブルをバインド (Binding descriptor tables)

APIバインドスロット ルート要素 HLSLバインドスロット
1 0 float4 b3
2
3
4
5 1 descripter table (for views…)
6 2 descripter table (for samplers)
7 3 root
CBV
b0
8

この例では、2つのデスクリプタテーブルを使用しています。1つ目は実行時用のCBV、SDV、UAVのヒープを5つ定義したテーブル、もう一つは実行時用の2つのサンプルデスクリプタヒープを宣言しています。コマンドリストをレコードする際に、デスクリプタテーブルはバインドされます。4DWORDサイズのfloat4ルート定数をルートシグニチャに登録するには、2DWORDを2定数使用してバインドします。

コマンドリストを記録する際に、デスクリプタテーブルをバインドするには……

pCmdList->SetComputeRootDescriptorTable(1, handleToCurrentMaterialDataInHeap);
pCmdList->SetComputeRootDescriptorTable(2, handleToCurrentMaterialDataInSamplerHeap);

このトピックのもう一つの要素である float4 をルート定数の 4DWORDサイズに格納するには、中間の 2 DWORDを4になるようにバインディングする方法を使用します。

pCmdList->SetComputeRoot32BitConstants(0,2,myFloat2Array,1);
// 要素開始位置のオフセットを1(32bit) として2要素を配置 (middle 2 values in float4)

複合ルートシグニチャ(A more complex root signature)

※翻訳省略

ストリーミングシェーダリソースビュー(Streaming Shader Resource Views)

※翻訳省略

Direct3D12 メモ

D3D12で出てくる単語とそれらの意味のざっくりまとめ

本家のリファレンスを読みつつまとめてみたメモ。

コマンドアロケータ

  • コマンド用GPUヒープ割り当て装置
  • ダイレクトコマンドリストとバンドル両方で使用できる
  • コマンドリストを作るために必要

コマンドリスト

  • コンピュート、グラフィックス(3D/ダイレクト)、コピーの三種類ある
  • バンドルかダイレクトかを選べる
  • バンドルの場合はGPUに残留、ダイレクトの場合は使い切り
  • コマンドを記録
  • コマンドアロケータが必要
  • リストを構築する前にリセットしないと、コマンドアロケータがすぐにあふれて死ぬ
  • ルートシグニチャが必要
  • パイプラインステートを設定できる

コマンドキュー(CPU)

  • 用途に合わせて複数作ることができる
  • 実行に優先順位をつけることができる
  • コマンドリストを登録して実行(ExecuteCommandList)するための装置
  • 実行するとGPUに仕事が行く
  • GPUの仕事の終了を待機する必要がある場合は Fence を使用

パイプラインステート

  • コンピュート、グラフィックスの二種類ある
  • コピーはコンピュートでもグラフィクスでもどちらでもできる
  • ルートシグニチャが必要
  • シェーダバイトコードが格納されている
  • レンダリングするにはステートオブジェクトが必要

ビュー

  • リソースの読み取り方法を定義

ルートシグニチャ

  • リソースをすべてとりまとめる定義集
  • デスクリプタテーブル、デスクリプタ(シェーダリソースビュー、定数バッファビュー、アンオーダードアクセスビュー)、 32bit 定数(ルート定数)を登録できる。最大 64 DWORD まで。
    • デスクリプタテーブル 1DWORD
    • ルート定数32ビット値 1DWORD
    • ルートデスクリプタ 2DWORD
  • ルートに配置するのは必要最小限に留め、テーブルを利用する。
  • 頻繁に変更されるパラメータは後ろに、アクセス遅延を抑えたいパラメータは前に配置する。
  • 静的サンプラの配列を登録できる。サイズ上限なし

デスクリプタヒープ

  • リソース定義(デスクリプタ)を保存するためのヒープ

デスクリプタ

  • デスクリプタヒープに登録される
  • 4DWORD
  • GPUとCPUのヒープへのアドレスが格納されている

デスクリプタテーブル

  • デスクリプタヒープ上のデスクリプタ配列を表すオブジェクト

 

 

Direct3D12 リファレンス日本語版欲しい 06

05 でざっくり描画関連のリファレンスに何が書かれているのかチェックできたので、そのなかで重要っぽいところの翻訳をしていきます。

リソースバインディング概要

Resource Binding Overview

Resources and the Graphics Pipeline

テクスチャ、定数バッファ、イメージバッファなどのシェーダリソースは、シェーダパイプラインに直接バインドされず、デスクリプタを通して参照されます。デスクリプタは、単一リソースについての情報を保持する小さなオブジェクトです。

複数のデスクリプタはデスクリプタテーブルにグループ化されます。デスクリプタテーブルに、リソースタイプごとに1つのレンジを使用して情報を格納します。リソースには多くの種類が存在します。以下のリソースがよく使用されます。

  • 定数バッファビュー(CBV)
  • アンオーダードアクセスビュー(UAV)
  • シェーダリソースビュー(SRV)
  • サンプラ

SRV、UAV、CBV のデスクリプタは、同じデスクリプタテーブル内に混合可能です。

グラフィックス/コンピュートパイプラインはデスクリプタテーブル内のインデックスによってリソースにアクセスするための参照を取得します。

デスクリプタテーブルはデスクリプタヒープ内に格納されます。デスクリプタヒープは(デスクリプタテーブル内の)すべてのデスクリプタを、1度または複数回レンダリングするために理想的に格納します。

別のコンセプトとして、ルートシグニチャ(ルート証明)があります。ルートシグニチャはバインディングの規約で、アプリケーションによって定義され、シェーダがリソースを使用するためにアクセスを要求する際に使用されます。ルートシグニチャは、以下を格納することができます。

  • デスクリプタヒープ内のデスクリプタテーブルのインデックス。このインデックスは、事前に定義されたデスクリプタテーブルのレイアウトです。
  • デスクリプタや、デスクリプタテーブルを利用せずにシェーダに直接渡される(ルート定数と呼ばれる)ユーザ定義の定数。
  • ルートシグニチャ内に直接、少量のデスクリプタを格納することができます。たとえば、描画ごとに変更される定数バッファビュー(CBV) を、アプリケーションの必要に応じてデスクリプタヒープ内にそれらのデスクリプタを配置するために保存できます。

表現を変えると、ルートシグニチャは描画ごとに小さな単位の組み合わせを最適化したパフォーマンスで切り替える機能を提供しているともいえます。

Direct3D 12 では、メモリマネジメント、オブジェクトライフタイムマネジメント、ステートトラッキング、メモリ同期など、それぞれのタスクを並列にバインディングするようにデザインされています。Direct3D  12 のバインディングは、低オーバヘッドで、API呼び出しの遅延についても最適化されています。さらに、ローエンド/ハイエンド のハードウェアに渡って拡張可能で、新旧のグラフィックスエンジンプログラミングからも拡張可能です。

Resource Types and views

リソースタイプは Direct3D 11 と同じです。

  • Texture1D と Texture1DArray
  • Texture2D と Texture2DArray、Texture3DMS、Texture2DMSArray
  • Texture3D
  • Buffers (型、構造、生)

リソースビューは Direct3D 11 とおおむね同じですが、頂点、インデックスバッファビューが追加されました。

  • 定数バッファビュー(CBV)
  • アンオーダードアクセスビュー (UAV)
  • シェーダリソースビュー ( SRV)
  • サンプラ
  • レンダーターゲットビュー (RTV)
  • 深度ステンシルビュー (DSV)
  • インデックスバッファビュー(IBV)
  • 頂点バッファビュー(VBV)
  • ストリームアウトプットビュー(SOV)

リスト冒頭4種類のビューのみシェーダに対して常に有効です。Shader Visible Descriptor Heaps と Non Shader Visible Descriptor Heaps の項目を参照してください。

XML のルールを作ろう

XML でデータを集めよう の記事で、XML 文書に自分のルールを設定すると、自分専用のデータ保存メカニズムが実現できることを説明しました。

ルールは自分で守ればそれで良いのですが、機械的にそれが守られているかをチェックしてくれればもっと便利です。 自分のルールと異なる間違った情報を入力した時にエラーを出してくれたり、ここにはコレかコレしか入れられないよ…と自動的にヒント(サジェスト)を出してくれると楽ですね。

らくらく XML

XML には、実はこのようなチェック機構とサジェスト機能を有効に利用するための便利なメカニズムがいくつかあります。
そのような仕掛けをDTD(ドキュメントタイプディフィニション)文書型定義と言います。

コレを使うと、文書に中でできる事とできない事、しなければならない事としてはならない事…をあらかじめ決めておき、自分の作成した文書がルールに則っているかを簡単にチェックしたり、必要な項目が確実に含まれているかを確認したり、ある場所に記述できる事の一覧を表示してそこから簡単に選択する事が出来ます。

まぁ早い話、正しい XML 文書を記述する為のとても便利なヘルパーになってくれるのです。

先程説明した便利な DTD にはいくつか種類があり、それぞれメリットが異なるのですが、私は xml Schema と言うのを一押しとして紹介します。

これは名前の通り XML 文書のスキーマ、つまり枠組みを作ってそれに従った文書を作って貰おうと言うアイディアの実装です。 更に、XML スキーマ自体が XML 文書です。 XML のルールを理解するために XML スキーマを利用するのは、言わば一石二鳥の合理的でおいしいアプローチなのです。

文書の具体的な例はあとで説明しますが、出来ることはこんな感じです。

  • 文書に出てきて良い要素を決める
  • 文書に出てくる要素の順序を決める
  • 文書に出てくる要素の出現回数を決める
  • 打ち込める文字の種類を制限する
  • 打ち込める文字の種類を選択肢から簡単に選ぶ
  • これらを複雑に組み合わせる

ぶっちゃけ出来ることはこれだけなのですが、これだけあれば整合性のとれた、ルールに則った XML 文書を作成する強力な手助けになり、文書を速く作製する支援も得られます。

ついでに言えば、XML スキーマを覚えることは、XML 文書の作成方法を覚える手助けにもなります。

DTD、XML Schema を使ってお手軽に自分専用の XML 文書を作りましょう!

さんぷる

毎回の事ですが、ここでちょっとサンプルです。

これも自分用の文書定義なので、これを丸々コピーして楽~ と言う訳にはいきませんが、ざっくりと内容を見る分には使えるかと思います。

<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="urn-localizeschema"
    elementFormDefault="qualified"
    xmlns="urn-localizeschema"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
  <!-- 文書ルートエレメント -->
  <xs:element name="article" type="article" />

  <!-- 文書ルート型 -->
  <xs:complexType name="article">
    <xs:sequence>
      <xs:element name="overview" type="overview" minOccurs="1" maxOccurs="1" />
      <xs:element name="signature" type="signature" minOccurs="0" maxOccurs="unbounded" />
      <xs:element name="members" type="members" minOccurs="0" maxOccurs="1" />
      <xs:element name="details" type="details" minOccurs="0" maxOccurs="1" />
      <xs:element name="moreinfo" type="moreinfo" minOccurs="0" maxOccurs="1" />
      <xs:element name="requirements" type="requirements" minOccurs="0" maxOccurs="1" />
      <xs:element name="seealso" type="seealso" minOccurs="0" maxOccurs="1" />
    </xs:sequence>
    <xs:attribute name="namespace" type="xs:string" />
    <xs:attribute name="name" type="xs:string" />
  </xs:complexType>

  <!-- 概要ブロック -->
  <xs:complexType name="overview">
    <xs:complexContent>
      <xs:extension base="paragraphs">
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
  <!-- シグニチャブロック -->
  <xs:complexType name="signature" mixed="true">
    <xs:complexContent>
      <xs:extension base="code">
        <xs:attribute name="lang" type="xs:string" use="required" />
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
  <!-- メンバ一覧ブロック -->
  <xs:complexType name="members">
    <xs:choice>
      <xs:sequence minOccurs="1" maxOccurs="unbounded">
         <xs:element name="member" type="member" />
      </xs:sequence>
      <xs:sequence minOccurs="1" maxOccurs="unbounded">
        <xs:element name="membergroup" type="membergroup">
        </xs:element>
      </xs:sequence>
    </xs:choice>
  </xs:complexType>
  <!-- 各メンバブロック -->
  <xs:complexType name="member">
    <xs:complexContent>
      <xs:extension base="paragraphs">
        <xs:attribute name="name" type="xs:string" use="required" />
        <xs:attribute name="href" type="xs:string" use="optional" />
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
  <!-- 各メンバグループ-->
  <xs:complexType name="membergroup">
    <xs:sequence minOccurs="1" maxOccurs="unbounded">
      <xs:element name="member" type="member" />
    </xs:sequence>
    <xs:attribute name="name" type="xs:string" use="required" />
  </xs:complexType>
  <!-- 詳細ブロック -->
  <xs:complexType name="details">
    <xs:complexContent>
      <xs:extension base="paragraphs">
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
  <!-- 詳しい情報ブロック -->
  <xs:complexType name="moreinfo">
    <xs:complexContent>
      <xs:extension base="paragraphs">
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
  <!-- 要求ブロック -->
  <xs:complexType name="requirements">
    <xs:sequence>
      <xs:element name="client" minOccurs="0" maxOccurs="1">
        <xs:complexType>
          <xs:attribute name="value" use="required" />
        </xs:complexType>
      </xs:element>
      <xs:element name="server" minOccurs="0" maxOccurs="1">
        <xs:complexType>
          <xs:attribute name="value" use="required" />
        </xs:complexType>
      </xs:element>
      <xs:element name="header" minOccurs="0" maxOccurs="1">
        <xs:complexType>
          <xs:attribute name="value" use="required" />
        </xs:complexType>
      </xs:element>
      <xs:element name="idl" minOccurs="0" maxOccurs="1">
        <xs:complexType>
          <xs:attribute name="value" use="required" />
        </xs:complexType>
      </xs:element>
      <xs:element name="lib" minOccurs="0" maxOccurs="1">
        <xs:complexType>
          <xs:attribute name="value" use="required" />
        </xs:complexType>
      </xs:element>
      <xs:element name="dll" minOccurs="0" maxOccurs="1">
        <xs:complexType>
          <xs:attribute name="value" use="required" />
        </xs:complexType>
      </xs:element>
      <xs:element name="iid" minOccurs="0" maxOccurs="1">
        <xs:complexType>
          <xs:attribute name="name" use="required" />
          <xs:attribute name="value" use="required" />
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
  <!-- 参照ブロック -->
  <xs:complexType name="seealso">
    <xs:sequence>
      <xs:element name="ms" minOccurs="0" maxOccurs="1">
        <xs:complexType>
          <xs:attribute name="href" type="xs:string" />
        </xs:complexType>
      </xs:element>
      <xs:element name="ul" type="list" minOccurs="0" maxOccurs="1" />
    </xs:sequence>
  </xs:complexType>
 
  <!-- 段落グループ -->
  <xs:complexType name="paragraphs">
    <!-- 空の要素を許可します。 -->
    <xs:sequence minOccurs="0" maxOccurs="unbounded">
      <xs:choice>
        <xs:element name="p" type="paragraph" />
        <xs:element name="h2">
           <xs:complexType mixed="true">
              <xs:attribute name="en" use="optional" />
           </xs:complexType>
        </xs:element>
        <xs:element name="h3" type="xs:string" />
        <xs:element name="ul" type="list" />
        <xs:element name="ol" type="list" />
        <xs:element name="dl" type="difinition-list" />
      </xs:choice>
    </xs:sequence>
  </xs:complexType>
  <!-- リスト -->
  <!-- p 要素か l 要素の繰り返し -->
  <xs:complexType name="list">
    <xs:sequence minOccurs="1" maxOccurs="unbounded">
      <xs:choice>
        <xs:element name="p" type="paragraph" />
        <xs:element name="l" type="line" />
      </xs:choice>
    </xs:sequence>
  </xs:complexType>
  <!-- 定義リスト -->
  <!-- リストと同じ形式で、各子要素に term 属性を必須とする -->
  <xs:complexType name="difinition-list">
    <xs:sequence minOccurs="1" maxOccurs="unbounded">
      <xs:choice>
        <xs:element name="p">
          <xs:complexType>
            <xs:complexContent>
              <xs:extension base="paragraph">
                <xs:attribute name="term" type="xs:string" use="required" />
              </xs:extension>
            </xs:complexContent>
          </xs:complexType>
        </xs:element>
        <xs:element name="l">
          <xs:complexType>
            <xs:complexContent>
              <xs:extension base="line">
                <xs:attribute name="term" type="xs:string" use="required" />
              </xs:extension>
            </xs:complexContent>
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:sequence>
  </xs:complexType>
  <!-- 段落 -->
  <!-- en 属性をオプションとする p ブロック要素 -->
  <xs:complexType name="paragraph" mixed="true">
    <xs:complexContent >
      <xs:extension base="line">
        <xs:sequence minOccurs="0" maxOccurs="unbounded">
          <xs:choice>
            <xs:group ref="elements" />
            <xs:element name="l" type="line" />
            <xs:element name="ul" type="list" />
          </xs:choice>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
  <!-- 単一行 -->
  <!-- en 属性をオプションとする l インライン要素 -->
  <xs:complexType name="line" mixed="true">
    <xs:sequence minOccurs="0" maxOccurs="unbounded">
      <xs:choice>
        <xs:group ref="elements" />
      </xs:choice>
    </xs:sequence>
    <xs:attribute name="en" type="xs:string" use="optional" />
  </xs:complexType>
  <!-- 行内で許可される要素のグループ -->
  <!-- l 要素とその派生先 p 要素で使用される -->
  <xs:group name="elements">
    <xs:choice>
      <xs:element name="kw" type="keyword" />
      <xs:element name="dfn" type="xs:string" />
      <xs:element name="kbd" type="xs:string" />
      <xs:element name="sup" type="xs:string" />
      <xs:element name="sub" type="xs:string" />
      <xs:element name="code" type="code" />
      <xs:element name="a" type="anchor" />
    </xs:choice>
  </xs:group>
  <!-- コードブロック -->
  <!-- 内容に含まれる要素を 0 以上全てをスキップ -->
  <xs:complexType name="code" mixed="true">
    <xs:sequence minOccurs="0" maxOccurs="unbounded">
      <xs:any processContents="skip"></xs:any>
    </xs:sequence>
  </xs:complexType>
  <!-- 明示的アンカー -->
  <!-- href 属性を必要、title 属性をオプションとする文字列単純要素 -->
  <xs:complexType name="anchor" mixed="true">
    <xs:attribute name="title" type="xs:string" use="optional" />
    <xs:attribute name="href" type="xs:string" use="required" />
  </xs:complexType>
  <!-- 行内キーワード -->
  <!-- class 属性をオプションとする文字列単純要素 -->
  <xs:complexType name="keyword">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="class" type="xs:string" use="optional" />
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
  </xs:schema>

と、見た目はこんな感じになります。

かいせつ

ここでの解説はあくまでも上のサンプルに対する物で、XML Schema の使用を網羅する物ではありませんが、主に使う機能とその代表的な使い方を上から順に読み解いていきます。

最初に

先に説明したように、XML Schema はそれ自体が XML 文書です。 ですから <?xml … ?> 行で始まり、文書のルートノードが一つだけあります。 上の例では <?xml version=”1.0″ encoding=”utf-8″?> が一行目にあり、<xs:schema … > </xs:schema> で文書が囲まれています。 まさしく XML 文書そのものですね。

名前空間

以前解説した内容では、<なんとか> … </なんとか> でノードが成り立つ事を説明しました。 HTML 文書などでも同じですね。 ここでは少しだけ +α の内容が含まれています。 “xs:” という部分が文書の至る所にちりばめられています。 これは後々詳しく説明しますが、XML namespace (名前空間) というプレフィクスの一種です。 先の例では、<xs:schema … > というノードは、 schema という名前なのですが、その名前は xs 名前空間に所属していますよー。 他の名前空間(たとえば xv)に所属する schema ノード(<xv:schema … >)とは区別して下さいねー。 という意味です。 このように、時に複雑になる XML 文書では、名前空間を使用して文書の構成ノードを明確に区別するお作法があります。 xs:… などのプレフィクスが無い = 名前空間の指定がないノードは、グローバル名前空間に所属しているとみなされます。 XHTML 文書で <html> タグにプレフィクスがないのは、グローバル名前空間だけを使っていても特に問題が無いからです。

名前空間の指定に、<xs:schema … xmlns:xs=”http://www.w3.org/2001/XMLSchema” と書かれている部分があります。 xmlns と言うのが XML NameSpace の省略表記で、:xs=”url” の部分がこの名前空間で使用できる全てのノードの定義、つまり XML Schema という XML 文書の XML Schema です。 URL の形式で書くのがお作法ですが、この URL に何らかの文書がある訳ではありません。 他の XML Schema と区別するために、この文書専用の URL、他の文書とバッティングしない名前を付けておく決まりになっています。 自分自身を自分自身と同じメカニズムで定義しているというのが面白い部分だと思いますがいかがですか。

まぁ名前空間の説明はざらっと流すだけにしておきます。 使いだすと深いのですが、XML Schema を覚える分にはあまり重要ではないので。

では本題

文書の至る所に出てくる xs: というのをいちいち書くと面倒なので、とりあえず付いているけど考えない方向で説明します。

文書の内容を眺めてみると、大雑把に言って以下の内容だけで構成されている事が分かります。

  • element
  • complexType
  • group

他にも用途によっては必要な要素があるのですが、とりあえず上のサンプルではこの 3つしか出てきません。 さらに言うと、ほぼ全てが complexType です。 (大文字小文字(ケース)を区別します。)

element

一番最初に一度だけ出てくる element ノードを見てみましょう。

<!– 文書ルートエレメント –>
<xs:element name=”article” type=”article” />

と言う作りになっています。 これはズバリ、文書に article と言う要素を発見したら、それは article 型とみなして処理を行いなさいよ~ という命令です。 この命令がある限り、文書のルート要素は article にしなければならない事が明らかになっています。 (前回説明したように、XML 文書にはルート要素が必ず一つだけ存在するルールでした。)

たとえば XHTML 文書に対する XML Schema があった場合、ここは

<xs:element name=”html” type=”なんとか” />

になっているはずです。

type=”article” と書かれている部分は、name=”article” で示された通り、article 要素の具体的な造りは article という型で定義されているからそこを見なさいよと言う指示です。 その type=”article” は直下で complexType として定義されています。

complexType

複雑なタイプというのは、単純なタイプに対するもう一つの要素です。 単純なタイプを使う事によって色々なメリットがあるのですが、私はちょっと面倒くさがりなのでここでは使いませんでした。 単純なタイプに関する説明はまた改めてするかもしれませんが、ここでは複雑なタイプに関してだけ見ていきましょう。

複雑なタイプに対して、name=”article” と名前が付けられています。 この名前は、先に出た elementtype=”article” に対応する物です。 ルート要素の article は具体的には complexTypearticle 型ですよ~ という説明です。

group

xml文書を変換しよう!

xml文書を記述しました。
これはDTDに準拠した正しいxml文書です。
これによって、あなたは自分専用の文書形式を定義して、必要に応じて様々な内容をルールに則って記述、保存できました。

さて、ある目的の文書をいくつか作成すると、必要に応じてHTMLのような別の文書に変換し、ユーザーがぱっと見で内容を把握できると便利じゃないか? という欲が出てきます。
xml文書は確かに正確ですが、人間が読むにはあまり適していません。
あくまでもコンピューターが正しい文書を保存するのに適しているだけです。

文書の内容を人間が見て直ぐに理解するためには、見慣れた他の文書形式に変換できると便利です。
早い話、HTMLのような、ユーザーフレンドリーな文書に変換して、ウェブブラウザなどで閲覧できると良いよね? って事です。

もう想像がついているかも知れませんが、xml文書を他のxml文書やHTML文書形式に変換するメカニズムも用意されています。
この方法もxml文書の一首であるxsltという文書を使います。

この文書は通常、DTDと対になって利用され、ある文書を一定のルールで他の文書形式に変換することができます。

この要素がきたら、ヘッダと区切り線を入れて内容をボールドで表示しよう、または、この要素がいくつか並んでいたら、リスト表示しよう… といった文書の論理的な構造を、見た目で分かりやすい文書に変換できるのです。

これによって、入力したデータを必要に応じて見やすい形にコンバートできるのがxsltの大切な役割です。

次回はサンプルを交えて、xsltの強力な変換ロジックを見てみましょう。