Javaの基本からXML文書処理まで 2001年8月1日 岸 和孝 JAGAT客員研究員
はじめに
SDKの用法

Java言語の基本
 文字列の表示
 文字列の連結,パッケージ化
 char型の配列
 型の変換
 ループ
 ビット演算
 シグニチャ
 部分文字列
 クラス階層

ファイルの入出力
 ファイル内容の表示
 バイト単位の入出力
 行単位の入出力

SAX
 XML文書からESISへの変換
 XML文書のツリー表現

DOM
 XML文書からESISへの変換
 XML文書のツリー表現
 XML文書のノード表現
 XML文書の生成

XSL
 XSL変換
 XSL:FO変換
 XML文書からPDFへの変換

仕様の要約
 ESIS
 DOM
 XSLT
 CSS

サンプルデータ
 CARDS.DTD
 MYCARDS.XML
 BOOKS.DTD
 MYBOOKS.XML
 BOOKS.XSL
 TEXT.XSL

はじめに

小文は,私(岸 和孝 )がXML中級セミナーで用いるJava入門テキストです。自習書ではありませんので,Java言語の文法は記述していません。したがって,プログラミング上で必要となる多くの技術情報については,該当する仕様書を参照してください。

現在,XML応用の急速な普及によって,多くのXML応用プログラムの開発が要請されています。XML応用では,従来のデータ処理方法とは異なる面が要求されます。

XML応用に向いたプログラミング言語としてはJavaを挙げることができます。次に述べるような特長を備えていることから,すでに多くのXML応用のライブラリー(製品や部品)やプログラムがJavaによって開発されています。

Javaは,Sun Microsystems社によって1991年に開発されたオブジェクト指向のプログラミング言語です。Javaは,C++をベースにしていますが,C++よりも単純で,学習が容易です。またJavaは,対話的なネットワーク向けプログラムで要求される安全性,堅牢性,高性能性を実現しております。Javaのソースは,プラットフォームに依存しない形で表現でき,それから得られるバイナリー(これはバイトコードと呼ばれます)は,異なるプラットフォームでも実行できるようにJVMJVM:Java Vartual Machine の下で実行します。XML応用に共通のライブラリーがJARJAR:Java ARchive として無償配付されています。こうしたことがXML応用への適用に向いている理由とされています。

実習の目的

このセミナーでは,SDKSDK:Java Software Development Kit (MS-WindowsではJ2SDKJ2SDK:Java 2 SDK, Standard Edition ,MacOSではMRJ SDK 2.2MRJ SDK 2.2:Mac OS Runtime for Java Software Development Kit )を用いながら,Java言語の基本を学んだ後に,XML応用に不可欠なSAXSAX:Simple API for XML とDOMDOM:Document Object Model を用いたJavaプログラムの構築方法について学びます。さらに,JavaによるXSL変換についても学びます。なお,J2SDKとMRJ SDK 2.2の実現は全く同じではありませんので,注意が必要です。さらにMRJ SDK 2.2には,まだ幾つかの不具合があるために,別のJavaコンパイラであるJakeを併用します。

実習で用いるリソース

ここで用いるリソースは,次のサイトから入手して解凍解凍:解凍結果で得られたJARファイルをさらに解凍してはなりません。なお,これらのJARファイルは2001年6月時点のものです。必要に応じて,上記の参考URLから最新のものを入手してください。 してください。

ソフトウェア開発キット
J2SDK:http://java.sun.com/j2se/1.3/ja/download-windows.html
MRJ SDK 2.2:ftp://ftp.apple.com/developer/Development_Kits/MRJ_SDK_2.2_Install.sit.hqx
Jake:http://users.aber.ac.uk/nst/Jake/DownloadFiles/Jake1.2.sea.hqx
XML処理のためのJava応用プログラムインターフェース
jaxp.jar:http://java.sun.com/xml/xml_jaxp.html
XMLパーザー
crimson.jar:http://xml.apache.org/dist/crimson/crimson-1.1.zip
xerces-1.2.3.jar(Parser,Schema,DOM2,SAX2):http://xml.apache.org/dist/xerces-j/Xerces-J-bin.1.2.3.tar.gz
XSLTスタイルシートプロセッサー
xalan.jar:http://xml.apache.org/dist/xalan-j/xalan-J_2_2_D6.tar.gz
XSLフォーマッティングオブジェクト
fop-0.17.0-jp.jar:http://cvs.baykit.org/pub/bxs/bxs-1_0_12.jar内
仕様書
XML:http://www.w3.org/TR/REC-xml
XML名前空間:http://www.w3.org/TR/REC-xml-names/
SAX:http://www.megginson.com/SAX/
DOM:http://www.w3.org/DOM/
XSLT:http://www.w3.org/TR/xslt
XSL:FO:http://www.w3.org/TR/2000/CR-xsl-20001121/
PDF:http://partners.adobe.com/asn/developer/acrosdk/DOCS/pdfspec.pdf
SVG:http://www.w3.org/TR/2000/CR-SVG-20001102/

SDKの用法

実習を始めるに当たって,SDKを使ったコンパイルと実行の方法について説明します。

MS-Windowsにおけるコンパイルと実行の方法

MS-Windows J2SDKは,MS-DOSで実行します。先ず,スタートメニューのMS-DOSプロンプトからMS-DOSを呼び出すと,MS-DOSウィンドウが開きますので,そのMS-DOSの制御の下でJ2SDKを使っていきます。

J2SDKを使う上で必要となるMS-DOSコマンドは,次のものです。その詳細については,参考書を参照してください。

60mm100mm
MS-DOSコマンドの例機能
CD \XJ\1\1_1ディレクトリ"\XJ\1\1_1"へ切り替える。
SET path=C:\J2SDK\binJ2SDKのバイナリへのパス"C:\J2SDK\bin"を設定する。
SET classpath=C:\XJ\lib\crimson.jar;C:\XJ\lib\jaxp.jar参照するJARファイルを"C:\XJ\lib\crimson.jar"と"C:\XJ\lib\jaxp.jar"に設定する。
javac -d . Xml2EsisUsingSAX.javajavaソース"Xml2EsisUsingSAX.java"をコンパイルし,現在のディレクトリ"-d ."にバイトコード"Xml2EsisUsingSAX.class"を生成する。
java Xml2EsisUsingSAX sample.xmlバイトコード"Xml2EsisUsingSAX.class"を引数"sample.xml"で実行する。

コンパイルの方法

MS-Windows J2SDKでは,javaソース(拡張子が".java")は,javac(javaコンパイラ)によってコンパイルされます。例えば,"C:\J2SDK\bin\javac"によってjavaソースをコンパイルします。javaソースが"Xml2EsisUsingSAX.java"であれば,参照するJARファイルは"C:\XJ\lib\crimson.jar"と"C:\XJ\lib\jaxp.jar"ですので,次のようになります。コンパイル結果のバイトコード(拡張子が".class")は,現在のディレクトリ"-d ."に"Xml2EsisUsingSAX.class"として得られます。

SET classpath=C:\XJ\lib\crimson.jar;C:\XJ\lib\jaxp.jar;.
javac -d . Xml2EsisUsingSAX.java

実行の方法

MS-Windows J2SDKでは,コンパイルで生成されたバイトコードは,java(Javaアプリケーションの起動コマンド)を介して実行します。例えば,"C:\J2SDK\bin\java"を介してバイトコードを実行します。コマンドラインは,バイトコードが"Xml2EsisUsingSAX.class"であれば,参照するJARファイルは"C:\XJ\lib\crimson.jar"と"C:\XJ\lib\jaxp.jar"ですので,次のようになります。なお,コマンド引数が必要な場合は,"sample.xml"のように続けて入力します。

SET classpath=C:\XJ\lib\crimson.jar;C:\XJ\lib\jaxp.jar;.
java Xml2EsisUsingSAX sample.xml

こうした操作を簡便にするために,AUTOEXEC.BATにおいてPATHやclasspathを設定しておいたり,バッチファイルを用いることもできますが,MS-DOSの操作に慣れていない方は,コマンドで毎回指示したほうがいいでしょう。

MacOSにおけるコンパイルと実行の方法

コンパイルの方法

MRJ SDK 2.2では,javaソースは,javacによってコンパイルされます。例えば,javaソースを"MyDisk:MRJ SDK 2.2:JDK Tools:javac"へドラッグ・アンド・ドロップします。ドラッグ・アンド・ドロップしたjavaソースが含まれたフォルダーがClasspath欄へ追加されます。参照するJARファイルがある場合は,Classpath欄に追加します。次に,Do Javacボタンを押すと,コンパイルが行われます。

Jakeによってもjavaソースをコンパイルできます。例えば,javaソースを"MyDisk:Jake1.2:Jake 1.2 (beta1)"へドラッグ・アンド・ドロップします。javaソースがSource Code欄へ追加されます。次に,Classpath欄に参照するJARファイルを追加します。compileボタンを押すと,コンパイルが行われます。この設定は保存できますので,次のコンパイルの時は,そのドキュメントをダブルクリックするだけで済みます。

実行の方法

MRJ SDK 2.2では,コンパイルで生成されたバイトコードは,JBinderyを介して実行します。例えば,javaバイトコードを"MyDisk:MRJ SDK 2.2:Application Builders:JBindery:JBindery"へドラッグ・アンド・ドロップします。コマンド引数が必要な場合は,Command:optional parameters欄に入力します。参照するJARファイルがある場合は,Classpath:Additions to class path欄に追加します。Runボタンを押すと,バイトコードが実行されます。

確認済みの不具合点

fopの不具合点

javacの不具合点

Jakeの不具合点

JBinderyの不具合点

Java言語の基本

Java言語の基本を例題を通して学びます。

文字列の表示

このプログラムは,文字列"Hello"と"Hi"を表示します。

プログラム実行条件

60mm60mm
プログラムsample1
クラスパスなし
コマンド引数なし

sample1.java

class sample1 {
  public static void main( String[] args ) {
    System.out.println("Hello");
    System.out.println("Hi");
    System.exit(0);
  }
}

解説

60mm100mm
class クラス名 ブロック単純なクラス定義
class sample1 { }sample1のクラス定義
型指定 メソッド名( パラメタ ... ) ブロックメソッド定義
public static void main( String[] args ) { }main()のメソッド定義
void戻り値を返さない
staticクラスメソッド
public外部から呼び出せる(公開)
main( String[] args )main()メソッド
型指定 配列変数名[]配列変数
String[] argsString型配列の変数args
argsコマンドラインのパラメタ
クラス名.クラスメソッド名( 値, ... )クラスメソッド
System.out.println();Systemクラスの標準出力(改行付き)
"こんにちわ"文字列リテラル

文字列の連結,パッケージ化

このプログラムは,いろいろな文字列を表示します。

プログラム実行条件

60mm60mm
プログラムsample2
クラスパスなし
コマンド引数なし

sample2.java

import other.*;
class sample2 {
  public static void main( String[] args ) {
    String Hello = "Hello", lo = "lo";
    System.out.println( "Hello" );
    System.out.println( "Hel" + "lo" );
    System.out.println( "Hel" + lo );
    System.out.println( sample2x.hello );
    System.out.println( other.sample2x.hello );
    System.exit(0);
  }
}
class sample2x {
  static String hello = "Hi";
}

other.sample2x.java

package other;
public class sample2x {
  public static String hello = "Yes";
}

解説

60mm100mm
import パッケージ;パッケージのpublicクラスをすべてインポート
import other.*;otherのpublicクラスをすべてインポート
クラス名 変数名, ... ;クラス型の変数宣言
String Hello;String型の変数名Hello
String Hello = "Hello";変数名Helloへの初期値代入
"Hel" + "lo"文字列リテラルどうしの連結
"Hel" + lo文字列リテラルと変数の連結
package パッケージ;このファイルをパッケージに所属させる
package other;sample2x.javaをotherに所属させる
sample2x.hello同じパッケージ内にあるクラス変数
other.sample2x.helloパッケージother内のクラス変数

char型の配列

このプログラムは,コマンドラインから任意の文字列を入力すると,それを一文字づつ表示します。

プログラム実行条件

60mm60mm
プログラムsample3
クラスパスなし
コマンド引数文字列

sample3.java

class sample3 {
  public static void main( String[] args ) {
    String  a = args[0];
    System.out.println( "String : " + a );
    char[]    chars = a.toCharArray();
    System.out.println( "char[0]: " + chars[0] );
    System.out.println( "char[1]: " + chars[1] );
    System.out.println( "char[2]: " + chars[2] );
    System.out.println( "char[3]: " + chars[3] );
    System.out.println( "char[4]: " + chars[4] );
    System.out.println( "char  : " + java.lang.String.valueOf( chars ) );
    System.exit(0);
  }
}

解説

60mm100mm
char[]char型(基本型)の配列
オブジェクト.メソッド名( 値, ... )インスタンスメソッド
オブジェクト.クラスメソッド名( 値, ... )クラスメソッド
クラス名.クラスメソッド名( 値, ... )クラスメソッド
a.toCharArray()変数a(Stringオブジェクト)に附随するtoCharArrayメソッド(char型配列として取り出す)を呼ぶ
java.lang.String.valueOf( chars )変数chars(基本型,オブジェクトではない)をvalueOfメソッド(String型へ変換)に引き渡す

型の変換

このプログラムは,コマンドラインから任意の文字列を入力すると,それが数値であれば数値として表示します。

プログラム実行条件

60mm60mm
プログラムsample4
クラスパスなし
コマンド引数文字列

sample4.java

class sample4 {
  public static void main( String[] args ) throws NumberFormatException {
    String  a = args[0];
    try {
      try {
        int  i = java.lang.Integer.parseInt( a );
        System.out.println( "int: " + java.lang.Integer.toString( i ) );
      }
      catch ( NumberFormatException e ) {
        long  l = java.lang.Long.parseLong( a );
        System.out.println( "long: " + java.lang.Long.toString( l ) );
      }
    }
    catch ( NumberFormatException e ) {
      System.out.println( "String: " + a );
    }
    System.exit(0);
  }
}

解説

60mm100mm
throws NumberFormatExceptionNumberFormatException(数値形式の例外)を投げる可能性がある
java.lang.Integer.parseInt( a )変数a(基本型)をparseIntメソッド(int型として解析)に引き渡す
java.lang.Long.parseLong( a )変数a(基本型)をparseLongメソッド(long型として解析)に引き渡す
java.lang.Integer.toString( i )変数i(基本型)をtoStringメソッド(String型へ変換)に引き渡す
try ブロック catch ( 例外指定 ) ブロックガードされたブロックと例外の受け止め
catch ( NumberFormatException e )受け止める例外指定とそのスタックトレース

ループ

このプログラムは,コマンドラインから幾つかの文字列を入力すると,それらを表示します。

プログラム実行条件

60mm60mm
プログラムsample5
クラスパスなし
コマンド引数文字列[文字列]...

sample5.java

class sample5 {
  public static void main( String[] args ) {
    for ( int  i = 0; i < args.length; i++ )
      System.out.println( "args[" + i +"]: " + args[i] );
    System.exit(0);
  }
}

解説

60mm100mm
for ( 初期化 ; テスト ; 再設定 ) ブロックforループ
for ( int i = 0; )初期化:int型のローカル変数iを0とする
for ( ; i < args.length; )テスト:変数iがパラメタの配列の要素数よりも小さいか
for ( ; ; i++ )再設定:変数iを1だけインクリメントする
配列変数[添字]配列の要素を参照する
配列変数.length配列の要素数
args[i]配列変数argsのi番目の要素を参照する
条件 ? 値1 : 値2条件が真の時に値1をとり,偽の時に値2をとる
System.out.print();Systemクラスの標準出力(改行なし)

ビット演算

このプログラムは,コマンドラインから数値を入力すると,それをバイトとして扱い,結果を表示します。

プログラム実行条件

60mm60mm
プログラムsample6
クラスパスなし
コマンド引数数値

sample6.java

class sample6 {
  public static void main(String[] args) {
    int    n = java.lang.Integer.parseInt( args[0] );
    System.out.println( " n  :" + n );
    int    a[] = new int[n];
    System.out.println("a[" + a.length + "]" );
    byte  b = (byte)n;
    System.out.println( " b  :" + b );
    int    i = ~b;
    System.out.println( " b  :" + Integer.toHexString(b) );
    System.out.println( "~b  :" + Integer.toHexString(i) );
    i = b << 4;
    System.out.println( "b  :" + Integer.toHexString(b) );
    System.out.println( "b<<4:" + Integer.toHexString(i) );
    System.exit(0);
  }
}

解説

60mm100mm
型指定 配列変数名[] = new 型指定[要素数];新しい配列オブジェクトの生成
int a[] = new int[n];n個の要素からなるint型配列変数a
(型名)式キャスト
(byte)nint型変数nをbyte型へ変換する
byte bbyte型の変数b
~b変数b全体をNOTする
b << 4変数b全体を4ビットだけ左へシフトする
Integer.toHexString(b)変数bを16進文字列へ変換する

シグニチャ

このプログラムは,コマンドラインから1個から3個までの数値を入力すると,その最大値を表示します。

プログラム実行条件

60mm60mm
プログラムsample7
クラスパスなし
コマンド引数数値[ 数値[ 数値 ]]

sample7.java

public class sample7 {

  int max(int x) {
    return x;
  }

  int max(int x, int y) {
    return ( x > y ) ?  x : y;
  }

  int max(int x, int y, int z) {
    if      ( x > y && x > z) return x;
    else if ( y > x && y > z) return y;
    else                      return z;
  }

  public static void main(String[] args) {
    int      i, j, k;
    sample7    test = new sample7();
    switch ( args.length ) {
      case 1 :
        i = java.lang.Integer.parseInt( args[0] );
        System.out.println( "max(x): " + test.max( i ) );
        break;
      case 2 :
        i = java.lang.Integer.parseInt( args[0] );
        j = java.lang.Integer.parseInt( args[1] );
        System.out.println( "max(x,y): " + test.max( i, j ) );
        break;
      case 3 :
        i = java.lang.Integer.parseInt( args[0] );
        j = java.lang.Integer.parseInt( args[1] );
        k = java.lang.Integer.parseInt( args[2] );
        System.out.println( "max(x,y,z): " + test.max( i, j, k ) );
        break;
      default :
        System.out.println( "failed" );
        break;
    }
    System.exit(0);
  }
}

解説

60mm100mm
switch ( 式 ) ブロックブロック内のcaseによる場合分け
case 値 : 文値に等しい時に,この文を実行する
default : 文ブロック内のすべてのcaseに一致しない時に,この文を実行する
breakforなどのループやswitchのブロックから脱出する
クラス名 変数名 = new クラス名[値, ...];新しいインスタンスの生成
sample7 test = new sample7();クラスsample7のインスタンスtestの生成
戻り値の型 メソッド名(型, 引き数, ...) ブロックメソッド定義
int max(int x, int y, int z) { }x,y,zのうちの最大値を返すメソッド
クラス名.クラスメソッド名( 値, ... )クラスメソッド
test.max( i, j, k )i,j,kのうちの最大値
if ( 条件 ) ブロック1 else ブロック2条件が真の時にブロック1を実行し,偽の時にブロック2を実行する
return値を戻す
値1 > 値2値1が値2より大きいか
値1 && 値2値1と値2との論理ANDをとる

部分文字列

このプログラムは,コマンドラインから任意の文字列,その部分文字列の開始位置と終了位置を入力すると,その部分文字列を表示します。

プログラム実行条件

60mm60mm
プログラムsample8
クラスパスなし
コマンド引数文字列 開始位置 終了位置

sample8.java

class sample8 {
  public static void main( String[] args ) {
    System.out.println( "string        :" + args[0] );
    System.out.println( "start position:" + args[1] );
    System.out.println( "end position  :" + args[2] );
    String  str = args[0];
    int  start = java.lang.Integer.parseInt( args[1] );
    int  end  = java.lang.Integer.parseInt( args[2] );
    char    c1  = str.charAt( start );
    char    c2  = str.charAt( end - 1 );
    System.out.println( "starting char :" + c1 );
    System.out.println( "ending char  :" + c2 );
    char  buffer[] = new char[ end - start ];
    str.getChars( start, end, buffer, 0 );
    System.out.println( "sub-string    :" + buffer );
    System.exit(0);
  }
}

解説

60mm100mm
オブジェクト.メソッド名( 値, ... )インスタンスメソッド
str.charAt( start )変数strの(Stringオブジェクト)の指定桁位置の文字を取り出す
str.getChars( start, end, buffer, 0 )変数strの(Stringオブジェクト)の部分文字列を取り出す

クラス階層

このプログラムは,スーパークラス,サブクラスを利用して,ある配列の内容を表示します。

プログラム実行条件

60mm60mm
プログラムsample9
クラスパスなし
コマンド引数なし

sample9.java

class Point {
  int x, y;

  Point( int x, int y ) {
    this.x = x;
    this.y = y;
  }

  public String toString() {
    return ( "x=" + x + ", y=" + y );
  }
}

interface  Colorable {
  void  setColor( int color );
}

class ColoredPoint extends Point implements Colorable {
  int color;

  ColoredPoint( int x, int y, int color ) {
    super( x, y );
    setColor( color );
  }

  public void setColor( int color ) {
    this.color = color;
  }

  public String toString() {
    return super.toString() + ", color=" + color;
  }
}

class sample9 {
  public static void main( String[] args ) {
    Point[]  cp = new ColoredPoint[4];
    cp[0] = new ColoredPoint(1, 2, 0);
    cp[1] = new ColoredPoint(3, 4, 1);
    cp[2] = new ColoredPoint(5, 6, 2);
    ColoredPoint[]  cpa = ( ColoredPoint[] ) cp;
    System.out.println( "cpa.length: " + cpa.length );
    for (int i = 0; i < cpa.length - 1; i++)
      System.out.println( "cpa[" + i + "]: " + cpa[i] );
    System.exit(0);
  }
}

解説

60mm100mm
クラス名( パラメタ, ... )コンストラクタ定義
Point( int x, int y )コンストラクタPointの定義
this.オブジェクトカレントオブジェクトを参照する
super.オブジェクトスーパークラスのオブジェクトを参照する
this.x = xPointの変数xにコンストラクタのパラメタxを代入する
super.toString()PointのtoString()メソッドを参照する
super( 値, ... )スーパークラスのコンストラクタを呼ぶ
this( 値, ... )クラスのコンストラクタを呼ぶ
interface インタフェース名 ブロックインタフェース定義
interface Colorable { }インタフェースColorableの定義
extends スーパークラス名 ブロックスーパークラス定義
class ColoredPoint extends PointクラスColoredPointはスーパークラスPointのサブクラスとなる
implements インタフェース名, ...インタフェースを実現する
class ColoredPoint implements ColorableクラスColoredPointはインタフェースColorableを実現する

ファイルの入出力

Java応用の基本となるファイルの入出力を例題を通して学びます。

ファイル内容の表示

このプログラムは,コマンドラインで指定したファイルの内容を入力し,それをそのまま表示します。

プログラム実行条件

60mm60mm
プログラムDisplayFile
クラスパスなし
コマンド引数入力ファイル名

DisplayFile.java

import java.io.*;
public class DisplayFile {
  public static void main( String[] args ) {
    if ( args.length != 1 ) {
      System.err.println( "USAGE: java FileOperationByByte inputfile");
      System.exit(1);
    }
    try {
      DataInput  data;
      String    text;
      int      lineNo;
      data = new DataInputStream( new FileInputStream( args[0] ) );
      lineNo = 1;
      while ( ( text = data.readLine() ) != null ) {
        System.out.println( lineNo + " " + text.length() + " " + text );
        lineNo++;
      }
    }
    catch( IOException e ) {
      System.err.println( "Error detected:" + e.getMessage() );
      System.exit(1);
    }
    System.exit(0);
  }
}

解説

60mm100mm
import java.io.*;java.ioパッケージのインポート
DataInputインタフェース
FileInputStream抽象クラスInputStreamのサブクラスFileInputStream
DataInputStream抽象クラスInputStreamのサブクラスFilterInputStreamのサブクラスDataInputStream
data.readLine()行末符号までのデータを行単位に読み込む
nullこの場合はEOF(ファイルの終了)を表す
catch( IOException e ) { }入出力例外の受け止め

バイト単位の入出力

このプログラムは,バイト単位の入出力を用いて,コマンドラインで指定した入力ファイルから出力ファイルへ内容を複製し,同時にその内容を表示します。

プログラム実行条件

60mm60mm
プログラムFileOperationByByte
クラスパスなし
コマンド引数入力ファイル名 出力ファイル名

FileOperationByByte.java

import java.io.*;
public class FileOperationByByte {
  public static void main( String[] args ) {
    if ( args.length != 2 ) {
      System.err.println( "USAGE: java FileOperationByByte inputfile Outputfile");
      System.exit(1);
    }
    if ( new File( args[1] ).exists() ) {
      System.err.println( "Error: OutputFile already existed");
      System.exit(1);
    }
    DataInput  in;
    DataOutput  out;
    byte    b;
    int      lineNo;
    int      charPos;
    try {
      in  = new DataInputStream( new FileInputStream( args[0] ) );
      out = new DataOutputStream( new FileOutputStream( args[1] ) );
      try{
        lineNo = 1;
        charPos = 1;
        System.out.print( lineNo + "\t" + charPos + "\t" );
        while ( true ) {
          b = in.readByte();
          charPos++;
          switch ( b ) {
            case 0x0a :  // '\n'
              System.out.println( "\\n" );
              lineNo++;
              System.out.print( lineNo + "\t" + charPos + "\t" );
              break;
            case 0x0d :  // '\r'
              System.out.println( "\\r" );
              lineNo++;
              System.out.print( lineNo + "\t" + charPos + "\t" );
              break;
            case 0x09 :  // '\t'
              System.out.print( "\\t" );
              break;
            default :
              System.out.print( (char)b );
              break;
          }
          out.writeByte( b );
        }
      }
      catch( IOException e ) {
        System.out.println( "Error detected: " + e.getMessage() );
        System.exit(1);
      }
    }
    catch( IOException e ) {
      System.err.println( "Error detected: " + e.getMessage() );
      System.exit(1);
    }
    System.exit(0);
  }
}

解説

60mm100mm
'文字'文字リテラル
\\\(本来はバックスラッシュ)を表す文字エスケープ記号
\nLF符号を表す文字エスケープ記号
\rCR符号を表す文字エスケープ記号
DataOutputインタフェース
FileOutputStream抽象クラスOutputStreamのサブクラスFileOutputStream
DataOutputStream抽象クラスOutputStreamのサブクラスFilterOutputStreamのサブクラスDataOutputStream
in.readByte()データをバイト単位に読み込む
out.writeByte( b )データをバイト単位に書き出す

行単位の入出力

このプログラムは,行単位の入出力を用いて,コマンドラインで指定した入力ファイルから出力ファイルへ内容を複製します。

プログラム実行条件

60mm60mm
プログラムFileOperationByLine
クラスパスなし
コマンド引数入力ファイル名 出力ファイル名

FileOperationByLine.java

import java.io.*;
public class FileOperationByLine {
  public static void main( String[] args ) {
    if ( args.length != 2 ) {
      System.err.println( "USAGE: FileOperationByLine inputfile Outputfile");
      System.exit(1);
    }
    if ( new File( args[1] ).exists() ) {
      System.err.println( "Error: OutputFile already existed");
      System.exit(1);
    }
    try {
      BufferedReader  reader;
      PrintWriter    writer;
      String      text;
      reader = new BufferedReader( new FileReader( args[0] ) );
      writer = new PrintWriter( new FileWriter( args[1] ) );
      try {
        for ( text = reader.readLine(); null != text; text = reader.readLine() ) {
          writer.println( text );
          System.out.println( text );
        }
      }
      finally {
        writer.close();
      }
    }
    catch( IOException e ) {
      System.err.println( "Error detected: " + e.getMessage() );
      System.exit(1);
    }
    System.exit(0);
  }
}

解説

60mm100mm
BufferedReaderReaderのサブクラス
PrintWriterWriterのサブクラス
FileReaderInputStreamReaderのサブクラス
FileWriterOutputStreamWriterのサブクラス
finally ブロック後始末

SAX

SAXSAX:Simple API for XML を例題を通して学びます。SAXは,XML文書データを順次に読み取りながら個別の処理を行うようにした応用プログラムインターフェースで,少ない記憶容量で大きな文書を扱うのに適しています。

XML文書からESISへの変換

このプログラムは,xml.orgが開発したSAXを用いて,XML文書インスタンスを入力し,ESIS形式 で表示します。

プログラム実行条件

60mm60mm
プログラムXml2EsisUsingSAX
クラスパスcrimson.jar,jaxp.jar
コマンド引数入力ファイル名

Xml2EsisUsingSAX.java

import org.xml.sax.*;
import javax.xml.parsers.*;
import java.io.*;
public class Xml2EsisUsingSAX extends HandlerBase {
  static  String    fileName;
  private int      level;
  private String[ ] nest = new String[ 100 ];

  public static void main( String[] args ) throws Exception {
    if ( args.length != 1 ) {
      System.err.println( "USAGE: java Xml2EsisUsingSAX xmlfile" );
      System.exit(1);
    }
    try {
      SAXParserFactory  factory = SAXParserFactory.newInstance();
      factory.setValidating( true );
      SAXParser        saxParser = factory.newSAXParser();
      Parser            parser  = saxParser.getParser();
      Xml2EsisUsingSAX  handler = new Xml2EsisUsingSAX( );
      parser.setDocumentHandler( handler );
      fileName = args[0];
      parser.parse( fileName );
      System.exit(1);
    }
    catch ( Exception e) {
      System.out.println( "Error detected: " + e.getMessage() );
      System.exit(1);
    }
  }

  public void startDocument( ) {
    level = 0;
  }

  public void endDocument( ) {
    System.out.println( "C" );
  }

  public void startElement( String qname, AttributeList atts ) {
    if ( atts != null ) {
      for ( int i = 0; i < atts.getLength(); i++ ) {
        System.out.println( "A" + atts.getName(i) + " TOKEN " + atts.getValue(i) );
      }
    }
    System.out.println( "(" + qname );
    nest[ level ] = qname;
    nest[ level + 1 ] = null;
    level++;
  }

  public void endElement( String qname ) {
    level--;
    System.out.println( ")" + qname );
  }

  public void characters( char ch[], int start, int length ) {
    // fix me !
    String  text = new String(ch, start, length ).replace( '\n', '~' );
    System.out.println( "-" + text );
    nest[ level ] = "#text";
    nest[ level + 1 ] = null;
  }

  public void processingInstruction( String target, String data ) {
    System.out.println( "?" + target + " " + data );
    nest[ level ] = target;
    nest[ level + 1 ] = null;
  }
}

解説

60mm100mm
SAXParserFactory.newInstance()使用するパーザーを指定しインスタンス化する
SAXParserSAXの基本インタフェース
parser.setDocumentHandler( handler )イベントハンドラーを登録する
parser.parse()XML文書を構文解析する
startDocument() { }文書の開始を読み込んだ時に呼び出されるメソッドに上書きされる
endDocument() { }文書の終了を読み込んだ時に呼び出されるメソッドに上書きされる
startElement() { }要素の開始を読み込んだ時に呼び出されるメソッドに上書きされる
endElement() { }要素の終了を読み込んだ時に呼び出されるメソッドに上書きされる
characters() { }内容を読み込んだ時に呼び出されるメソッドに上書きされる
processingInstruction() { }処理命令を読み込んだ時に呼び出されるメソッドに上書きされる

XML文書のツリー表現

このプログラムは,変数levelを用いて要素のツリーを字下げで表現し出力するように,Xml2EsisUsingSAXを書き換えたものです。

プログラム実行条件

60mm60mm
プログラムXml2TreeUsingSAX
クラスパスcrimson.jar,jaxp.jar
コマンド引数XMLファイル 結果ファイル

Xml2TreeUsingSAX

import org.xml.sax.*;
import javax.xml.parsers.*;
import java.io.*;
public class Xml2TreeUsingSAX  extends HandlerBase {
  static String    fileName;
  private int      level;
  private String[ ]  nest = new String[ 100 ];
  static PrintWriter  writer;

  public static void main( String[] args ) {
    if ( args.length != 2 ) {
      System.err.println( "USAGE: java Xml2TreeUsingSAX xmlfile outputfile");
      System.exit(1);
    }
    try {
      SAXParserFactory  factory = SAXParserFactory.newInstance();
      factory.setValidating( true );
      SAXParser        saxParser = factory.newSAXParser();
      Parser            parser  = saxParser.getParser();
      Xml2TreeUsingSAX  handler = new Xml2TreeUsingSAX( );
      parser.setDocumentHandler( handler );
      writer = new PrintWriter( new FileWriter( args[1] ) );
      fileName = args[0];
      parser.parse( fileName );
      writer.close();
      System.exit(0);
    }
    catch ( Exception e) {
      System.out.println( "Error detected :" + e.getMessage() );
      System.exit(1);
    }
  }

  public void startDocument( ) {
    level = 0;
  }

  public void endDocument( ) {
    ;
  }

  public void startElement( String qname, AttributeList atts ) {
    writer.println( indent( level ) + qname );
    nest[ level ] = qname;
    nest[ level + 1 ] = null;
    level++;
  }

  public void endElement( String qname ) {
    level--;
  }

  public void characters( char ch[], int start, int length ) {
    // fix me
    String  text = new String(ch, start, length ).replace( '\n', '~' );
    writer.println( "\t" + text );
    nest[ level ] = "#text";
    nest[ level + 1 ] = null;
  }

/*
  public void processingInstruction( String target, String data ) {
    writer.println( indent( level ) + "?" + target + " " + data );
    nest[ level ] = target;
    nest[ level + 1 ] = null;
  }
*/

  public String indent( int n ) {
    String s;
    for ( s = ""; n > 0; n-- )
      s += " ";
    return s;
  }
}

DOM

DOMDOM:Document Object Model を例題を通して学びます。DOM は,XML文書データを一旦すべて読み取って記憶上にノードツリーとして展開し,その後,個別の処理を行うようにした応用プログラムインターフェースで,文書を構造的に扱うのに適しています。

XML文書からESISへの変換

このプログラムは,W3Cが開発したDOMとSun Microsysystemsが開発したJAXPJAXP:Java API for XML Parsing を用いて,XML文書インスタンスを入力し,ESIS形式 で表示します。

プログラム実行条件

60mm60mm
プログラムXml2EsisUsingDOM
クラスパスcrimson.jar,jaxp.jar
コマンド引数XMLファイル

Xml2EsisUsingDOM.java

import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.*;
public class Xml2EsisUsingDOM {
  private int      level = 0;
  private String[ ]  nest = new String[ 100 ];
  static PrintStream  out = System.out;

  Xml2EsisUsingDOM() { }

  public void makeDocTree( String docName ) throws Exception {
    DocumentBuilderFactory  dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder        db = dbf.newDocumentBuilder();
    Document                doc = db.parse( new FileInputStream( docName ) );
    Element                elem = doc.getDocumentElement();
    makeNodeTree( elem );
  }

  public void makeNodeTree( Node node ) throws Exception {
    printNodeData( node );
    NodeList  nl = node.getChildNodes();
    int  numberOfChildren = nl.getLength();
    level++;
    if ( numberOfChildren > 0 ) {
      for ( int  i = 0; i < numberOfChildren; i++ ) {
        makeNodeTree( nl.item( i ) );
      }
    }
    level--;
    // fix me
    if ( ! nest[ level ].substring( 0, 1 ).equals( "#" ) ) {
      out.println( ")"  +  nest[ level ] );
    }
  }

  public void printNodeData( Node node ) throws Exception {
    String  nodeName = node.getNodeName();
    int    nodeType = node.getNodeType();
    String  nodeValue = node.getNodeValue();
    nest[ level ] = nodeName;
    nest[ level + 1 ] = null;
    switch ( nodeType ) {
      case Node.CDATA_SECTION_NODE :
        break;
      case Node.COMMENT_NODE :
        break;
      case Node.DOCUMENT_FRAGMENT_NODE :
        break;
      case Node.DOCUMENT_NODE :
        break;
      case Node.DOCUMENT_TYPE_NODE :
        break;
      case Node.ELEMENT_NODE :
        NamedNodeMap  attlist = node.getAttributes();
        if ( attlist != null ) {
          for ( int i = 0; i < attlist.getLength(); i++ ) {
            Node  it = attlist.item( i );
            if ( it.getNodeType() != Node.ATTRIBUTE_NODE ) {
              System.err.println( "Internal error: " + nodeName );
            }
            out.println( "A" + it.getNodeName() + " TOKEN " + it.getNodeValue() );
          }
        }
        out.println( "(" + nodeName );
        break;
      case Node.ENTITY_NODE :
        break;
      case Node.ENTITY_REFERENCE_NODE :
        out.println( "&" + nodeName );
        break;
      case Node.NOTATION_NODE :
        out.println( "N" + nodeName );
        break;
      case Node.PROCESSING_INSTRUCTION_NODE :
        out.println( "?" + nodeName + " " + nodeValue );
        break;
      case Node.TEXT_NODE :
        if ( nodeValue != null ) {
          // fix me
          String  newNodeValue = nodeValue.replace( '\n', '~' );
          out.println( "-" + newNodeValue );
        }
        break;
    }
  }

  public static void main( String[ ] args ) {
    if ( args.length != 1 ) {
      System.err.println( "USAGE: java Xml2EsisUsingDOM xmlfile");
      System.exit(1);
    }
    try {
      Xml2EsisUsingDOM  tree = new Xml2EsisUsingDOM();
      tree.makeDocTree( args[ 0 ] );
      System.exit(0);
    }
    catch ( Exception e) {
      out.println( "Error detected: " + e.getMessage() );
      System.exit(1);
    }
  }
}

解説

60mm100mm
DocumentBuilderFactoryXML文書からDOMオブジェクトツリーを生成するパーザーが得られるようにするAPIを定義するクラス
DocumentBuilderFactory.newInstance()DocumentBuilderFactoryの新しいインスタンスを作る
DocumentBuilderXML文書からDOM文書インスタンスを得るためのAPIを定義するクラス
dbf.newDocumentBuilder()現在設定されている条件を用いてDocumentBuilderの新しいインスタンスを作る
db.parse()XML文書として与えられたInputStreamの内容を構文解析し,新しいDOM文書オブジェクトを返す
Document完全なXML文書のルートノード
Node大半のオブジェクトを表すインタフェース
NodeList順に並べたノードの集まりを表すインタフェース
Element文書内の要素を表すインタフェース
NamedNodeMap名前でアクセスできるノードの集まりを表すインタフェース
doc.getDocumentElement()文書docのルート要素を返す
node.getChildNodes()ノードnodeのすべての子を順に並べたNodeListオブジェクトを返す
node.getNodeName()ノードnodeのノード名を返す
node.getNodeType()ノードnodeのノード型を返す
node.getNodeValue()ノードnodeのノード値を返す
node.getAttributes()ノードnodeのすべての属性を順に並べたNamedNodeMapオブジェクトを返す

XML文書のツリー表現

このプログラムは,変数levelを用いて要素のツリーを字下げで表示するように,Xml2EsisUsingDOMを書き換えたものです。

プログラム実行条件

60mm60mm
プログラムXml2TreeUsingDOM
クラスパスcrimson.jar,jaxp.jar
コマンド引数XMLファイル

Xml2TreeUsingDOM.java

import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.*;
public class Xml2TreeUsingDOM {
  private int        level = 0;
  private String[ ]  nest = new String[ 100 ];
  static PrintStream  out = System.out;

  Xml2TreeUsingDOM() { }

  public void makeDocTree( String docName ) throws Exception {
    DocumentBuilderFactory  dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder      db = dbf.newDocumentBuilder();
    Document        doc = db.parse( new FileInputStream( docName ) );
    Element          elem = doc.getDocumentElement();
    makeNodeTree( elem );
  }

  public void makeNodeTree( Node node ) throws Exception {
    printNodeData( node );
    NodeList  nl = node.getChildNodes();
    int  numberOfChildren = nl.getLength();
    level++;
    if ( numberOfChildren > 0 ) {
      for ( int  i = 0; i < numberOfChildren; i++ ) {
        makeNodeTree( nl.item( i ) );
      }
    }
    level--;
  }

  public void printNodeData( Node node ) throws Exception {
    String  nodeName = node.getNodeName();
    int    nodeType = node.getNodeType();
    String  nodeValue = node.getNodeValue();
    nest[ level ] = nodeName;
    nest[ level + 1 ] = null;
    switch ( nodeType ) {
      case Node.DOCUMENT_NODE :
        break;
      case Node.DOCUMENT_TYPE_NODE :
        break;
      case Node.ELEMENT_NODE :
        out.println( indent( level ) + nodeName );
        break;
      case Node.PROCESSING_INSTRUCTION_NODE :
        out.println( indent( level ) + "?" + nodeName + " " + nodeValue );
        break;
      case Node.TEXT_NODE :
        if ( nodeValue != null ) {
          // fix me
          String  newNodeValue = nodeValue.replace( '\n', '~' );
          out.println( "\t" + newNodeValue );
        }
        break;
    }
  }

  public String indent( int n ) {
    String s;
    for ( s = ""; n > 0; n-- )
      s += " ";
    return s;
  }

  public static void main( String[ ] args ) {
    if ( args.length != 1 ) {
      System.err.println( "USGAE: java Xml2TreeUsingDOM xmlfile");
      System.exit(1);
    }
    try {
      Xml2TreeUsingDOM  tree = new Xml2TreeUsingDOM();
      tree.makeDocTree( args[ 0 ] );
      System.exit(0);
    }
    catch ( Exception e) {
      out.println( "Error detected: " + e.getMessage() );
      System.exit(1);
    }
  }
}

XML文書のノード表現

このプログラムは,DOMとして記憶された文書のツリーのノード情報を表示するように,Xml2EsisUsingDOMを書き換えたものです。

プログラム実行条件

60mm60mm
プログラムDumpTreeUsingDOM
クラスパスcrimson.jar,jaxp.jar
コマンド引数XMLファイル

DumpTreeUsingDOM.java

import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.*;
public class DumpTreeUsingDOM {
  private int         level = 0;
  static PrintStream  out = System.out;
  DumpTreeUsingDOM() { }

  public void makeDocTree( String docName ) throws Exception {
    DocumentBuilderFactory  dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder         db = dbf.newDocumentBuilder();
    Document                doc = db.parse( new FileInputStream( docName ) );
    Element                 elem = doc.getDocumentElement();
    printNodeAllInfo( 'n', 0, elem );
  }

  public void printNodeAllInfo( char nodeT, int nodeN, Node node ) throws Exception {
    if ( node == null ) { out.println( indent( level ) + level + " " + "node is null." ); return; }
    String  nodeName = node.getNodeName();
    out.print( indent( level ) + level + " " );
    switch ( nodeT ) {
      case 'n' :
        out.print(  "(" + nodeN + ")" );
        break;
      case 'a' :
        out.print( "[" + nodeN + "]" );
        break;
      default :
        out.print( "???" );
        break;
    }
    out.print( " " + nodeName + "  " );
    int    type = node.getNodeType();
    String nodeType = "";
    switch (type) {
      case Node.ELEMENT_NODE :
        nodeType = "ELEMENT_NODE"; break;
      case Node.ATTRIBUTE_NODE :
        nodeType = "ATTRIBUTE_NODE"; break;
      case Node.TEXT_NODE :
        nodeType = "TEXT_NODE"; break;
      case Node.CDATA_SECTION_NODE :
        nodeType = "CDATA_SECTION_NODE"; break;
      case Node.ENTITY_REFERENCE_NODE :
        nodeType = "ENTITY_REFERENCE_NODE"; break;
      case Node.ENTITY_NODE :
        nodeType = "ENTITY_NODE"; break;
      case Node.PROCESSING_INSTRUCTION_NODE :
        nodeType = "PROCESSING_INSTRUCTION_NODE"; break;
      case Node.COMMENT_NODE :
        nodeType = "COMMENT_NODE"; break;
      case Node.DOCUMENT_NODE :
        nodeType = "DOCUMENT_NODE"; break;
      case Node.DOCUMENT_TYPE_NODE :
        nodeType = "DOCUMENT_TYPE_NODE"; break;
      case Node.DOCUMENT_FRAGMENT_NODE :
        nodeType = "DOCUMENT_FRAGMENT_NODE"; break;
      case Node.NOTATION_NODE :
        nodeType = "NOTATION_NODE"; break;
      default :
        nodeType = "?"; break;
    }
    out.print( nodeType + "  "  );
    String  nodeValue = node.getNodeValue();
    String  newNodeValue;
    if ( nodeValue != null ) {
      newNodeValue = nodeValue.replace( '\n', '~' );
    }
    else {
      newNodeValue = "";
    }
    out.println( "|" + newNodeValue + "|"  );
    boolean  hasAttributes = node.hasAttributes();
    if ( hasAttributes ) {
      NamedNodeMap  nameNodeMap = node.getAttributes();
      int  numberOfNodes = nameNodeMap.getLength();
      out.println( indent( level ) + "   " + nodeName + "'s attributes: " + numberOfNodes );
      level++;
      if ( numberOfNodes > 0 ) {
        for ( int  i = 0; i < numberOfNodes; i++ ) {
          printNodeAllInfo( 'a', i, nameNodeMap.item( i ) );
        }
      }
      level--;
    }
    boolean  hasChildNodes = node.hasChildNodes();
    if ( hasChildNodes ) {
      NodeList  nodeList = node.getChildNodes();
      int  numberOfChildren = nodeList.getLength();
      out.println( indent( level ) + "   " + nodeName + "'s children: " + numberOfChildren );
      level++;
      if ( numberOfChildren > 0 ) {
        for ( int  i = 0; i < numberOfChildren; i++ ) {
          printNodeAllInfo( 'n', i, nodeList.item( i ) );
        }
      }
      level--;
    }
  }

  public String indent( int n ) {
    String s;
    for ( s = ""; n > 0; n-- )
      s += "  ";
    return s;
  }

  public static void main( String[ ] args ) {
    if ( args.length != 1 ) {
      System.err.println( "USAGE: java DumpTreeUsingDOM xmlfile");
      System.exit(1);
    }
    try {
      DumpTreeUsingDOM  tree = new DumpTreeUsingDOM();
      tree.makeDocTree( args[ 0 ] );
      System.exit(0);
    }
    catch ( Exception e) {
      out.println( "Error detected: " + e.getMessage() );
      System.exit(1);
    }
  }
}

XML文書の生成

このプログラムは,ESIS形式 の文書データからDOMとしてXML文書を生成します。これは,実用的なプログラムではありませんが,線状のESISのストリームとツリー状のDOMとの関係や,DOMを構造的にアクセスする際の手法が確認できます。-vオプションを指定すると,詳細な進行状況を表示します。

プログラム実行条件

60mm60mm
プログラムHandleTreeUsingDOM
クラスパスcrimson.jar,jaxp.jar
コマンド引数ESISファイル[-v]

HandleTreeUsingDOM.java

import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.*;
import java.util.*;
public class HandleTreeUsingDOM {
  static  boolean      verbose = false;
  static  PrintStream  out = System.out;
  static  final  int   maxOfArrayOfNode  = 100;
  static  final  int   maxOfArrayOfOccur = 1000;
  static  final  int   maxOfArrayOfAttr  = 10;
  static  String       arrayOfNodeName[] = new String[maxOfArrayOfNode];
  static  int          arrayOfOccur[]    = new int[maxOfArrayOfOccur];
  static  String       arrayOfAttr[]     = new String[maxOfArrayOfAttr];;
  static  int          currLevel    = 0;
  static  int          traceLevel   = 0;
  static  int          indexOfAttr  = 0;
  static  int          level        = 0;

  HandleTreeUsingDOM() { }

  public Document  makeDocTree( String docName ) throws Exception {
    char          command;
    String        operands;
    DocumentType  doctype = null;
    Document      doc     = null;
    Node          root    = null;
    Node          parent  = null;
    Node          curr    = null;
    Element       element = null;
    Element       currElement = null;
    String        parentName;
    String        elementName;
    String        contents;
    Text          text;
    DocumentBuilderFactory  dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder         db  = dbf.newDocumentBuilder();
    DOMImplementation       di  = db.getDOMImplementation();
    BufferedReader  reader = new BufferedReader( new FileReader( docName ) );
    currLevel = -1;
    try {
      for ( String line = reader.readLine(); null != line; line = reader.readLine() ) {
        command  = line.charAt( 0 );
        operands = line.substring( 1, line.length() );
        if ( verbose ) out.println( "ESIS: "+command+" "+operands );
        switch ( command ) {
          case '(':
            elementName = operands;
            if ( currLevel == -1 ) {
              currLevel = 0;
              arrayOfOccur[currLevel] = 0;
              arrayOfOccur[currLevel+1] = -1;
              arrayOfNodeName[currLevel] = elementName;
              if ( verbose ) out.println( " "+currLevel+"("+arrayOfOccur[currLevel]+")  "+elementName );
              doctype = di.createDocumentType( elementName, "", "" );
              doc     = di.createDocument( "", elementName, doctype );
              root    = doc.getDocumentElement();
              curr    = root;
              element = (Element) root;
              if ( verbose ) out.println( " root:"+root.getNodeName() );
            }
            else {
              currLevel++;
              arrayOfOccur[currLevel]++;
              arrayOfOccur[currLevel+1] = -1;
              arrayOfNodeName[currLevel] = elementName;
              if ( verbose ) out.println( " "+currLevel+"("+arrayOfOccur[currLevel]+")  "+elementName );
              parentName = arrayOfNodeName[currLevel-1];
              if ( verbose ) out.println( " parent:"+(currLevel-1)+"("+arrayOfOccur[currLevel-1] +")  "+parentName);
              parent = moveToParent( doc, currLevel-1, arrayOfOccur[currLevel-1], parentName );
              if ( verbose ) out.println( " moveToParent... "+parent.getNodeName() );
              element = doc.createElement( elementName );
              if ( verbose ) out.println( " createElement... "+element.getNodeName() );
              curr = parent.appendChild( element );
              currElement = (Element) curr;
              if ( verbose ) out.println( " appendChild... "+parent.getNodeName()+" <= "+currElement.getNodeName() );
              if ( indexOfAttr > 0 ) {
                String  arrayOfToken[] = new String[100];
                for ( int  i = 0; i < indexOfAttr; i++ ) {
                  if ( verbose ) out.println( " ("+i+") "+arrayOfAttr[i] );
                  StringTokenizer ts = new StringTokenizer( arrayOfAttr[i] );
                  int  j = 0;
                  while ( ts.hasMoreTokens() )
                    arrayOfToken[j++] = ts.nextToken();
                  Attr  attr = doc.createAttribute( arrayOfToken[0] );
                  if ( verbose ) out.println( " createAttribute... "+attr.getName() );
                  currElement.setAttributeNode( attr );
                  if ( verbose ) out.println( " setAttributeNode... "+currElement.getNodeName()+" <= "+attr.getName() );
                  if ( arrayOfToken[1].equals( "TOKEN" ) ) {
                    // fix me
                    attr.setValue( arrayOfToken[2] );
                    if ( verbose ) out.println( " setValue...|"+arrayOfToken[2]+"|" );
                  }
                }
              }
              indexOfAttr = 0;
            }
            break;
          case ')' :
            elementName = operands;
            if ( verbose ) out.println( " "+currLevel+"("+arrayOfOccur[currLevel]+")  "+elementName );
            currLevel--;
            break;
          case 'A' :
            arrayOfAttr[indexOfAttr++] = operands;
            if ( verbose ) out.println( " "+currLevel+"["+arrayOfOccur[currLevel]+"]  "+operands );
            break;
          case '-' :
            contents = operands;
            currLevel++;
            arrayOfOccur[currLevel]++;
            arrayOfOccur[currLevel+1] = -1;
            arrayOfNodeName[currLevel] = "#text";
            if ( verbose ) out.println( " "+currLevel+"("+arrayOfOccur[currLevel]+")  "+contents );
            parentName = arrayOfNodeName[currLevel-1];
            if ( verbose ) out.println( " parent:"+(currLevel-1)+"("+arrayOfOccur[currLevel-1] +")  "+parentName);
            parent = moveToParent( doc, currLevel-1, arrayOfOccur[currLevel-1], parentName );
            if ( verbose ) out.println( " moveToParent... "+parent.getNodeName() );
            text = doc.createTextNode( contents );
            if ( verbose ) out.println( " createTextNode... "+text.getNodeName() );
            parent.appendChild( text );
            if ( verbose ) out.println( " appendChild... "+parent.getNodeName() );
            currLevel--;
            break;
          default :
            break;
        }
      }
    }
    catch ( DOMException e ) {
      e.printStackTrace();
      System.exit(1);
    }
    finally {
      reader.close();
      return( doc );
    }
  }

  public Node  moveToParent( Document doc, int level, int occur, String parentName ) {
    if ( verbose )
    out.println( " moveToParent(doc"+", "+level+", "+occur+", "+parentName+" )" );
    traceLevel = 0;
    Node node = doc.getDocumentElement();
    if ( verbose ) out.println( " root:"+node.getNodeName() );
    if ( traceLevel == level
      && parentName.equals( arrayOfNodeName[traceLevel] )
       ) {
      if ( verbose ) out.println( " found:"+node.getNodeName() );
      return( node );
    }
    traceLevel++;
    boolean  look = true;
    Node     child = null;
    while ( look ) {
      if ( verbose ) out.println( " traceLevel:"+traceLevel );
      NodeList  nodeList      = node.getChildNodes();
      boolean   hasChildNodes = node.hasChildNodes();
      if ( hasChildNodes ) {
        int  numberOfChildren = nodeList.getLength();
        if ( verbose ) out.println( " numberOfChildren:"+numberOfChildren );
        if ( numberOfChildren > 0 ) {
          child = nodeList.item( arrayOfOccur[traceLevel] );
          String childName = child.getNodeName();
          int    childType = child.getNodeType();
          if ( verbose ) out.println( " "+currLevel+"("+arrayOfOccur[currLevel] +")  child:"+childName+", type:"+childType+", array:"+arrayOfNodeName[traceLevel] );
          if ( childName.equals( arrayOfNodeName[traceLevel] )
            && parentName.equals( childName ) ) {
                if ( verbose ) out.println( " found:"+child.getNodeName() );
                look = false;
                break;
          }
          else {
             traceLevel++;
             if ( verbose ) out.println( " next:"+child.getNodeName() );
             node = child;
             continue;
          } // if
        } // if
      } // if
    } // while
    if ( verbose ) out.println( " return:"+child.getNodeName() );
    return( child );
  }

  public void printAllInfoOfDOM( Document doc ) throws Exception {
    try {
      Node  root = doc.getDocumentElement();
      level = 0;
      out.println( "" );
      printNodeAllInfo( 'n', 0, root );
    }
    catch ( DOMException e ) {
      e.printStackTrace();
      System.exit(1);
    }
  }

  public void printNodeAllInfo( char nodeT, int nodeN, Node node ) throws Exception {
    if ( node == null ) { out.println( indent( level ) + level + " " + "node is null." ); return; }
    String  nodeName = node.getNodeName();
    out.print( indent( level ) + level + " " );
    switch ( nodeT ) {
      case 'n' :
        out.print(  "(" + nodeN + ")" );
        break;
      case 'a' :
        out.print( "[" + nodeN + "]" );
        break;
      default :
        out.print( "???" );
        break;
    }
    out.print( " " + nodeName + "  " );
    int    type = node.getNodeType();
    String nodeType = "";
    switch (type) {
      case Node.ELEMENT_NODE :
        nodeType = "ELEMENT_NODE"; break;
      case Node.ATTRIBUTE_NODE :
        nodeType = "ATTRIBUTE_NODE"; break;
      case Node.TEXT_NODE :
        nodeType = "TEXT_NODE"; break;
      case Node.CDATA_SECTION_NODE :
        nodeType = "CDATA_SECTION_NODE"; break;
      case Node.ENTITY_REFERENCE_NODE :
        nodeType = "ENTITY_REFERENCE_NODE"; break;
      case Node.ENTITY_NODE :
        nodeType = "ENTITY_NODE"; break;
      case Node.PROCESSING_INSTRUCTION_NODE :
        nodeType = "PROCESSING_INSTRUCTION_NODE"; break;
      case Node.COMMENT_NODE :
        nodeType = "COMMENT_NODE"; break;
      case Node.DOCUMENT_NODE :
        nodeType = "DOCUMENT_NODE"; break;
      case Node.DOCUMENT_TYPE_NODE :
        nodeType = "DOCUMENT_TYPE_NODE"; break;
      case Node.DOCUMENT_FRAGMENT_NODE :
        nodeType = "DOCUMENT_FRAGMENT_NODE"; break;
      case Node.NOTATION_NODE :
        nodeType = "NOTATION_NODE"; break;
      default :
        nodeType = "?"; break;
    }
    out.print( nodeType + "  "  );
    String  nodeValue = node.getNodeValue();
    String  newNodeValue;
    if ( nodeValue != null ) {
      newNodeValue = nodeValue.replace( '\n', '~' );
    }
    else {
      newNodeValue = "";
    }
    out.println( "|" + newNodeValue + "|"  );
    boolean  hasAttributes = node.hasAttributes();
    if ( hasAttributes ) {
      NamedNodeMap  nameNodeMap = node.getAttributes();
      int  numberOfNodes = nameNodeMap.getLength();
      out.println( indent( level ) + "   " + nodeName + "'s attributes: " + numberOfNodes );
      level++;
      if ( numberOfNodes > 0 ) {
        for ( int  i = 0; i < numberOfNodes; i++ ) {
          printNodeAllInfo( 'a', i, nameNodeMap.item( i ) );
        }
      }
      level--;
    }
    boolean  hasChildNodes = node.hasChildNodes();
    if ( hasChildNodes ) {
      NodeList  nodeList = node.getChildNodes();
      int  numberOfChildren = nodeList.getLength();
      out.println( indent( level ) + "   " + nodeName + "'s children: " + numberOfChildren );
      level++;
      if ( numberOfChildren > 0 ) {
        for ( int  i = 0; i < numberOfChildren; i++ ) {
          printNodeAllInfo( 'n', i, nodeList.item( i ) );
        }
      }
      level--;
    }
  }

  public String indent( int n ) {
    String s;
    for ( s = ""; n > 0; n-- )
      s += "  ";
    return s;
  }

  public static void main( String[ ] args ) {
    if ( args.length == 0 || args.length > 2 ) {
      System.err.println( "USAGE: java HandleTreeUsingDOM esisfile [-v]");
      System.exit(1);
    }
    if ( args.length == 2 )
      verbose = ( args[1].equals( "-v" ) ? true : false );
    try {
      HandleTreeUsingDOM  tree = new HandleTreeUsingDOM();
      Document  doc = tree.makeDocTree( args[0] );
      tree.printAllInfoOfDOM( doc );
      System.exit(0);
    }
    catch ( Exception e) {
      out.println( "Error detected: "+e.getMessage() );
      System.exit(1);
    }
  }
}

XSL

XSLを学びます。

XSL変換

このプログラムは,XML文書をスタイルシートに従ってXSL変換(XSLT )します。

プログラム実行条件

60mm60mm
プログラムRunXSLT
クラスパスcrimson.jar,jaxp.jar,xalan.jar,xerces-1.2.3.jar
コマンド引数XMLファイル スタイルシート[ 出力形式[ エンコーディング ]]

RunXSLT.java

import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import java.io.File;
public class RunXSLT {

  public static void main(String[] args) throws Exception {
    File    xmlFile  = new File( args[0] );
    File    xslFile  = new File( args[1] );
    if ( args.length < 2 || args.length > 4 ) {
      System.err.println( "USAGE: java RunXSLT xmlfile xslfile [method [encoding] ]");
      System.exit(1);
    }
    try {
      Source  xml = new StreamSource( xmlFile );
      Source  xsl = new StreamSource( xslFile );
      Result  out = new StreamResult( System.out );
      TransformerFactory tf = TransformerFactory.newInstance();
      Transformer        t  = tf.newTransformer( xsl );
      if ( args.length >= 3 ) {
        t.setOutputProperty( OutputKeys.METHOD, args[2] );
      }
      else {
        t.setOutputProperty( OutputKeys.METHOD, "html" );
      }
      if ( args.length == 4 ) {
        t.setOutputProperty( OutputKeys.ENCODING, args[3] );
      }
      else {
        t.setOutputProperty( OutputKeys.ENCODING, "Shift_JIS" );
      }
      t.transform( xml, out );
      System.exit(0);
    }
    catch ( Exception e ) {
      e.printStackTrace();
      System.exit(1);
    }
  }
}

XSL:FO変換

このプログラムは,フォーマッティングオブジェクトで表現されたFOファイルをPDFへ変換し結果ファイルへ出力します。

プログラム実行条件

60mm60mm
プログラムRunXSLFO
クラスパスcrimson.jar,fop-0.17.0-jp.jar,jaxp.jar,xalan.jar,xerces-1.2.3.jar
コマンド引数FOファイル 結果ファイル

RunXSLFO.java

import org.w3c.dom.*;
import javax.xml.parsers.*;
import org.apache.fop.apps.*;
import org.apache.fop.render.*;
import org.apache.fop.fo.*;
import org.apache.fop.svg.*;
import java.io.*;
public class RunFO {

  public static void main( String[ ] args ) {
    if ( args.length != 2 ) {
      System.err.println( "USAGE: java RunFO fofile outFile");
      System.exit(1);
    }
    try {
      OutputStream outFile = new FileOutputStream( args[1] );
      DocumentBuilderFactory  dbf = DocumentBuilderFactory.newInstance();
      DocumentBuilder         db = dbf.newDocumentBuilder();
      Document                doc = db.parse( new FileInputStream( args[0] ) );
      Driver driver = new Driver( );
      driver.setRenderer( "org.apache.fop.render.pdf.PDFRenderer", "1.0" );
      driver.addElementMapping( "org.apache.fop.fo.StandardElementMapping" );
      driver.addElementMapping( "org.apache.fop.svg.SVGElementMapping" );
      driver.addPropertyList( "org.apache.fop.fo.StandardPropertyListMapping" );
      driver.addPropertyList( "org.apache.fop.svg.SVGPropertyListMapping" );
      driver.buildFOTree( doc );
      driver.setOutputStream( outFile );
      driver.format();
      driver.render();
      System.exit(0);
    }
    catch ( Exception e ) {
      e.printStackTrace();
      System.exit(1);
    }
  }
}

XML文書からPDFへの変換

このプログラムは,XML文書をスタイルシートに従ってフォーマッティングオブジェクトに変換し,次いでFOファイルをPDFへ変換し結果ファイルへ出力するように,RunXSLTとRunFOを合わせたものです。

プログラム実行条件

60mm60mm
プログラムRunXSLFO
クラスパスcrimson.jar,fop-0.17.0-jp.jar,jaxp.jar,xalan.jar,xerces-1.2.3.jar
コマンド引数 ソースファイル スタイルシート 変換結果

RunXSLFO.java

import org.w3c.dom.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import org.apache.fop.apps.*;
import org.apache.fop.render.*;
import org.apache.fop.fo.*;
import org.apache.fop.svg.*;
import java.io.*;
public class RunXSLFO {
  static int          level = 0;
  static PrintStream  writer = System.out;

  public static void main( String[ ] args ) {
    if ( args.length != 5 ) {
      System.err.println( "USAGE: java RunXSLFO xmlfile xslfile fofile encoding outFile");
      System.exit(1);
    }
    try {
      // XSLT
      Source  xml = new StreamSource( new File( args[0] ) );
      Source  xsl = new StreamSource( new File( args[1] ) );
      Result  fo  = new StreamResult( new File( args[2] ) );
      String  encoding  = args[3];
      TransformerFactory tf = TransformerFactory.newInstance();
      Transformer        t  = tf.newTransformer( xsl );
      t.setOutputProperty( OutputKeys.METHOD, "xml" );
      t.setOutputProperty( OutputKeys.ENCODING, encoding );
      t.transform( xml, fo );
      // FOP
      OutputStream outFile = new FileOutputStream( args[4] );
      DocumentBuilderFactory  dbf = DocumentBuilderFactory.newInstance();
      DocumentBuilder         db = dbf.newDocumentBuilder();
      Document                doc = db.parse( new FileInputStream( args[2] ) );
      Driver driver = new Driver( );
      driver.setRenderer( "org.apache.fop.render.pdf.PDFRenderer", "1.0" );
      driver.addElementMapping( "org.apache.fop.fo.StandardElementMapping" );
      driver.addElementMapping( "org.apache.fop.svg.SVGElementMapping" );
      driver.addPropertyList( "org.apache.fop.fo.StandardPropertyListMapping" );
      driver.addPropertyList( "org.apache.fop.svg.SVGPropertyListMapping" );
      driver.buildFOTree( doc );
      driver.setOutputStream( outFile );
      driver.format();
      driver.render();
      System.exit(0);
    }
    catch ( Exception e ) {
      e.printStackTrace( writer );
      System.exit(1);
    }
  }
}

仕様の要約

ESIS

ESISESIS:Element Structure Information Set,要素構造情報集合 は,ISO/IEC 13673で定義されたSGMLデータ表現形式であり,通常,SGMLパーザーから出力されます。ESISにはSGML宣言,文書型定義,文書インスタンスの各々の情報がすべて含まれていますので,PerlやJavaなどによる後処理が容易です。次の表はその一部です。

20mm50mm90mm
コマンドオペランド意味
(共通識別子この共通識別子を持つ要素が開始したことを表わす。この要素の属性は,Aコマンドで指定される。
)共通識別子この共通識別子を持つ要素が終了したことを表わす。
-データこのデータを表わす。
?データこのデータを含む処理命令を表わす。
A属性名 IMPLIED属性名が省略され,その値が#IMPLIEDであることを表わす。
A属性名 CDATA 文字データ属性名の内容型がCDATAであることと,その値を文字データで表わす。
A属性名 NOTATION 記法名属性名の内容型がNOTATIONであることと,その記法名を表わす。
A属性名 ENTITY 一般実体名 ...属性名の内容型がENTITYまたはENTITIESであることと,その一般実体名のリストを表わす。各実体名は,Iコマンド,Eコマンド,Sコマンドで指定される。
A属性名 TOKEN 字句 ...属性名の内容型がその他の属性で,字句のリストが値を表わす。
&外部データ実体名この外部データ実体名を持つ外部データ実体への参照を表わす。外部データ実体名は,Eコマンドで指定される。

DOM

DOMDOM:Document Object Model は,文書をノードの集まりで記憶しています。次の表は,関数で取り出せるノードの情報を表わします。

30mm30mm30mm30mm30mm
ノードgetNodeType()getNodeName()getNodeValue()getAttributes()
ElementELEMENT_NODEタグ名nullNameNodeMap
AttrATTRIBUTE_NODE属性名属性値null
TextTEXT_NODE#text内容null
CDATASectionCDATA_SECTION_NODE#cdata-section内容null
EntityReferenceENTITY_REFERENCE_NODE実体参照名nullnull
EntityENTITY_NODE実体名nullnull
ProcessingInstructionPROCESSING_INSTRUCTION_NODEターゲット名名前を除く内容null
CommentCOMMENT_NODE#comment内容null
DocumentDOCUMENT_NODE#documentnullnull
DocumentTypeDOCUMENT_TYPE_NODE文書型名nullnull
DocumentFragmentDOCUMENT_FRAGMENT_NODE#document-fragmentnullnull
NotationNOTATION_NODE記法名nullnull

XSLT

XSLTXSLT:XSL Transformation,XSL変換 は,XSL仕様の前段に相当します。タグの変換をスタイルシート(変換規則の並び)として表わします。次の表はその一部です。

80mm80mm
変換規則変換の機能
<xsl:template match="パターン"> 変換規則の並び </xsl:template> パターンで指定された要素が出現した場合に,その変換規則の並びを適用する。
<xsl:value-of select="パターン"/> パターンで指定された要素の内容をここに挿入する。
<xsl:attribute name="属性名"> 属性値 </xsl:attribute> 直前の要素に対して属性(属性名="属性値")を追加する。
<xsl:if test="パターン"> 変換規則の並び </xsl:if> パターンで指定された要素が出現した場合,あるいはパターンの比較式が真である場合に,その変換規則の並びを適用する。
<xsl:choose> 場合分けの並び </xsl:choose> 場合分けを表わす。
<xsl:when test="パターン"> 変換規則の並び </xsl:when> <xsl:when>は,パターンで指定された要素が出現した場合,あるいはパターンの比較式が真である場合に,その変換規則の並びを適用する。これは場合の数だけ指定する。
<xsl:otherwise> 変換規則の並び </xsl:otherwise> <xsl:otherwise>は,場合分けの<xsl:when>すべてに一致しない場合に,その変換規則の並びを適用する。
<xsl:for-each select="パターン"> 変換規則の並び </xsl:for-each> パターンで指定された要素が反復して出現する度に,変換規則の並びを繰り返し適用する。

CSS

CSSCSS:Cascade Style Sheet,段階スタイルシート は,HTML文書の既定の表示を変更します。次の表はその一部です。

40mm60mm60mm
特性名特性値意味
displayblock, inline, list-item, none表示の仕方
font-family名前フォントのファミリ名
font-size長さフォントのサイズ
font-stylenormal, italic, obliqueフォントのスタイル
line-height行の高さ
color文字色
background-color背景色
text-indent長さ字下げ
text-alignleft, right, justify, center行揃え
margin-left長さ左マージン
margin-right長さ右マージン
border-width長さ境界の線幅
border-color境界の線色

サンプルデータ

CARDS.DTD

CARDS.DTDは,幾つかの個人情報から成る名簿の文書型を定義します。

<!ELEMENT  CARDS        (CARD+) --名簿-->
<!ELEMENT  CARD          (NAME,ORG?,STATUS?,ADDR,PHONE?) --個人情報-->
<!ELEMENT  NAME          (FAMILY,FIRST) --姓名-->
<!ELEMENT  FAMILY        (#PCDATA) --姓-->
<!ELEMENT  FIRST        (#PCDATA) --姓-->
<!ELEMENT  ORG          (#PCDATA) --組織-->
<!ELEMENT  STATUS        (#PCDATA) --役職-->
<!ELEMENT  ADDR          (#PCDATA) --住所-->
<!ELEMENT  PHONE        (CITY, #PCDATA) --電話番号-->
<!ELEMENT  CITY          (#PCDATA) --市外局番-->

MYCARDS.XML

MYCARDS.XMLは,CARDS型で表わされた名簿の一例を表わしている文書インスタンスです。

<?xml version="1.0" encoding="Shift_JIS"?>
<?xml-stylesheet type="text/xsl" href="CARDS.XSL"?>
<!DOCTYPE BOOKS SYSTEM "CARDS.DTD">
<CARDS>
<CARD>
<NAME><FAMILY>岸</FAMILY><FIRST>和孝</FIRST></NAME>
<ORG>飯豊山書林</ORG>
<ADDR>福島県喜多方市松山町鳥見山字下堰下4608</ADDR>
<PHONE><CITY>0241</CITY>22-3981</PHONE>
</CARD>
<CARD>
<NAME><FAMILY>北条</FAMILY><FIRST>時宗</FIRST></NAME>
<ORG>鎌倉幕府</ORG>
<STATUS>執権</STATUS>
<ADDR>武蔵国鎌倉鶴岡</ADDR>
</CARD>
</CARDS>

BOOKS.DTD

BOOKS.DTDは,幾つかの書誌情報から成る図書目録の文書型を定義します。

<!ELEMENT  BOOKS        (BOOK+) --図書目録-->
<!ELEMENT  BOOK          (TITLE,(AUTHOR|TRANSLATOR),PUBLISHER,DATE,ISBN) --書誌情報-->
<!ELEMENT  TITLE        (#PCDATA) --表題-->
<!ATTLIST  TITLE  TITLE  CDATA  #IMPLIED --原題--
                  SYLL  CDATA  #REQUIRED --振り仮名-->
<!ELEMENT  AUTHOR        (#PCDATA) --著者-->
<!ELEMENT  TRANSLATOR    (#PCDATA) --訳者-->
<!ATTLIST  TRANSLATOR    AUTHOR  CDATA  #IMPLIED --原著者-->
<!ELEMENT  PUBLISHER    (#PCDATA) --出版者-->
<!ATTLIST  PUBLISHER    PUBLISHER  CDATA  #IMPLIED --原書出版者-->
<!ELEMENT  DATE          (#PCDATA) --発行日-->
<!ATTLIST  DATE  DATE    CDATA  #IMPLIED --原書発行日-->
<!ELEMENT  ISBN          (#PCDATA) --国際標準図書番号-->

MYBOOKS.XML

MYBOOKS.XMLは,BOOKS型で表わされた図書目録の一例を表わしている文書インスタンスです。

<?xml version="1.0" encoding="Shift_JIS"?>
<?xml-stylesheet type="text/xsl" href="BOOKS.XSL"?>
<!DOCTYPE BOOKS SYSTEM "BOOKS.DTD">
<BOOKS>
<BOOK><TITLE SYLL="ぱずるほうかい">パズル崩壊</TITLE><AUTHOR>法月綸太郎</AUTHOR><PUBLISHER>集英社</PUBLISHER><DATE>1999/9/25</DATE><ISBN>4-08-747098-9</ISBN></BOOK>
<BOOK><TITLE TITLE="SAVAGES" SYLL="ひんしのもり,ゆうしのやり">瀕死の森,勇士の槍</TITLE><TRANSLATOR AUTHOR="Joe Kane">池田真紀子</TRANSLATOR><PUBLISHER PUBLISHER="The Spieler Agency">新潮社</PUBLISHER><DATE DATE="1995">1999/2/1</DATE><ISBN>4-10-218211-X</ISBN></BOOK>
<BOOK><TITLE SYLL="そうるとぴょんやん">ソウルと平壌</TITLE><AUTHOR>萩原遼</AUTHOR><PUBLISHER>文藝春秋</PUBLISHER><DATE>1998/10/10</DATE><ISBN>4-16-726004-2</ISBN></BOOK>
<BOOK><TITLE SYLL="たにうちろくろうてんらんかい">谷内六郎展覧会</TITLE><AUTHOR>谷内六郎</AUTHOR><PUBLISHER>新潮社</PUBLISHER><DATE>1982/5/25</DATE><ISBN>4-10-125206-8</ISBN></BOOK>
<BOOK><TITLE TITLE="UNNATURAL EXPOSURE" SYLL="せっしょく">接触</TITLE><TRANSLATOR AUTHOR="Patricia D. Cornwell">相原真理子</TRANSLATOR><PUBLISHER PUBLISHER="International Creative Management">講談社</PUBLISHER><DATE DATE="1997">1997/12/15</DATE><ISBN>4-06-263659-X</ISBN></BOOK>
</BOOKS>

BOOKS.XSL

BOOKS.XSLは,MYBOOKS.XMLをHTML文書へ変換するためのスタイルシートです。

<?xml version="1.0" encoding="Shift_JIS"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <HTML>
      <HEAD>
        <TITLE>図書目録</TITLE>
      </HEAD>
      <BODY>
        <TABLE BORDER="1">
        <TR>
          <TH>書名</TH>
          <TH>著者・訳者</TH>
          <TH>出版者<BR/>(原出版者)</TH>
          <TH>発行年<BR/>(原発行年)</TH>
          <TH>ISBN番号</TH>
        </TR>
        <xsl:for-each select="BOOKS/BOOK">
         <xsl:sort select="TITLE/@SYLL" lang="ja" data-type="text" order="ascending"/>
          <TR>
            <TD>
              <FONT SIZE="+1" COLOR="BLUE">
              <xsl:value-of select="TITLE"/>
              </FONT>
              <xsl:if test="TITLE/@TITLE">
                <BR/>原題:<xsl:value-of select="TITLE/@TITLE"/>
              </xsl:if>
           </TD>
            <TD>
              <xsl:choose>
                <xsl:when test="AUTHOR">
                  <xsl:value-of select="AUTHOR"/> 著
                </xsl:when>
                <xsl:when test="TRANSLATOR">
                  <xsl:value-of select="TRANSLATOR"/> 訳
                  <BR/><xsl:value-of select="TRANSLATOR/@AUTHOR"/> 著
               </xsl:when>
              </xsl:choose>
            </TD>
            <TD>
              <xsl:value-of select="PUBLISHER"/>
              <xsl:if test="PUBLISHER/@PUBLISHER">
                <BR/>(<xsl:value-of select="PUBLISHER/@PUBLISHER"/>)
              </xsl:if>
            </TD>
            <TD>
              <xsl:value-of select="DATE"/>
              <xsl:if test="DATE/@DATE">
                <BR/>(<xsl:value-of select="DATE/@DATE"/>)
              </xsl:if>
            </TD>
            <TD>
              <xsl:value-of select="ISBN"/>
            </TD>
          </TR>
        </xsl:for-each>
        </TABLE>
      </BODY>
    </HTML>
  </xsl:template>
</xsl:stylesheet>

TEXT.XSL

TEXT.XSLは,このHTML文書(java_xml.htm)をPDFへ変換するためのスタイルシートです。

<?xml version="1.0" encoding="Shift_JIS"?>
<xsl:stylesheet version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:fo="http://www.w3.org/1999/XSL/Format">

<!-- 書誌情報 -->
<xsl:variable name="cover-title"><xsl:value-of select="html/head/title"/></xsl:variable>
<xsl:variable name="cover-subtitle"><xsl:value-of select="html/body/span[@class='cover-subtitle']"/></xsl:variable>
<xsl:variable name="cover-issue"><xsl:value-of select="html/body/span[@class='cover-issue']"/></xsl:variable>
<xsl:variable name="cover-author"><xsl:value-of select="html/body/span[@class='cover-author']"/></xsl:variable>
<xsl:variable name="cover-status"><xsl:value-of select="html/body/span[@class='cover-status']"/></xsl:variable>

<!-- テンプレート -->
<xsl:template match="/">
  <xsl:processing-instruction name="cocoon-format">type="text/xslfo"</xsl:processing-instruction>
  <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <!-- ページの条件 -->
    <fo:layout-master-set>
       <fo:simple-page-master master-name="A4-1"
                             page-width="210mm"
                             page-height="297mm"
                             margin-top="20mm"
                             margin-bottom="20mm"
                             margin-left="30mm"
                             margin-right="20mm">
        <fo:region-body   margin-top="0mm"/>
        <fo:region-before extent="10mm"/>
      </fo:simple-page-master>
      <fo:simple-page-master master-name="A4-2"
                             page-width="210mm"
                             page-height="297mm"
                             margin-top="20mm"
                             margin-bottom="20mm"
                             margin-left="30mm"
                             margin-right="20mm">
        <fo:region-body   margin-top="10mm"/>
        <fo:region-before extent="10mm"/>
      </fo:simple-page-master>

      <fo:page-sequence-master master-name="basic" >
        <fo:repeatable-page-master-alternatives>
          <fo:conditional-page-master-reference master-name="A4-1" page-position="first"/>
          <fo:conditional-page-master-reference master-name="A4-2" page-position="rest"/>
          <fo:conditional-page-master-reference master-name="A4-2"/>
        </fo:repeatable-page-master-alternatives>
      </fo:page-sequence-master>
    </fo:layout-master-set>

    <!-- 表紙 -->
    <fo:page-sequence master-name="basic">
      <fo:flow flow-name="xsl-region-body">
        <!-- 表題 -->
        <fo:block font-size="40pt"
                  font-family="Osaka"
                  background-color="black"
                  color="white"
                  text-align="center"
                  margin-left="20mm"
                  margin-right="20mm"
                  space-before.optimum="50mm"
                  padding-top="10mm"
                  padding-bottom="10mm">
          <xsl:value-of select="html/head/title"/>
        </fo:block>
        <!-- 副題 -->
        <fo:block font-family="Osaka"
                  font-size="20pt"
                  text-align="center"
                  space-before.optimum="30mm">
          <xsl:copy-of select="$cover-subtitle"/>
        </fo:block>
        <!-- 発行日 -->
        <fo:block font-size="16pt"
                  font-family="Osaka"
                  text-align="center"
                  space-before.optimum="60mm">
          <xsl:copy-of select="$cover-issue"/>
        </fo:block>
        <!-- 著者 -->
        <fo:block font-size="20pt"
                  font-family="Osaka"
                  text-align="center"
                  space-before.optimum="20mm">
          <xsl:copy-of select="$cover-author"/>
        </fo:block>
        <!-- 役職 -->
        <fo:block font-size="16pt"
                  font-family="Osaka"
                  text-align="center"
                  space-before.optimum="20mm">
          <xsl:copy-of select="$cover-status"/>
        </fo:block>
      </fo:flow>
    </fo:page-sequence>

    <!-- 本文 -->
    <fo:page-sequence master-name="basic"
                      initial-page-number="1">
      <fo:static-content flow-name="xsl-region-before">
        <fo:block text-align="end"
                  font-size="10pt"
                  font-family="Osaka">
          <xsl:value-of select="html/head/title"/> <fo:page-number/>
        </fo:block>
      </fo:static-content>
      <fo:flow flow-name="xsl-region-body">
        <xsl:apply-templates select="html/body"/>
      </fo:flow>
    </fo:page-sequence>

    <!-- 奥付 -->
    <fo:page-sequence master-name="basic">
      <fo:flow flow-name="xsl-region-body">
        <fo:block border-width="0.5mm"
                  background-color="lime"
                  break-before="page"
                  space-before.optimum="100mm"
                  margin-left="40mm"
                  margin-right="40mm"
                  text-align="start">
                <fo:block font-family="Osaka"
                          font-size="12pt"
                          line-height="14pt"
                          text-align="center">
                  <xsl:copy-of select="$cover-title"/>
                </fo:block>
                <fo:block font-family="Osaka"
                          font-size="10pt"
                          line-height="12pt"
                          text-align="center">
                  - <xsl:copy-of select="$cover-subtitle"/> -
                </fo:block>
                <fo:block font-family="Osaka"
                          font-size="10pt"
                           line-height="14pt"
                         text-align="center">
                  (C) <xsl:copy-of select="$cover-issue"/>
                </fo:block>
                <fo:block font-family="Osaka"
                          font-size="12pt"
                          line-height="14pt"
                          text-align="center">
                  <xsl:copy-of select="$cover-author"/>
                </fo:block>
        </fo:block>
      </fo:flow>
    </fo:page-sequence>

  </fo:root>
</xsl:template>

<!-- 章の見出し -->
<xsl:template match="html/body/h1">
  <fo:block font-size="18pt"
            font-family="Osaka"
            line-height="20pt"
            text-align="center"
            space-before.optimum="8pt"
            space-after.optimum="8pt"
            break-before="page">
    第<xsl:number/>章 <xsl:apply-templates/>
  </fo:block>
</xsl:template>

<!-- 節の見出し -->
<xsl:template match="html/body/h2">
  <fo:block font-size="16pt"
            font-family="Osaka"
            line-height="18pt"
            text-align="start"
            text-indent="-10pt"
            margin-left="-10pt"
            space-before.optimum="8pt"
            space-after.optimum="8pt">
    <xsl:number level="any" count="h1"/>.<xsl:number level="any" from="h1" count="h2"/> <xsl:apply-templates/>
  </fo:block>
</xsl:template>

<!-- 項の見出し -->
<xsl:template match="html/body/h3">
  <fo:block font-size="14pt"
            font-family="Osaka"
            line-height="16pt"
            text-align="start"
            text-indent="-10pt"
            margin-left="-10pt"
            space-before.optimum="8pt"
            space-after.optimum="8pt">
    <xsl:apply-templates/>
  </fo:block>
</xsl:template>

<xsl:template match="html/body/h4">
  <fo:block font-size="12pt"
            font-family="Osaka"
            line-height="14pt"
            text-align="start"
            text-indent="-10pt"
            margin-left="-6pt"
            space-before.optimum="8pt"
            space-after.optimum="8pt">
    <xsl:apply-templates/>
  </fo:block>
</xsl:template>

<!-- 段落 -->
<xsl:template match="html/body/p">
  <fo:block font-size="12pt"
            font-family="Osaka"
            line-height="14pt"
            text-align="justify"
            text-indent="12pt"
            space-before.optimum="4pt"
            space-after.optimum="4pt">
    <xsl:apply-templates/>
  </fo:block>
</xsl:template>

<xsl:template match="html/body/pre">
  <xsl:choose>
   <!-- 目次 -->
   <xsl:when test="@class[.='toc']">
    <fo:block font-size="16pt"
              font-family="Osaka"
              line-height="18pt"
              text-align="center">
      目次
    </fo:block>
    <fo:table space-before.optimum="8pt"
              space-after.optimum="8pt">
      <fo:table-column column-width="160mm"/>
      <fo:table-body>
        <fo:table-row>
          <fo:table-cell background-color="white">
            <fo:block font-size="12pt"
                      font-family="Osaka"
                      line-height="14pt"
                      white-space-collapse="false">
              <xsl:apply-templates/>
            </fo:block>
          </fo:table-cell>
        </fo:table-row>
      </fo:table-body>
    </fo:table>
   </xsl:when>
   
   <!-- ソースコード -->
   <xsl:when test="@class[.='code']">
     <fo:table space-before.optimum="8pt"
               space-after.optimum="8pt">
       <fo:table-column column-width="160mm"/>
         <fo:table-body>
           <fo:table-row>
             <fo:table-cell background-color="lightblue">
               <fo:block font-size="12pt"
                         font-family="Osaka"
                         line-height="14pt"
                         white-space="pre"
                         white-space-collapse="false">
                 <xsl:apply-templates/>
               </fo:block>
             </fo:table-cell>
         </fo:table-row>
       </fo:table-body>
     </fo:table>
   </xsl:when>
   
   <!-- 画面表示内容 -->
   <xsl:when test="@class[.='window']">
     <fo:table space-before.optimum="8pt"
               space-after.optimum="8pt">
       <fo:table-column column-width="160mm"/>
         <fo:table-body>
           <fo:table-row>
             <fo:table-cell background-color="yellow">
               <fo:block font-size="12pt"
                         font-family="Osaka"
                         line-height="14pt"
                         white-space-collapse="false">
                 <xsl:apply-templates/>
               </fo:block>
             </fo:table-cell>
         </fo:table-row>
       </fo:table-body>
     </fo:table>
   </xsl:when>
 </xsl:choose>
</xsl:template>

<!-- テーブル -->
<xsl:template match="html/body/table">
  <fo:table space-before.optimum="8pt"
            space-after.optimum="8pt">
    <xsl:apply-templates select="span"/>
    <fo:table-body>
      <xsl:apply-templates select="tr"/>
    </fo:table-body>
  </fo:table>
</xsl:template>

<xsl:template match="html/body/table/tr">
  <fo:table-row>
    <xsl:apply-templates/>
  </fo:table-row>
</xsl:template>

<xsl:template match="html/body/table/tr/th">
  <fo:table-cell border-width="0.5mm"
                 background-color="aqua">
    <fo:block font-family="Osaka"
              font-size="10pt"
              text-align="center">
      <xsl:apply-templates/>
    </fo:block>
  </fo:table-cell>
</xsl:template>

<xsl:template match="html/body/table/tr/td">
  <fo:table-cell border-width="0.5mm"
                 background-color="pink">
    <fo:block font-family="Osaka"
              font-size="10pt">
      <xsl:apply-templates/>
    </fo:block>
  </fo:table-cell>
</xsl:template>

<!-- 箇条書き -->
<xsl:template match="html/body/ul">
  <fo:list-block space-before.optimum="8pt"
                 space-after.optimum="8pt">
    <xsl:apply-templates/>
  </fo:list-block >
</xsl:template>

<xsl:template match="html/body/ul/li">
  <fo:list-item>
   <fo:list-item-label>
     <fo:block>
       <fo:inline font-family="Osaka">・</fo:inline>
     </fo:block>
   </fo:list-item-label>
   <fo:list-item-body>
     <fo:block font-family="Osaka">
       <xsl:apply-templates/>
     </fo:block>
   </fo:list-item-body>
  </fo:list-item>
</xsl:template>

<xsl:template match="html/body/dl">
  <fo:list-block space-before.optimum="8pt"
                 space-after.optimum="8pt">
    <xsl:apply-templates/>
  </fo:list-block >
</xsl:template>

<xsl:template match="html/body/dl/dt">
  <fo:list-item>
   <fo:list-item-label>
     <fo:block>
       <fo:inline font-family="Osaka">・</fo:inline>
     </fo:block>
   </fo:list-item-label>
   <fo:list-item-body>
     <fo:block font-family="Osaka">
       <xsl:apply-templates/>
     </fo:block>
   </fo:list-item-body>
  </fo:list-item>
</xsl:template>

<xsl:template match="html/body/dl/dt/dd">
  <fo:list-item font-family="Osaka"
                margin-left="12pt">
   <fo:list-item-label>
     <fo:block>
       <fo:inline font-family="Osaka">-</fo:inline>
     </fo:block>
   </fo:list-item-label>
   <fo:list-item-body>
     <fo:block>
       <xsl:apply-templates/>
     </fo:block>
   </fo:list-item-body>
  </fo:list-item>
</xsl:template>

<xsl:template match="//span">
  <xsl:choose>
    <!-- テーブルのカラム幅 -->
    <xsl:when test="@class[.='column-width']">
     <fo:table-column>
       <xsl:attribute name="column-width"><xsl:value-of select="."/></xsl:attribute>
     </fo:table-column>
   </xsl:when>
   <!-- 脚注 -->
   <xsl:when test="@class[.='footnote']">
     <fo:footnote>
      <fo:inline font-family="Osaka"
                 font-size="6pt"
                 color="green"
                 vertical-align="super">
         [<xsl:number level="any" from="h1"/>]</fo:inline>
      <fo:footnote-body>
        <fo:block font-family="Osaka"
                  font-size="10pt"
                  color="green"
                  text-indent="-20pt"
                  margin-left="-5pt">
         [<xsl:number level="any" from="h1"/>]<xsl:apply-templates/>
        </fo:block>
       </fo:footnote-body>
     </fo:footnote>
   </xsl:when>
  </xsl:choose>
</xsl:template>

<!-- リンク -->
<xsl:template match="//a">
 <xsl:choose>
  <xsl:when test="substring(@href,1,4)='http'">
    <fo:inline>
      <fo:basic-link color="blue">
        <xsl:attribute name="external-destination"><xsl:value-of select="@href"/></xsl:attribute>
        <xsl:apply-templates/>
      </fo:basic-link>
    </fo:inline>
  </xsl:when>
  <xsl:when test="substring(@href,1,3)='ftp'">
    <fo:inline>
      <fo:basic-link color="blue">
        <xsl:attribute name="external-destination"><xsl:value-of select="@href"/></xsl:attribute>
        <xsl:apply-templates/>
      </fo:basic-link> 
    </fo:inline>
  </xsl:when>
  <xsl:when test="substring(@href,1,6)='mailto'">
    <fo:inline white-space="nowrap">
      <fo:basic-link color="blue">
        <xsl:attribute name="external-destination"><xsl:value-of select="@href"/></xsl:attribute>
          <xsl:apply-templates/>
      </fo:basic-link>
    </fo:inline>
  </xsl:when>
  <xsl:when test="substring(@href,1,1)='#'">
    <fo:inline>
      <fo:basic-link color="blue">
        <xsl:attribute name="internal-destination"><xsl:value-of select="substring(@href,2)"/></xsl:attribute>
        <xsl:apply-templates/>
      </fo:basic-link>
    </fo:inline>
  </xsl:when>
  <xsl:when test="@name">
    <fo:inline>
        <xsl:attribute name="id"><xsl:value-of select="@name"/></xsl:attribute>
      <xsl:apply-templates/>
    </fo:inline>
  </xsl:when>
  <xsl:otherwise>
     ???<xsl:apply-templates/>???
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>

<!-- 外部画像 -->
<xsl:template match="//img">
  <fo:inline>
    <fo:external-graphic>
      <xsl:attribute name="src">file:<xsl:value-of select="@src"/></xsl:attribute>
    </fo:external-graphic>
  </fo:inline>
</xsl:template>

<!-- 上付き文字 -->
<xsl:template match="//sup">
  <fo:inline font-family="Osaka"
             font-size="6pt"
             vertical-align="super">
    <xsl:apply-templates/>
  </fo:inline>
</xsl:template>

<!-- 下付き文字 -->
<xsl:template match="//sub">
  <fo:inline font-family="Osaka"
             font-size="6pt"
             vertical-align="sub">
    <xsl:apply-templates/>
  </fo:inline>
</xsl:template>

<!-- テキスト内容 -->
<xsl:template match="text()">
  <xsl:value-of select="."/>
</xsl:template>

</xsl:stylesheet>

処理に先立って,このHTML文書(java_xml.htm)の先頭に次の宣言を追加しXML文書としてください。

<?xml version="1.0" encoding="Shift_JIS"?>

このHTML文書では,冊子形式を表わすためにHTML文書型に次のような拡張解釈を与えています。ウェブブラウザーにおいてこれらがPDFと(全く同じにはなりませんが)同様なスタイルで表示されるようにCSS によって指示しています。

100mm
HTMLタグ
<span class="cover-subtitle">副題</span>
<span class="cover-issue">発行日</span>
<span class="cover-author">著者</span>
<span class="cover-status">役職</span>
<span class="column-width">テーブルのカラム幅</span>
<span class="footnote">脚注</span>
<pre class="toc">目次の区画</pre>
<pre class="code">ソースコードの区画</pre>