ASXをRuby/Perl/PHPで

前回に引き続き3言語での実装まとめ。

今回は、テンプレートとして用意されたasxファイルを読み込み、再生するメディアを指定されたものへ変更、ブラウザへ出力するところまでを作成します。再生するメディアはここでは固定としますが、実際にはDBや設定ファイルなどから取得したりします。また、再生リストで表示する各メディアのタイトルについても少しだけ説明します。

ASXの概要についてははてなの説明を見て頂くとして、実装するに当たってMicrosoft社のWindows Media™ メタファイルの活用を参考にしてください。


主な処理内容は以下の通りです

  1. テンプレートを読み込む
  2. DOMを使って再生メディアを指定する要素・属性を変更
  3. 文字コードShift_JISに変更
  4. ヘッダの送出
  5. ASXファイルの内容を出力

文字コードShift_JISにするのには訳があり、上述の様に再生リストに表示する各メディアのタイトルを表示させる為です。Media PlayerではShift_JISのみが対応しているようです。

では最初にテンプレートファイルの中身です。UTF-8で保存します。

<ASX version="3.0">
<title>再生リストのタイトル</title>
   <Entry>
      <title>メディアのタイトル</title>
      <ref HREF="http://localhost/wmv/foo.wmv"/>
   </Entry>
</ASX>

タイトル要素は無くても構いません。今回は使用しません。

Perl

一番シンプルに書く事ができました。

use XML::DOM;
use Encode;

$parser = new XML::DOM::Parser;
$dom = $parser->parsefile("asx_template_japanese.asx");
my $nodeList = $dom->getElementsByTagName("ref");
$nodeList->item(0)->setAttribute('HREF', 'http://localhost/wmv/bar.wmv');

print "Content-type: application/vnd.ms-asf; charset='Shift_JIS'\n";
print 'Content-Disposition: inline; filename="test.asx"' , "\n";
print "\n";

print Encode::encode('shiftjis', $dom->toString);

$dom->dispose;

上の処理内容以外に説明すべきところは特にありませんが、CGIモジュールを使ってもいいでしょう。

PHP

<?php
$doc = new DOMDocument();
$doc->formatOutput = true;
$doc->load('asx_template_japanese.asx');

$ref = $doc->getElementsByTagName("ref");
$the_ref = $ref->item(0);
$the_ref->removeAttribute("HREF");
$the_ref->setAttribute("HREF", "http://localhost/wmv/bar.wmv");

$asx = $doc->getElementsByTagName('ASX');

header('Content-type: application/vnd.ms-asf; charset="Shift_JIS"');
header('Content-Disposition: inline; filename="test.asx"');

echo mb_convert_encoding($doc->saveXML($asx->item(0)), "SJIS", "UTF-8");
?>

DOMDocumentをsaveXML()でそのまま出力してしまうと、XML宣言まで出力されてしまうので、ASX要素以下のみを出力しています。

Ruby

require "rexml/document"
require "kconv"

xml_file_name = "asx_template_japanese.asx"

doc = nil
File.open(xml_file_name) {|xmlfile|
	doc = REXML::Document.new(xmlfile)
}

doc.get_elements("/ASX/Entry/ref")[0].delete_attribute('HREF')
doc.get_elements("/ASX/Entry/ref")[0].add_attribute('HREF', "http://localhost/wmv/bar.wmv")

normalized_str = doc.to_s
s = ""
normalized_str.split("\n").each { |line| s << line.strip }
s.gsub!(/'/, '"')

print "Content-type: application/vnd.ms-asf; charset='Shift_JIS'\n"
print 'Content-Disposition: inline; filename="test.asx"' , "\n"
print "\n"

print Kconv.tosjis(s)

REXMLモジュールは属性をシングルクォートで括って出力します。しかしMedia Playerはダブルクォートで括られていないとエラーが出てしまうので、出力前に置換してあげています。ロジックはDeleting my Blogから頂きました。
XPATHを使って要素を取得できるので、他の言語のgetElementsByTagName()よりは分りやすいかも知れません。


ツッコミどころがあると思いますが、その際はトラックバック、コメントなど頂ければ幸いです。なお、エラーハンドリングは省略してありますので、実際に使用される場合は、その辺気を付けてくださいね。