第11章のサンプルコード
---------------------
目次（ページ番号）
■P239
■P240
■P242-1
■P242-2
■P245
■P246
■P247
■P251
■P253
---------------------

■P239
<?xml version="1.0" encoding="utf-8"?>
<book>
  <title>XMLのサンプル</title>
  <chapter id="introduction">
    <title>紹介</title>
    <para><emphasis>XML</emphasis>（Extensible Markup Language）
      は、W3Cという団体によって定義された「汎用マークアップ言語」です。</para>
    <para>不等号（&lt;、&gt;）を表すには、&amp;lt;と&amp;gt;を使います。
    </para>
  </chapter>
</book>

■P240
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "docbookx.dtd">
<book>
  <title>XMLのサンプル</title>
  <chapter id="introduction">
    <title>紹介</title>
    <para><emphasis>XML</emphasis>（Extensible Markup Language）
      は、W3Cという団体によって定義された「汎用マークアップ言語」です。</para>
    <para>不等号（&lt;、&gt;）を表すには、&amp;lt;と&amp;gt;を使います。
    </para>
  </chapter>
</book>

■P242-1
# 簡単なXMLパーサ
#  xml-parse.pl

use XML::Parser;
$parser = new XML::Parser( );
eval ( "\$parser->parsefile( \@ARGV[0] );" );

if ($@) {
  print @ARGV[0] . "は不正なXMLドキュメントです。エラーは次のとおり: $@";
} else {
  print @ARGV[0] . "は正しいXMLドキュメントです。\n";
}

■P242-2
# 簡単なXMLパーサ（エラーメッセージを最適化）
#  xml-parse2.pl

use XML::Parser;
$parser = new XML::Parser( );
eval ( "\$parser->parsefile( \@ARGV[0] );" );

if ($@) {
  chomp($@);
  $@ =~ s/^\n//;
  $@ =~ s/ at (?:[A-Z]:)?\/.*//;
  print @ARGV[0] . "は不正なXMLドキュメントです (エラー: $@)。\n";
} else {
  print @ARGV[0] . "は正しいXMLドキュメントです。\n";
}

■P245
# 要素名と属性を表示する
#  element.pl
use XML::Parser;

# ハンドラ付きでオブジェクトを作成
$parser = new XML::Parser( Handlers => 
                          {Start => \&element_start,
                           End => \&element_end });

# インデントのカウンタ
$level = 0;

# 解析の実行
eval ( "\$parser->parsefile( \@ARGV[0] );");

if ($@) {
  chomp($@);
  $@ =~ s/^\n//;
  $@ =~ s/ at (?:[A-Z]:)?\/.*//;
  print @ARGV[0] . "は不正なXMLドキュメントです (エラー: $@)。\n";
}

sub element_start {
  # 要素の開始
  my ($expat, $name, %attributes) = @_;
  print "  " x $level;
  # 要素名、属性を表示
  print $name;
  if (%attributes) {
    print ": ";
    foreach (keys ( %attributes ) ) {
      print "$_=" . $attributes{$_} . " ";
    }
  }
  print "\n";
  $level++;
}

sub element_end {
  # 要素の終了
  $level--;
}

■P246
# コメントをcomment要素に変換してXMLを出力
#  comment_converter.pl
use encoding "utf8", STDOUT=>"Shift_JIS";
use XML::Parser;

# ハンドラ付きでオブジェクトを作成
$parser = new XML::Parser( Handlers => 
                          {Start => \&element_start,
                           Char => \&cdata,
                           Comment => \&comment,
                           End => \&element_end });

# 解析の実行
eval ( "\$parser->parsefile( \@ARGV[0] );");

if ($@) {
  chomp($@);
  $@ =~ s/^\n//;
  $@ =~ s/ at (?:[A-Z]:)?\/.*//;
  print @ARGV[0] . "は不正なXMLドキュメントです (エラー: $@)。\n";
}

sub element_start {
  # 要素の開始
  my ($expat, $name, %attributes) = @_;
  print "<$name";
  if (%attributes) {
    foreach (keys ( %attributes ) ) {
      print " $_=\"" . $attributes{$_} . "\"";
    }
  }
  print ">";
}

sub element_end {
  # 要素の終了
  my ($expat, $name) = @_;
  print "</$name>\n";
}

sub cdata {
  # テキストデータ
  my ($expat, $context) = @_;
  print $context if ($context !~ /^\s+$/);
}

sub comment {
  # コメント。要素に変換する
  my ($expat, $context) = @_;
  # 実体参照への変換
  $context =~ s/\&/\&amp;/g;
  $context =~ s/</\&lt;/g;
  $context =~ s/>/\&gt;/g;

  print "<comment>$context</comment>\n" if ($context !~ /^\s+$/);
}

■P247
<?xml version="1.0" encoding="utf-8"?>
<book>
  <title>XMLのサンプル</title>
  <chapter id="introduction" keyword="sample">
    <title><!-- XMLの -->紹介</title>
    <para><emphasis>XML</emphasis>（Extensible Markup Language）
      は、W3Cという団体によって定義された「汎用マークアップ言語」です。</para>
    <para><!-- 不等号（<;、>;）を表すには、&lt;と&gt;を使います。--></para>
  </chapter>
</book>

■P251
# XPathによる検索
#  xpath.pl

use encoding "utf8", STDOUT=>"Shift-JIS";
use XML::XPath;

$xpath = new XML::XPath ( filename => $ARGV[0] );
# パスの検索
$nodeset = $xpath->find($ARGV[1]);

foreach ($nodeset->get_nodelist( )) {
  # ノードの内容を表示
  print $_->toString( ) . "\n";
}

■P253
# XPathによる検索カウンタ
#  xpath_counter.pl

use XML::XPath;
$xpath = new XML::XPath ( filename => $ARGV[0] );

# パスの存在確認
if ($xpath->exists($ARGV[1])) {
  # パスの検索
  $nodeset = $xpath->find($ARGV[1]);
  print "パス $ARGV[1] は " . $nodeset->size( )  . " 個あります。\n";
} else {
  print "パス $ARGV[1] はありません。\n";
}
