各リンク凡例: … Netflix、 … Amazon Prime Video、 … YouTube、 … WOWOW on Demand
(リンク先で配信終了となっている場合があります)
<記事 日付="2023-12-03" 見出し="STRANGE NEW WORLDS" 状態="公開">
<エピ情報>
<シリーズ名>SNW</シリーズ名>
<シーズン番号>1</シーズン番号>
<話数>1</話数>
<t:エピタイ xml:lang="en" is原題="true" 直訳="奇妙な新世界">STRANGE NEW WORLDS</t:エピタイ>
<t:エピタイ xml:lang="ja">ストレンジ・ニュー・ワールド</t:エピタイ>
<翻訳>佐藤恵子</翻訳>
<翻訳>川嶋加奈子</翻訳>
<ツッコミファイル名>SNW1.html</ツッコミファイル名>
<ツッコミリンク>
<a href="SNW1.html#STRANGE NEW WORLDS">STRANGE NEW WORLDS</a>
</ツッコミリンク>
<評価>
<値 name="A">1</値>
<値 name="B">0</値>
<値 name="C">9</値>
<値 name="D">9</値>
<値 name="E">1</値>
<値 name="F">0</値>
<値 name="総合">-14</値>
</評価>
<動画リンク>
<a href="https://wod.wowow.co.jp/content/148475" target="new">
<img src="http://www1.coralnet.or.jp/yonetch/img/play_button_wow.png" alt="シーズン1-1: ストレンジ・ニュー・ワールド" title="シーズン1-1: ストレンジ・ニュー・ワールド" class="t_size" />
</a>
</動画リンク>
</エピ情報>
<カテゴリ>スター・トレック</カテゴリ>
<サブカテゴリ>翻訳ツッコミ
<サブカテゴリ> SNW第1シーズン</サブカテゴリ></サブカテゴリ>
</記事>
<記事 日付="" 見出し="" 状態="下書き">
<エピ情報>
<シリーズ名>SNW</シリーズ名>
<シーズン番号>2</シーズン番号>
<話数>1</話数>
<t:エピタイ xml:lang="en" is原題="true">THE BROKEN CIRCLE</t:エピタイ>
<t:エピタイ xml:lang="ja">壊れた環</t:エピタイ>
<ツッコミファイル名>SNW2.html</ツッコミファイル名>
<動画リンク>
<a href="https://wod.wowow.co.jp/content/154648" target="new">
<img src="http://www1.coralnet.or.jp/yonetch/img/play_button_wow.png" alt="シーズン2-1: 壊れた環" title="シーズン2-1: 壊れた環" class="t_size" />
</a>
</動画リンク>
</エピ情報>
<カテゴリ>スター・トレック</カテゴリ>
<サブカテゴリ>翻訳ツッコミ
<サブカテゴリ> SNW第2シーズン</サブカテゴリ></サブカテゴリ>
</記事>
【tsukkomi_list.xml(一部)】
これで表の作成時は、改めて検索・生成する必要なく、単にコピーするだけですみ、処理時間の短縮が望める。なお、以前はエピソード情報の有無そのものでツッコミ情報の有無を示していたが、今後は全エピソードの中間ファイルとなるので、「状態」という属性値も追加し「公開/下書き」という値をツッコミ情報の有無として使用する。CreateObject("InternetExplorer.Application").Visible=true
備考: まあ、EdgeのIEモードが全く使えないというわけではないが、やはりIEの方が軽いのと、英単語の意味をちょっと調べたいときに、右クリックでBing翻訳が使えるのが少し便利(なぜかEdgeのIEモードだとBing翻訳は動かない)
備考: ちなみに Strawberry Perl でも留意点がある。最新の 5.38.xx をインストールすると、「日本語をサポートしない」のような警告がでるようになっている。検索の結果、5.28.xx なら出ないという情報があり、そちらを使うことにした。
備考: 元々のネトフリオリジナルのTTMLでは、当然正しい書式のIDを使っていた。ワタシにとっては単に冗長にしか思えなったのでカットしたのだ。msxsl.exe や XML Notepad では何も問題なかったのに...
エピソード指向というヤツである。以前、ツッコミもネトフリリンクも「エピソードの情報」という観点から述べたが、違う観点からもエピソードそのものを中心に据えるべきという結論に至った。設計の是非についてより支持度が上がった気がしてちょっとウレシイ(^^)
2019.06.01追記: アマゾン・プライム・ビデオの配信情報に対応して拡張。同じエピソードが複数の配信元にリンクできる。テンプレート「エピソード」について、タイムシークリンクの際には専らネットフリックスの字幕idと決め打ちしていたが、他メディア由来のものも使えるように変更した。アマゾンへのリンクの際でも、ネトフリやDVDの字幕情報を参照できる。
XML::Simpleだろう。インストールは CPAN から簡単に行える。
use XML::Simple;
use Data::Dumper;
my $xml = new XML::Simple();
my $data = $xml->XMLin('DB_07_DSC.xml');
print Dumper($data);
【xmlsimle_test1.pl】
<?xml version="1.0" encoding="shift_jis"?>
<t:エピソード集 xmlns:t="urn:tables">
<t:エピ>
<t:シリーズ名>DSC</t:シリーズ名>
<t:シーズン番号>1</t:シーズン番号>
<t:話数>1</t:話数>
<t:原題 直訳="">THE VULCAN HELLO</t:原題>
<t:邦題>バルカンの挨拶</t:邦題>
<t:収録 メディア="DVD" ディスク番号="1" タイトル番号="1">
<t:尺 />
</t:収録>
<t:収録 メディア="Netflix" タイトル番号="1" URL="https://www.netflix.com/watch/80126025">
<字幕ファイル>subtitles\yn_DSC1-1.ttml</字幕ファイル>
<翻訳>大岩剛</翻訳>
<t:尺>43</t:尺>
</t:収録>
<t:ツッコミファイル>tsukkomi\DSC1-1.xml</t:ツッコミファイル>
</t:エピ>
(略)
</t:エピソード集>
【DB_07_DSC.xml(エピソード情報ファイル)】
C:\Users\Owner\Documents\xmltest\xmlsimple>perl test.pl
Couldn't open encmap shift_jis.enc:
No such file or directory
at C:/Perl/lib/XML/Parser.pm line 187.
XML::Simple called at test.pl line 4.
'shift_jis.enc' というファイルがないと言っている。が、さんざんググってみたところ、それを配布していたサイトが現在は閉鎖され入手不可。すなわち、入力ファイルを SJIS で記述することが問題の根幹である。use XML::Simple;
use Encode;
use utf8;
use Data::Dumper;
{
package Data::Dumper;
sub qquote { return shift; }
}
$Data::Dumper::Useperl = 1;
binmode STDIN, ':encoding(cp932)';
binmode STDOUT, ':encoding(cp932)';
binmode STDERR, ':encoding(cp932)';
$file = "DB_07_DSC_sjis.xml";
open(IN, $file);
while(<IN>)
{
s@encoding=\"Shift_JIS\"@encoding=\"UTF-8\"@i;
$line .= encode "utf-8", decode("shift_jis", $_);
}
close IN;
my $xml = new XML::Simple();
my $data = $xml->XMLin($line);
print Dumper($data);
【xmlsimle_test2.pl】
コードの実行結果及び紆余曲折の中身は割愛し、以下に要点のみ掲げる。備考: 理想としては最初からUTF-8にすべきだが、既にSJISで書かれたXMLファイルばかりなので上記ソースでは内部でコード変換している
参考サイト: Data::DumperでUTF-8フラグつき文字列をエスケープさせないようにするには
捕捉: 「ゴチャゴチャ」「ワケがわからん」というのは、ハッシュの理解ができていないワタシ個人の責任であり、当該のコードが不出来という意味合いは一切ございません(^^;
XML::LibXMLである。これもインストールは CPAN から簡単に行える。このパーサのいいところは、取り込んだ後のデータアクセスに XPath が使えることだ。すなわち、いままでXSLTで培ってきたデータ操作手法をそのままPerlに持ち込むことができる(と思われる)。
参考サイト: PerlのXML::LibXMLモジュールでShift_JISのXMLのパース
use utf8;
use warnings;
use XML::LibXML;
use Encode;
binmode STDIN, ':encoding(cp932)';
binmode STDOUT, ':encoding(cp932)';
binmode STDERR, ':encoding(cp932)';
$file = "DB_07_DSC_sjis.xml";
open(IN, $file);
while(<IN>)
{
s@encoding=\"Shift_JIS\"@encoding=\"UTF-8\"@i;
$line .= encode "utf-8", decode("shift_jis", $_);
}
close IN;
my $parser = XML::LibXML->new();
my $dom = $parser->parse_string($line);
my $tags = $dom->findnodes("//t:エピ[t:原題/\@直訳!='']/t:原題");
my @eachLines;
foreach my $tag(@$tags){
push (@eachLines, $tag->serialize);
}
my $joinedTxt = join("\n",@eachLines);
print $joinedTxt . "\n";
【libxml_test.pl】
<t:原題 直訳="臨機応変は王者の特権">CONTEXT IS FOR KINGS</t:原題>
<t:原題 直訳="肉屋のナイフは子羊の悲鳴にも躊躇しない">THE BUTCHER'S KNIFE CARES NOT FOR THE LAMB'S CRY</t:原題>
<t:原題 直訳="汝の苦痛を選べ">CHOOSE YOUR PAIN</t:原題>
<t:原題 直訳="忘却の川">LETHE</t:原題>
<t:原題 直訳="まっとう至極な男を狂わす魔法">MAGIC TO MAKE THE SANEST MAN GO MAD</t:原題>
<t:原題 直訳="汝平和を欲さば、戦への備えをせよ">SI VIS PACEM, PARA BELLUM</t:原題>
<t:原題 直訳="我の行く森の奥深くへ">INTO THE FOREST I GO</t:原題>
<t:原題 直訳="思いがけずして">DESPITE YOURSELF</t:原題>
<t:原題 直訳="内なる狼">THE WOLF INSIDE</t:原題>
<t:原題 直訳="はやり立つ野心">VAULTING AMBITION</t:原題>
<t:原題 直訳="ここからがいよいよ本題だ">WHAT'S PAST IS PROLOGUE</t:原題>
<t:原題 直訳="戦争の内と外で">THE WAR WITHOUT, THE WAR WITHIN</t:原題>
<t:原題 直訳="手を引いてくれる?">WILL YOU TAKE MY HAND?</t:原題>
<t:原題 直訳="兄弟">BROTHER</t:原題>
<t:原題 直訳="光の点">POINT OF LIGHT</t:原題>
<t:原題 直訳="逝く者の手向け">AN OBOL FOR CHARON</t:原題>
<t:原題 直訳="欠陥の聖者">SAINTS OF IMPERFECTION</t:原題>
<t:原題 直訳="雷の音">THE SOUNDS OF THUNDER</t:原題>
<t:原題 直訳="もしも記憶が確かなら">IF MEMORY SERVES</t:原題>
<t:原題 直訳="ダイダロス計画">PROJECT DAEDALUS</t:原題>
<t:原題 直訳="赤い天使">THE RED ANGEL</t:原題>
<t:原題 直訳="絶え間なき永遠">PERPETUAL INFINITY</t:原題>
<t:原題 直訳="影の谷をぬけて">THROUGH THE VALLEY OF SHADOWS</t:原題>
【実行結果(結局XMLジャンというツッコミはなし^^;)】
ここでもポイントだけ挙げておくと(ファイルの文字コードに関する制限は前と同様として)、print OUT encode("cp932", $text) . "\n";
open(OUT, ">", encode("cp932",$filename)) or die("error");
<t:エピ>
<t:シリーズ名>DSC</t:シリーズ名>
<t:シーズン番号>2</t:シーズン番号>
<t:話数>7</t:話数>
<t:原題 直訳="">LIGHT AND SHADOWS</t:原題>
<t:邦題>光と影</t:邦題>
<t:収録 メディア="Netflix" タイトル番号="7" URL="https://www.netflix.com/watch/80992617">
<字幕ファイル>subtitles\yn_DSC2-7.ttml</字幕ファイル>
<t:尺>56</t:尺>
<翻訳>大岩剛</翻訳>
</t:収録>
<t:ツッコミファイル>tsukkomi\DSC2-7.xml</t:ツッコミファイル>
</t:エピ>
補足: この前提として、シーズン毎にまとまっていたツッコミ原稿をエピソード毎に分割した。そもそも以前に一部は行っていたが、ここへきてそれが奏功しているのがちょっとウレシイ(^^)
<記事 日付="2019-03-10" 見出し="LIGHT AND SHADOWS" 状態="公開">
<エピ情報>
<シリーズ名>DSC</シリーズ名>
<シーズン番号>2</シーズン番号>
<話数>7</話数>
<邦題>光と影</邦題>
<ツッコミファイル名>DSC2.html</ツッコミファイル名>
<評価>
<値 name="A">0</値>
<値 name="B">1</値>
<値 name="C">5</値>
<値 name="D">2</値>
<値 name="E">0</値>
<値 name="F">0</値>
<値 name="総合">3</値>
</評価>
</エピ情報>
<カテゴリ>スター・トレック</カテゴリ>
<サブカテゴリ>翻訳ツッコミ
<サブカテゴリ>DSC第2シーズン</サブカテゴリ>
</サブカテゴリ>
</記事>
【tsukkomi_list.xml(一部)】
捕捉: こうみると、エピソードDBとカブる項目だらけなんだが、この際なので評価表に必要なものは全てとりこむことにした。
備考: XMLでは「オーバーライド」という言い方はしないのかもしれないが、カッコいいから使ってみた(^^)
<?xml version="1.0" encoding="shift_jis"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:t="urn:tables" >
<xsl:output method="html" encoding="Shift_JIS" />
<xsl:include href="st_eval_base.xsl" />
<xsl:template match="/">
<HTML>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=shift_jis" />
<link rel="stylesheet" type="text/css" href="http://www1.coralnet.or.jp/yonetch/hpbsite.css"/>
</head>
<BODY>
<xsl:comment>解析</xsl:comment>
<H1>翻訳ツッコミ 評価ランキング(ver. 2.0α)</H1>「クソ訳」係数導入、及びTAS対応版
<P align="right">
<FONT size="-1">
<<A href="#bottom">BOTTOM</A>>
</FONT>
<A name="top"></A>
<BR/>
</P>
<xsl:call-template name="評価表">
<xsl:with-param name="エピ">
<xsl:copy-of select="//記事[エピ情報]"/>
</xsl:with-param>
</xsl:call-template>
<BR/>
<HR/>
<P align="right">
<FONT size="-1">
<A name="bottom">
<<A href="#top">TOP</A>>
</A>
</FONT>
</P>
</BODY>
</HTML>
</xsl:template>
<xsl:template name="評価表">
<xsl:param name="エピ"/>
<TABLE cellSpacing="0" cellPadding="0" align="center" border="0">
<TBODY>
<TR>
<TD class="td0">
<TABLE cellSpacing="1" cellPadding="4" align="center" border="0">
<THEAD>
<TR>
<TH align="middle" width="260" rowSpan="2">
<B>
<span style="letter-spacing:1em;">サブタイトル</span>
</B>
</TH>
<TH align="middle" colSpan="6">
<B>
<span style="letter-spacing:3em;">評価</span>
</B>
</TH>
<TH align="middle" width="50" rowSpan="2">
<B>総<BR />合
</B>
</TH>
</TR>
<TR>
<xsl:for-each select="$台帳//t:評価/t:レベル">
<TH align="middle" width="50">
<FONT size="-1">
<xsl:value-of select="t:値[@name='表現']"/>
</FONT>
</TH>
</xsl:for-each>
</TR>
</THEAD>
<TBODY>
<xsl:call-template name="apply-sort">
<xsl:with-param name="エピ">
<xsl:copy-of select="$エピ"/>
</xsl:with-param>
</xsl:call-template>
</TBODY>
</TABLE>
</TD>
</TR>
</TBODY>
</TABLE>
</xsl:template>
<xsl:template name="apply-sort">
<xsl:param name="エピ"/>
<xsl:apply-templates select="msxsl:node-set($エピ)/*">
<xsl:sort select="エピ情報/評価/値[@name='総合']" data-type="number" order="descending"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="記事[not(エピ情報)]"/>
<xsl:template match="記事[エピ情報]">
<xsl:variable name="更新日MJD">
<xsl:call-template name="ymd2mjd">
<xsl:with-param name="ymd">
<xsl:value-of select="@日付"/>
</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<tr>
<xsl:attribute name="class">
<xsl:if test="(position() mod 2)=1">td1</xsl:if>
<xsl:if test="(position() mod 2)=0">td2</xsl:if>
</xsl:attribute>
<td align="left">
<xsl:call-template name="エピ情報">
<xsl:with-param name="en_subtitle">
<xsl:value-of select="@見出し" />
</xsl:with-param>
<xsl:with-param name="option">0x09 </xsl:with-param>
</xsl:call-template>
<br/>
<xsl:value-of select="エピ情報/邦題"/>
<xsl:call-template name="シリーズ名">
<xsl:with-param name="series">
<xsl:value-of select="エピ情報/シリーズ名"/>
</xsl:with-param>
</xsl:call-template>
<xsl:if test="$基準日MJD - $更新日MJD < 365">
<font size="-1">
<xsl:attribute name="color">
<xsl:choose>
<xsl:when test="$基準日MJD - $更新日MJD < 30">#ff0000</xsl:when>
<xsl:when test="$基準日MJD - $更新日MJD < 90">#ff7f7f</xsl:when>
<xsl:when test="$基準日MJD - $更新日MJD < 180">#ff8989</xsl:when>
<xsl:when test="$基準日MJD - $更新日MJD < 270">#ffc489</xsl:when>
<xsl:otherwise>#ffcccc</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<b>
<i>New!</i>
</b>
</font>
</xsl:if>
</td>
<xsl:for-each select="エピ情報/評価/値[@name!='総合']">
<td>
<xsl:value-of select="."/>
</td>
</xsl:for-each>
<td>
<b>
<xsl:value-of select="エピ情報/評価/値[@name='総合']"/>
</b>
</td>
</tr>
</xsl:template>
<xsl:template name="シリーズ名">
<xsl:param name="series"/>
<font size="-1">
[<xsl:value-of select="$series"/>]
</font>
</xsl:template>
</xsl:stylesheet>
【st_eval_rank.xsl】
<?xml version="1.0" encoding="shift_jis"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dt="urn:schemas-microsoft-com:datatypes" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:t="urn:tables" >
<xsl:import href="st_eval_rank.xsl" />
<xsl:output method="html" encoding="Shift_JIS" />
<xsl:template match="/">
<HTML>
<head>
<link rel="stylesheet" type="text/css" href="http://www1.coralnet.or.jp/yonetch/hpbsite.css"/>
</head>
<BODY>
<xsl:comment>解析</xsl:comment>
<H1>翻訳ツッコミ 更新順リスト</H1>
<P align="right">
<FONT size="-1">
<<A href="#bottom">BOTTOM</A>>
</FONT>
<A name="top"></A>
<BR/>
</P>
<xsl:call-template name="評価表">
<xsl:with-param name="エピ">
<xsl:for-each select="//記事[エピ情報 and @日付!='']">
<xsl:variable name="更新日MJD">
<xsl:call-template name="ymd2mjd">
<xsl:with-param name="ymd">
<xsl:value-of select="@日付"/>
</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsl:if test="$基準日MJD - $更新日MJD < 270">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:with-param>
</xsl:call-template>
<BR/>
<HR/>
<P align="right">
<FONT size="-1">
<A name="bottom">
<<A href="#top">TOP</A>>
</A>
</FONT>
</P>
</BODY>
</HTML>
</xsl:template>
<xsl:template name="apply-sort">
<xsl:param name="エピ"/>
<xsl:apply-templates select="msxsl:node-set($エピ)/*">
<xsl:sort select="@日付" order="descending"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
【st_eval_moddt.xsl】
断っておくが、上記は抜粋ではなく全ソースである。インポートを使うことで改変部のみの記述ですむため、なんとシンプルで美しいコードであることか!これまでは共通のスタイルシートを使い、コマンドラインオプションを指定してそれぞれ場合分けをするようなことをしていた。通常の手続き型言語の呪縛にどっぷり浸かっていたことがよくわかる。この、コードで場合分けせず、スタイルシート自体を変えてオーバーライドによって場合分けするというのが、XSLTらしい書き方なのだろうとようやくわかった気がする(飽くまで自分の勝手な理解に過ぎないが)。
<?xml version="1.0" encoding="shift_jis"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dt="urn:schemas-microsoft-com:datatypes" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:t="urn:tables" >
<xsl:import href="st_eval_moddt.xsl" />
<xsl:import href="st_table.xsl"/>
<xsl:output method="html" encoding="Shift_JIS" />
<xsl:variable name="記事">
<xsl:copy-of select="document('tsukkomi_list.xml')/日記/記事[エピ情報]" />
</xsl:variable>
<xsl:template match="/">
<HTML>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=shift_jis" />
<link rel="stylesheet" type="text/css" href="http://www1.coralnet.or.jp/yonetch/hpbsite.css"/>
<title>スター・トレック エピソードリスト</title>
</head>
<BODY>
<xsl:comment>解析</xsl:comment>
<H1>翻訳ツッコミこ〜な〜</H1>吹替版の翻訳に対して入れたツッコミを集計しました。以下のような数量化を行っています。閲覧の際の参考にしてください。
<ul>
<xsl:apply-templates select="msxsl:node-set($台帳)/t:台帳/t:評価/t:レベル"/>
</ul>
<A name="top"></A>
<P align="right">
<FONT size="-1"><
<A href="#bottom">BOTTOM</A>>
</FONT>
</P>
<xsl:apply-templates />
<A name="bottom"></A>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="t:略称[@name!='MOV']">
<xsl:variable name="シリーズ名">
<xsl:value-of select="@name" />
</xsl:variable>
<H2>
<A>
<xsl:attribute name="name">
<xsl:value-of select="@name" />
</xsl:attribute>
<xsl:value-of select="concat(t:値[@name='邦題'],' (',@name,')')" />
</A>
<xsl:value-of select="concat(' ',' ')" />
<xsl:for-each select="t:値[@name='シーズン']">
<font size="-1">[
<A>
<xsl:attribute name="href">
<xsl:value-of select="concat('#',../@name,.)" />
</xsl:attribute>
<xsl:call-template name="序数">
<xsl:with-param name="no">
<xsl:value-of select="." />
</xsl:with-param>
</xsl:call-template>
</A>]
</font>
</xsl:for-each>
</H2>
<xsl:for-each select="t:値[@name='シーズン']">
<xsl:variable name="シーズン番号">
<xsl:value-of select="."/>
</xsl:variable>
<H3>
<A>
<xsl:attribute name="name">
<xsl:value-of select="concat(../@name,.)" />
</xsl:attribute>
<xsl:value-of select="concat('第',.,'シーズン')" />
</A>
</H3>
<xsl:call-template name="評価表">
<xsl:with-param name="エピ">
<xsl:copy-of select="msxsl:node-set($記事)/記事[エピ情報/シリーズ名=$シリーズ名 and エピ情報/シーズン番号=$シーズン番号]"/>
</xsl:with-param>
</xsl:call-template>
<P align="right">
<FONT size="-1">
<A name="bottom"><
<A href="#top">TOP</A>>
</A>
</FONT>
</P>
<HR/>
</xsl:for-each>
<xsl:if test="position()!=last()">
<HR/>
</xsl:if>
</xsl:template>
<xsl:template match="t:略称[@name='MOV']">
<xsl:variable name="シリーズ名">
<xsl:value-of select="@name" />
</xsl:variable>
<H2>
<A>
<xsl:attribute name="name">
<xsl:value-of select="@name" />
</xsl:attribute>
<xsl:value-of select="concat(t:値[@name='邦題'],' (',@name,')')" />
</A>
<xsl:value-of select="concat(' ',' ')" />
</H2>
<xsl:call-template name="評価表">
<xsl:with-param name="エピ">
<xsl:copy-of select="msxsl:node-set($記事)/記事[エピ情報/シリーズ名=$シリーズ名]"/>
</xsl:with-param>
</xsl:call-template>
<P align="right">
<FONT size="-1">
<A name="bottom"><
<A href="#top">TOP</A>>
</A>
</FONT>
</P>
<HR/>
<HR/>
</xsl:template>
<xsl:template match="t:シリーズ">
<xsl:apply-templates>
<xsl:sort order="ascending" select="t:値[@name='シリーズ番号']"/>
</xsl:apply-templates>
<HR/>
</xsl:template>
<xsl:template match="t:シリーズ" mode="index">
<HR/>
<B>
<FONT size="+1">
<xsl:for-each select="t:略称">
<xsl:sort order="ascending" select="t:値[@name='シリーズ番号']"/>[
<A>
<xsl:attribute name="href">
<xsl:value-of select="concat('#',@name)" />
</xsl:attribute>
<xsl:value-of select="@name" />
</A>]
</xsl:for-each>
</FONT>
</B>
<HR/>
</xsl:template>
<xsl:template match="t:レベル">
<LI>
<B>
<span style="letter-spacing:1em;">
<xsl:value-of select="t:値[@name='表現']" />
</span>(係数:
<xsl:value-of select="t:値[@name='係数']" />)
</B>
<BR />
<xsl:value-of select="t:値[@name='説明']" />
</LI>
</xsl:template>
<xsl:template name="シリーズ名">
<xsl:param name="series"/>
</xsl:template>
<xsl:template name="apply-sort">
<xsl:param name="エピ"/>
<xsl:apply-templates select="msxsl:node-set($エピ)/*">
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
【st_eval_tbl.xsl】
ここでのポイントは、テンプレート「シリーズ名」で、『何もしない』ことである。全シリーズ混在の表ではシリーズ名を付記していたが、シリーズ毎の表でそれは必要ない。だから『何もしない』のだ。この辺りがオーバーライドを駆使した美しい書法だと思う。<?xml version="1.0" encoding="shift_jis"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:t="urn:tables" >
<xsl:output method="text" encoding="Shift_JIS" />
<xsl:strip-space elements="*"/>
<xsl:include href="st_eval_base.xsl" />
<xsl:template match="記事[エピ情報 and .//シリーズ名!='MOV']">
<xsl:variable name="原題">
<xsl:value-of select="@見出し"/>
</xsl:variable>
<xsl:value-of select="concat(
エピ情報/ツッコミファイル名,',',
'"',$原題,'",',
エピ情報/評価/値[@name='A'],',',
エピ情報/評価/値[@name='B'],',',
エピ情報/評価/値[@name='C'],',',
エピ情報/評価/値[@name='D'],',',
エピ情報/評価/値[@name='E']+エピ情報/評価/値[@name='F'],','
)"/>
<xsl:variable name="更新日MJD">
<xsl:call-template name="ymd2mjd">
<xsl:with-param name="ymd">
<xsl:value-of select="@日付"/>
</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$基準日MJD - $更新日MJD < 180">1</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="記事[not(エピ情報) or .//シリーズ名='MOV']"/>
<xsl:template match="シリーズ名|シーズン番号|話数|邦題|ツッコミファイル名|評価|値|カテゴリ|サブカテゴリ"/>
</xsl:stylesheet>
【st_eval_csv.xsl】
捕捉: ただし、飽くまでネトフリリンク目的の裏方扱いであり、公開版のエピソードリストには掲載しない。
<?xml version="1.0" encoding="shift_jis"?>
<t:エピソード集 シリーズ名="DSC" xmlns:t="urn:tables">
<t:エピ>
<t:シリーズ名>DSC</t:シリーズ名>
<t:シーズン番号>1</t:シーズン番号>
<t:話数>1</t:話数>
<t:原題 直訳="">THE VULCAN HELLO</t:原題>
<t:邦題>バルカンの挨拶</t:邦題>
<t:収録 メディア="DVD" ディスク番号="1" タイトル番号="1">
<t:尺 />
</t:収録>
<t:収録 メディア="Netflix" タイトル番号="1" URL="https://www.netflix.com/watch/80126025">
<字幕ファイル>subtitles\yn_DSC1-1.ttml</字幕ファイル>
<翻訳>大岩剛</翻訳>
<t:尺>43</t:尺>
</t:収録>
</t:エピ>
<t:エピ>
<t:シリーズ名>DSC</t:シリーズ名>
<t:シーズン番号>1</t:シーズン番号>
<t:話数>2</t:話数>
<t:原題 直訳="">BATTLE AT THE BINARY STARS</t:原題>
<t:邦題>連星系の戦い</t:邦題>
<t:収録 メディア="DVD" ディスク番号="1" タイトル番号="2">
<t:尺 />
</t:収録>
<t:収録 メディア="Netflix" タイトル番号="2" URL="https://www.netflix.com/watch/80194752">
<字幕ファイル>subtitles\yn_DSC1-2.ttml</字幕ファイル>
<翻訳>大岩剛</翻訳>
<t:尺>39</t:尺>
</t:収録>
</t:エピ>
(略)
</t:エピソード集>
【DB_06_DSC.xml】
<?xml version="1.0" encoding="shift_jis"?>
<t:エピソード集 xmlns:t="urn:tables" t:シリーズ名="TMNT">
<t:エピ>
<t:シーズン番号>1</t:シーズン番号>
<t:話数>1</t:話数>
<t:原題>RISE OF THE TURTLES (PART 1)</t:原題>
<t:邦題>タートルズ参上!(前編)</t:邦題>
<t:収録 メディア="Netflix" タイトル番号="1" URL="https://www.netflix.com/watch/80080493">
<字幕ファイル>subtitles\yn_TMNT1-1.ttml</字幕ファイル>
<尺>23</尺>
</t:収録>
</t:エピ>
<t:エピ>
<t:シーズン番号>1</t:シーズン番号>
<t:話数>2</t:話数>
<t:原題>RISE OF THE TURTLES (PART 2)</t:原題>
<t:邦題>タートルズ参上!(後編)</t:邦題>
<t:収録 メディア="Netflix" タイトル番号="2" URL="https://www.netflix.com/watch/80080494">
<字幕ファイル>subtitles\yn_TMNT1-2.ttml</字幕ファイル>
<尺>23</尺>
</t:収録>
</t:エピ>
(略)
</t:エピソード集>
【DB_20_TMNT.xml】
捕捉: ちなみにDBファイルには、エピソード情報の他に評価係数とシリーズ情報も含まれる。これも別ファイルに分割した。
<?xml version="1.0" encoding="shift_jis"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:t="urn:tables" >
<xsl:output method="xml" encoding="Shift_JIS" />
<xsl:template match="t:台帳"/>
<xsl:template match="/">
<xsl:processing-instruction name="xml-stylesheet">
<xsl:text>type="text/xsl" href="st_table.xsl"</xsl:text>
</xsl:processing-instruction>
<t:台帳>
<xsl:copy-of select="document('DB_99_OTHERS.xml')/t:台帳/t:評価"/>
<xsl:copy-of select="document('DB_99_OTHERS.xml')/t:台帳/t:シリーズ"/>
<t:エピソード集>
<xsl:copy-of select="document('DB_00_MOV.xml')//t:エピ"/>
<xsl:copy-of select="document('DB_01_TOS.xml')//t:エピ"/>
<xsl:copy-of select="document('DB_02_TAS.xml')//t:エピ"/>
<xsl:copy-of select="document('DB_03_TNG.xml')//t:エピ"/>
<xsl:copy-of select="document('DB_04_DS9.xml')//t:エピ"/>
<xsl:copy-of select="document('DB_05_VGR.xml')//t:エピ"/>
<xsl:copy-of select="document('DB_06_ENT.xml')//t:エピ"/>
<xsl:copy-of select="document('DB_07_DSC.xml')//t:エピ"/>
<xsl:copy-of select="document('DB_20_TMNT.xml')//t:エピ"/>
</t:エピソード集>
</t:台帳>
</xsl:template>
</xsl:stylesheet>
【mergedb.xsl】
んで、これを以下のようにつかって、元の結合DB化する(全てのデータとなるXMLファイルをXSL内で読み込んでいるので、実行時に指定するXMLファイルは単なるダミーである)。msxsl -u 4.0 DB_99_OTHERS.xml mergedb.xsl -o ST_def.xml
捕捉: ここまでの説明、かなり端折っている。これをまともに使うための前提は他にいろいろあるが、単なる自分メモとしてはこれで十分としておく(「ソース読め!」>自分)
agent属性を廃止することに決めた。本稿で以前導入について述べているが、これをやめるということである。
備考: 理由は、角カッコだとツッコミ原稿で役名表記に使っており、紛らわしいため
重いXMLファイルを読み込むと、最初に編集するときだけ、10分以上もの無応答が起こるのだ。この「編集」とは、何かテキスト入力するとか、要素等を追加するとかの、ごく普通のことである。そして、その無応答タイムをやりすごすと、その後は何の問題もなく編集ができるからワケがわからない(ちなみに無応答の間、CPU使用率は100%で張り付くので何らかの前処理的なことをしているのだろうが...)。
備考: 翻訳ツッコミで劇場版を採りあげたとき、3000余ある字幕台詞を全て事前変換しておくと重くて使い物にならないと前に述べたが、主な現象はコレだった。
備考: 本来ならXML Notepadの方での問題として何か対処法を探したいところだが、サポートサイトを覗いても作者からの返信が絶えて久しいようだし、如何ともしがたい
備考: 値のない<字幕id>要素は、[omit]を意味する
【従来形式】
だが台詞引用においては、字幕IDは降順に連続するものがほとんどである。そこで以下のように連続する数を「続」という属性値に入れておくものとした。【新形式】
<xsl:template match="字幕id">
<xsl:value-of select="concat(msxsl:node-set($字幕)//tt:p[@xml:id=$id],' ')"/>
<xsl:value-of select="@続"/>
<xsl:if test="@続 and @続 > 0">
<xsl:call-template name="loop">
<xsl:with-param name="i" select="1"/>
<xsl:with-param name="i_limit" select="@続"/>
<xsl:with-param name="字幕" select="$字幕"/>
<xsl:with-param name="id" select="$id"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="loop">
<xsl:param name="i"/>
<xsl:param name="i_limit"/>
<xsl:param name="i_inc">1</xsl:param>
<xsl:param name="字幕"/>
<xsl:param name="id"/>
<xsl:if test="$i <= $i_limit">
<xsl:value-of select="concat(' ',msxsl:node-set($字幕)//tt:p[@xml:id=$id]/following-sibling::*[$i])"/>
<xsl:variable name="i1" select="$i + $i_inc"/>
<xsl:call-template name="loop">
<xsl:with-param name="i" select="$i1"/>
<xsl:with-param name="i_limit" select="$i_limit"/>
<xsl:with-param name="i_inc" select="$i_inc"/>
<xsl:with-param name="字幕" select="msxsl:node-set($字幕)"/>
<xsl:with-param name="id" select="$id"/>
</xsl:call-template>
</xsl:if>
<?xml version="1.0" encoding="Shift_JIS" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" encoding="Shift_JIS"/>
<xsl:include href="..\..\xml\commonlib.xsl" />
<xsl:template match="エピ">
<xsl:element name="エピ">
<xsl:attribute name="状態">下書き</xsl:attribute>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="台詞">
<xsl:element name="台詞">
<xsl:attribute name="状態">
<xsl:value-of select="@状態"/>
</xsl:attribute>
<xsl:attribute name="人物">
<xsl:value-of select="@人物"/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="原語[字幕id!='']">
<xsl:element name="原語">
<xsl:element name="字幕id">
<xsl:attribute name="続">
<xsl:if test="count(字幕id) > 1">
<xsl:value-of select="count(字幕id)-1"/>
</xsl:if>
</xsl:attribute>
<xsl:value-of select="字幕id[1]"/>
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template match="原語[not(字幕id) or 字幕id='']">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="吹替|直訳|所感|余談|原題|更新日|字幕ソース">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
備考: ちなみに今は XML Notepadのプレビュータブは使わず、IEをプレビュー用に使っている。これならAlt+Tabで切り替え、[F5]で表示することができるので多少はマシ。
トップページの What's New (直近の更新3項目のリスト)だけは手作業での更新を続けていた。
参考: ばっちり書けてますかhref= – 特に&(&)などを含む場合 – 属性値としてのCDATAただ、Coralnetのサーバでは、そうはなっておらず、XHTML的に
備考: ちなみに、FC2のアクセス解析タグも同じく & の問題があったのだが、こちらは & を受け入れるようだ。
<xsl:if test="yn:contains(string(.),'[^\.][\)\]\?\.!]"?\n?$')">
【行末判定部】
C:\>msxsl -u 4.0 yn_DS9_3-12.ttml ttml2tsukkomi.xsl
Error occurred while executing stylesheet 'ttml2tsukkomi.xsl'.
Code: 0x80004005
システム エラー: -2146828260
プロパティまたはメソッド 'contains' の呼び出し中にエラーが発生しました。
'contains'の呼び出し中に、とあるからには、正規表現対応させたJScript版のyn:containsが原因... なのか?再起呼び出しだということだ。上記のコードの意味はよくわからないが、ひょっとしてスタックオーバーフローなのではないか?つまり、JScriptの関数そのものが原因なのではなく、スタック領域を食い尽くしているだけなのかもしれない。
<p xml:id="172" term="">
First Officer's Log,
supplemental.
</p>
<p xml:id="173" term="">
Somehow, Sisko, Dax and Bashir
have altered Earth's history.
</p>
<p xml:id="174">
We have no choice but to send
an away team into the past
</p>
<p xml:id="175" term="">
to try to find them and correct
the changes to the timeline.
</p>
【ツッコミ形式変換用TTML(DS9"PAST TENSE, PART II"より)】
変更前: <xsl:if test="yn:contains(string(.),'[^\.][\)\]\?\.!]"?\n?$')">
変更後: <xsl:if test="@term">
【ttml2tsukkomi.xsl 判定部変更内容】
<p begin="15419992503t" end="15438760002t" region="region_00" tts:extent="40.00% 5.33%" tts:origin="10.00% 79.29%" xml:id="subtitle722" agent="">What do you think</p>
<p begin="15419992503t" end="15438760002t" region="region_01" tts:extent="47.50% 5.33%" tts:origin="10.00% 84.62%" xml:id="subtitle723" agent="">you're doing, Quark?</p>
<p begin="15467955001t" end="15489645003t" region="region_00" tts:extent="27.50% 5.33%" tts:origin="47.50% 79.29%" xml:id="subtitle727" agent="">Oh, you mean</p>
<p begin="15467955001t" end="15489645003t" region="region_01" tts:extent="40.00% 5.33%" tts:origin="47.50% 84.62%" xml:id="subtitle728" agent="">this holo-imager.</p>
<p begin="15489645003t" end="15506325000t" region="region_00" tts:extent="47.50% 5.33%" tts:origin="27.50% 79.29%" xml:id="subtitle729" agent="">I was just recording</p>
<p begin="15489645003t" end="15506325000t" region="region_01" tts:extent="60.00% 5.33%" tts:origin="27.50% 84.62%" xml:id="subtitle730" agent="">an image of the Promenade</p>
<p begin="15506325000t" end="15529685003t" region="region_00" tts:extent="27.50% 5.33%" tts:origin="57.50% 68.63%" xml:id="subtitle731" agent="">to send home</p>
<p begin="15506325000t" end="15529685003t" region="region_01" tts:extent="30.00% 5.33%" tts:origin="57.50% 73.96%" xml:id="subtitle732" agent="">to my mother.</p>
【ネトフリTTML(DS9"MERIDIAN"より)】
<p begin="7680589582t" end="7698524166t" region="region.after" style="defaultStyle" xml:id="subtitle210">If you need to sleep, go ahead.</p>
<p begin="7699358332t" end="7719378332t" region="region.after" style="defaultStyle" xml:id="subtitle211">-I'll understand.<br/>-No, you won't.</p>
<p begin="7720212499t" end="7731473749t" region="region.after" style="defaultStyle" xml:id="subtitle212">You'll be disappointed</p>
<p begin="7732307916t" end="7764840416t" region="region.after" style="defaultStyle" xml:id="subtitle213">and you'll start brooding<br/>and stomping around like an Andorian bull.</p>
【ネトフリTTML(DS9"FASCINATION"より)】
tt:p[tt:br]
preceding-sibling::node()に対して、それぞれ行頭が '-'(ハイフン)で始まる場合に行う
following-sibling::node()
補足: この<tt:p>タグの子要素が、DSC式では<span>タグであり、DS9式ではテキストであるというように異なるため、双方にてきようできるXPath式を編み出すのにどれほど苦労したか...
<?xml version="1.0" encoding="shift_jis"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tt="http://www.w3.org/ns/ttml" xmlns:ttm="http://www.w3.org/ns/ttml#metadata" xmlns:ttp="http://www.w3.org/ns/ttml#parameter" xmlns:tts="http://www.w3.org/ns/ttml#styling" xmlns="http://www.w3.org/ns/ttml" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:yn="urn:yonetch">
<xsl:output method="xml" encoding="Shift_JIS"/>
<!-- 07-29版 台詞内に改行が入っている場合に対応 -->
<!-- 08-02版 DSC式に [Burnham] のように役名が入っている場合の agent化に対応 -->
<!-- 08-04版 DS9式に SISCO: のように役名が入っている場合の agent化にに対応 -->
<xsl:include href="..\mysite\xml\commonlib.xsl" />
<xsl:key name="スタイル情報" match="tt:style" use="@tts:fontStyle"/>
<xsl:variable name="ItaSty">
<xsl:value-of select="key('スタイル情報','italic')/@xml:id"/>
</xsl:variable>
<xsl:template match="tt:tt">
<tt>
<xsl:apply-templates/>
</tt>
</xsl:template>
<xsl:template match="tt:head|tt:styling|tt:layout|ttp:profile|tt:region">
<xsl:copy>
<xsl:for-each select="@*">
<xsl:copy />
</xsl:for-each>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="tt:style[@tts:fontStyle='italic']">
<xsl:copy>
<xsl:for-each select="@*">
<xsl:choose>
<xsl:when test="name()='xml:id'">
<xsl:attribute name="xml:id">italic
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:copy />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="tt:style[not(@tts:fontStyle)]">
<xsl:copy>
<xsl:for-each select="@*">
<xsl:copy />
</xsl:for-each>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="tt:body">
<body>
<xsl:apply-templates/>
</body>
</xsl:template>
<xsl:template match="tt:div">
<div>
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="tt:p[not(tt:br)]">
<xsl:copy>
<xsl:for-each select="@*">
<xsl:copy />
</xsl:for-each>
<xsl:attribute name="agent">
<xsl:value-of select="yn:replace(string(.),'\[([^\]]+)\].+','$1')"/>
<xsl:value-of select="yn:replace(string(.),'([^:]+):.+','$1')"/>
<!-- DSC式とDS9式が同時に使われることはないという前提で併記 -->
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="tt:p/text()">
<xsl:value-of select="yn:replace(string(.),'([^:]+:)?(.+)','$2')"/>
<!-- DS9式の地の文から役名を削除 -->
<!-- 役名以外の目的で:(コロン)が使われていたら誤動作するだろう -->
</xsl:template>
<xsl:template match="tt:p[tt:br]">
<xsl:apply-templates select="tt:br"/>
<!-- br要素のあるp要素について、br要素のみ評価 -->
</xsl:template>
<xsl:template match="tt:br">
<xsl:choose>
<xsl:when test="yn:contains(string(preceding-sibling::node()[last()]),'^\-')">
<!-- 行頭が '-' で始まっていたら(正規表現 ^\-)-->
<!-- 2つの台詞に分割 -->
<p>
<xsl:for-each select="../@*">
<xsl:copy/>
</xsl:for-each>
<xsl:attribute name="agent">
<xsl:value-of select="yn:replace(string(preceding-sibling::node()[last()]),'-\[([^\]]+)\].+','$1')"/>
</xsl:attribute>
<xsl:for-each select="preceding-sibling::node()">
<!-- brより前の、ノードかテキストである兄弟要素についてループ -->
<xsl:apply-templates select="."/>
</xsl:for-each>
</p>
<xsl:text>
</xsl:text>
<p>
<xsl:for-each select="../@*">
<xsl:if test="not(contains(.,'xml:id'))">
<xsl:copy />
</xsl:if>
</xsl:for-each>
<xsl:attribute name="xml:id">
<xsl:value-of select="concat(../@xml:id,'-2')"/>
<!-- 台詞idをコピーして接尾詞'-2'をつける -->
</xsl:attribute>
<xsl:attribute name="agent">
<xsl:value-of select="yn:replace(string(following-sibling::node()[1]),'-\[([^\]]+)\].+','$1')"/>
</xsl:attribute>
<xsl:for-each select="following-sibling::node()">
<!-- brより後の、ノードかテキストである兄弟要素についてループ -->
<xsl:apply-templates select="."/>
</xsl:for-each>
</p>
<xsl:attribute name="agent">
<xsl:value-of select="yn:replace(string(following-sibling::node()[1]),'-\[([^\]]+)\].+','$1')"/>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<!-- それ以外(行頭が '-' で始まっていなかったら -->
<!-- brノード以外をコピー(改行を削除) -->
<p>
<xsl:for-each select="../@*">
<xsl:copy/>
</xsl:for-each>
<xsl:attribute name="agent">
<xsl:value-of select="yn:replace(string(preceding-sibling::node()[1]),'\[([^\]]+)\].+','$1')"/>
</xsl:attribute>
<xsl:for-each select="preceding-sibling::node()">
<xsl:apply-templates select="."/>
</xsl:for-each>
<xsl:text>
</xsl:text>
<xsl:for-each select="following-sibling::node()">
<xsl:apply-templates select="."/>
</xsl:for-each>
</p>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="tt:span">
<span>
<xsl:choose>
<xsl:when test="@style=$ItaSty">
<xsl:attribute name="style">italic
</xsl:attribute>
</xsl:when>
</xsl:choose>
<xsl:value-of select="yn:replace(string(.),'(-)?(\[[^\]]+\]\s)?([^\[\]]*)','$1$3')"/>
<!-- DSC式のspanタグ内から役名を削除 -->
</span>
</xsl:template>
</xsl:stylesheet>
【make_ynttml.xsl】
兄弟要素をグループ化する手法を使います。ひとことでいうと、
全要素を順番に処理して、終端要素が出たら、そこまでをグループとするとなります。フラットな字幕データを台詞(文章)としてグループ化するための終端要素は、当然ピリオド、クエスチョンマーク等です。台詞文字列の中にそれらの終端文字があるかどうかを contain() 関数でチェックします。
補足: ただし、複数の文字をひとつずつチェックするのは冗長なので、正規表現に対応した yn:contain() 関数を作りました。それについてはまた別の機会にまとめたい思います。また、このテンプレートは、DS9のように全てを<p>要素で記述しているものにしか適用できません(DSCは<p>の下に<span>を使っているのでもうひとひねり必要)。
<?xml version="1.0" encoding="Shift_JIS" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tt="http://www.w3.org/ns/ttml" xmlns:ttm="http://www.w3.org/ns/ttml#metadata" xmlns:ttp="http://www.w3.org/ns/ttml#parameter" xmlns:tts="http://www.w3.org/ns/ttml#styling" xmlns:yn="urn:yonetch" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" >
<xsl:output method="xml" encoding="Shift_JIS"/>
<xsl:include href="..\..\..\xml\commonlib.xsl" />
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="tt:body">
<body>
<xsl:apply-templates/>
</body>
</xsl:template>
<xsl:template match="div">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="tt:div">
<xsl:element name="エピ">
<xsl:attribute name="状態">下書き
</xsl:attribute>
<xsl:element name="原題"/>
<xsl:element name="更新日"/>
<xsl:element name="字幕ソース">Netflix
</xsl:element>
<xsl:text></xsl:text>
<xsl:for-each select="tt:p">
<xsl:if test="yn:contains(string(.),'[^\.][\)\]\?\.!]"?$')">
<xsl:element name="台詞">
<xsl:attribute name="状態">下書き
</xsl:attribute>
<xsl:attribute name="人物">
</xsl:attribute>
<xsl:element name="原語">
<xsl:text></xsl:text>
<xsl:if test="preceding-sibling::*[1]">
<xsl:call-template name="func">
<xsl:with-param name="node" select="preceding-sibling::*[1]" />
</xsl:call-template>
<字幕id>
<xsl:value-of select="@xml:id" />
</字幕id>
<xsl:text></xsl:text>
</xsl:if>
</xsl:element>
<xsl:text></xsl:text>
<xsl:element name="吹替">
<xsl:attribute name="評価"/>
</xsl:element>
<xsl:text></xsl:text>
<xsl:element name="直訳"/>
<xsl:text></xsl:text>
<xsl:element name="所感"/>
<xsl:text></xsl:text>
</xsl:element>
<xsl:text></xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:element>
</xsl:template>
<xsl:template name="func">
<xsl:param name="node" />
<xsl:if test="not(yn:contains(string($node/.),'[^\.][\)\]\?\.!]"?$'))">
<xsl:call-template name="func">
<xsl:with-param name="node" select="$node/preceding-sibling::*[1]" />
</xsl:call-template>
<字幕id>
<xsl:value-of select="$node/@xml:id" />
</字幕id>
<xsl:text></xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
【ttml2tsukkomi_DS9.xsl】
<?xml version="1.0" encoding="shift_jis"?>
<?xml-stylesheet type="text/xsl" href="st_eval.xsl"?>
<!DOCTYPE startrek [
<!ENTITY DS9_1 SYSTEM "DS9_1.xml">
<!ENTITY DS9_2 SYSTEM "DS9_2.xml">
<!ENTITY DS9_3-1 SYSTEM "DS9_3-1.xml">
<!ENTITY DS9_3-2 SYSTEM "DS9_3-2.xml">
<!ENTITY DS9_3-3 SYSTEM "DS9_3-3.xml">
<!ENTITY DS9_3-4 SYSTEM "DS9_3-4.xml">
<!ENTITY DS9_3-5 SYSTEM "DS9_3-5.xml">
<!ENTITY DS9_3-8 SYSTEM "DS9_3-8.xml">
<!ENTITY DS9_3-9 SYSTEM "DS9_3-9.xml">
<!ENTITY DS9_3-11 SYSTEM "DS9_3-11.xml">
<!ENTITY DS9_3-12 SYSTEM "DS9_3-12.xml">
<!ENTITY DS9_3-14 SYSTEM "DS9_3-14.xml">
<!ENTITY DS9_3-15 SYSTEM "DS9_3-15.xml">
<!ENTITY DS9_3-25 SYSTEM "DS9_3-25.xml">
]>
<シーズン シーズン番号="3" 略称="DS9">
&DS9_3-1;
&DS9_3-2;
&DS9_3-3;
&DS9_3-4;
&DS9_3-5;
&DS9_3-8;
&DS9_3-9;
&DS9_3-11;
&DS9_3-12;
&DS9_3-14;
&DS9_3-15;
&DS9_3-25;
</シーズン>
【DS9第3シーズン】
<?xml version="1.0" encoding="shift_jis"?>
<?xml-stylesheet type="text/xsl" href="st_eval_tbl.xsl"?>
<!DOCTYPE startrek [
<!ENTITY 台帳 SYSTEM "ST_def.xml">
<!ENTITY TOS1 SYSTEM "TOS1.xml">
<!ENTITY TOS2 SYSTEM "TOS2.xml">
<!ENTITY TOS3 SYSTEM "TOS3.xml">
<!ENTITY TAS1 SYSTEM "TAS1.xml">
<!ENTITY TAS2 SYSTEM "TAS2.xml">
<!ENTITY TNG_1 SYSTEM "TNG_1.xml">
<!ENTITY TNG_2 SYSTEM "TNG_2.xml">
<!ENTITY TNG_3 SYSTEM "TNG_3.xml">
<!ENTITY TNG_4 SYSTEM "TNG_4.xml">
<!ENTITY TNG_5 SYSTEM "TNG_5.xml">
<!ENTITY TNG_6 SYSTEM "TNG_6.xml">
<!ENTITY TNG_7 SYSTEM "TNG_7.xml">
<!ENTITY DS9_1 SYSTEM "DS9_1.xml">
<!ENTITY DS9_2 SYSTEM "DS9_2.xml">
<!ENTITY DS9_3-1 SYSTEM "DS9_3-1.xml">
<!ENTITY DS9_3-11 SYSTEM "DS9_3-11.xml">
<!ENTITY DS9_3-12 SYSTEM "DS9_3-12.xml">
<!ENTITY DS9_3-14 SYSTEM "DS9_3-14.xml">
<!ENTITY DS9_3-15 SYSTEM "DS9_3-15.xml">
<!ENTITY DS9_3-2 SYSTEM "DS9_3-2.xml">
<!ENTITY DS9_3-25 SYSTEM "DS9_3-25.xml">
<!ENTITY DS9_3-3 SYSTEM "DS9_3-3.xml">
<!ENTITY DS9_3-4 SYSTEM "DS9_3-4.xml">
<!ENTITY DS9_3-5 SYSTEM "DS9_3-5.xml">
<!ENTITY DS9_3-8 SYSTEM "DS9_3-8.xml">
<!ENTITY DS9_3-9 SYSTEM "DS9_3-9.xml">
<!ENTITY DS9_4 SYSTEM "DS9_4.xml">
<!ENTITY DS9_5 SYSTEM "DS9_5.xml">
<!ENTITY DS9_6 SYSTEM "DS9_6.xml">
<!ENTITY DS9_7 SYSTEM "DS9_7.xml">
<!ENTITY VGR1 SYSTEM "VGR1.xml">
<!ENTITY VGR2 SYSTEM "VGR2.xml">
<!ENTITY VGR3 SYSTEM "VGR3.xml">
<!ENTITY VGR4 SYSTEM "VGR4.xml">
<!ENTITY VGR5 SYSTEM "VGR5.xml">
<!ENTITY VGR6 SYSTEM "VGR6.xml">
<!ENTITY VGR7 SYSTEM "VGR7.xml">
<!ENTITY ENT1 SYSTEM "ENT1.xml">
<!ENTITY ENT2 SYSTEM "ENT2.xml">
<!ENTITY ENT3 SYSTEM "ENT3.xml">
<!ENTITY ENT4 SYSTEM "ENT4.xml">
<!ENTITY DSC1 SYSTEM "DSC1.xml">
]>
<スタートレック xmlns:t="urn:tables">
<?xml-stylesheet type="text/xsl" href="st_table.xsl"?>
&台帳;
<シリーズ 略称="TOS" xmlns:t="urn:tables">&TOS1;
&TOS2;
&TOS3;
</シリーズ>
<シリーズ 略称="TAS" xmlns:t="urn:tables">&TAS1;
&TAS2;
</シリーズ>
<シリーズ 略称="TNG" xmlns:t="urn:tables">&TNG_1;
&TNG_2;
&TNG_3;
&TNG_4;
&TNG_5;
&TNG_6;
&TNG_7;
</シリーズ>
<シリーズ 略称="DS9" xmlns:t="urn:tables">&DS9_1;
&DS9_2;
<シーズン シーズン番号="3" 略称="DS9">
&DS9_3-1;
&DS9_3-11;
&DS9_3-12;
&DS9_3-14;
&DS9_3-15;
&DS9_3-2;
&DS9_3-25;
&DS9_3-3;
&DS9_3-4;
&DS9_3-5;
&DS9_3-8;
&DS9_3-9;
</シーズン>
&DS9_4;
&DS9_5;
&DS9_6;
&DS9_7;
</シリーズ>
<シリーズ 略称="VGR" xmlns:t="urn:tables">&VGR1;
&VGR2;
&VGR3;
&VGR4;
&VGR5;
&VGR6;
&VGR7;
</シリーズ>
<シリーズ 略称="ENT" xmlns:t="urn:tables">&ENT1;
&ENT2;
&ENT3;
&ENT4;
</シリーズ>
<シリーズ 略称="DSC" xmlns:t="urn:tables">&DSC1;
</シリーズ>
</スタートレック>
【全シリーズ結合】
XIncludeというのがかなり有力な案でした。実際、以下のようにすると、できちゃうんですよ!... ただし XML Notepad のプレビュー上だけですが(泣)。
<?xml version="1.0" encoding="shift_jis"?>
<?xml-stylesheet type="text/xsl" href="st_eval.xsl"?>
<シーズン シーズン番号="3" 略称="DS9" xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="DS9_3-1.xml"/>
<xi:include href="DS9_3-2.xml"/>
<xi:include href="DS9_3-3.xml"/>
<xi:include href="DS9_3-4.xml"/>
<xi:include href="DS9_3-5.xml"/>
<xi:include href="DS9_3-8.xml"/>
<xi:include href="DS9_3-9.xml"/>
<xi:include href="DS9_3-11.xml"/>
<xi:include href="DS9_3-12.xml"/>
<xi:include href="DS9_3-14.xml"/>
<xi:include href="DS9_3-15.xml"/>
<xi:include href="DS9_3-25.xml"/>
</シーズン>
【DS9第3シーズン XInclude版】
これに悩んで、本稿が半年以上もほったらかされることになったんだぞ!チクショー!!
備考: ちなみに、ワタシの通常環境である Windows7 Pro SP1 には msxsl4.dll がインストールされていなかったために、当初このオプションはエラーとなっていた。MSXML 4.0 Service Pack 3 (Microsoft XML Core Services) をインストールする必要があった(msxsl6.dllはあったから、てっきり上位互換のものかと思ってた...)。
(RSSを記述した)rdfファイルを生成するというのがあった。いよいよ目途がたったのでコレに取り掛かりたいと思う。
補足: 少々ハナシが前後してしまっているが、元々「ツッコミリスト」は日記形式ではなく、この形式変換が必要になった段で変更した、という経緯があった。
<?xml version="1.0" encoding="shift_jis"?>
<!DOCTYPE GeneralDialy [
<!ENTITY 雑記 SYSTEM "diary2017-2018.xml">
<!ENTITY XML化 SYSTEM "XML-ization.xml">
<!ENTITY マネー SYSTEM "money.xml">
<!ENTITY 弥生元帳印刷 SYSTEM "yayoiprint.xml">
<!ENTITY パーソナルログ SYSTEM "..\startrek\xml\personal_log.xml">
<!ENTITY ツッコミ SYSTEM "..\startrek\xml\tsukkomi_list.xml">
]>
<日記総合>
&雑記;
&XML化;
&マネー;
&弥生元帳印刷;
&パーソナルログ;
&ツッコミ;
</日記総合>
<?xml version="1.0" encoding="shift_jis"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns="http://purl.org/rss/1.0/"
xmlns:t="urn:tables" xmlns:yn="urn:yonetch" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:output method="xml" encoding="UTF-8" />
<xsl:include href="commonlib.xsl" />
<xsl:variable name="記事">
<xsl:for-each select="//記事[@状態!='テンプレ' and @状態!='下書き' and @日付!='']">
<xsl:variable name="日付">
<xsl:call-template name="日付表示">
<xsl:with-param name="形式" select="'YYYYMMDD'" />
<xsl:with-param name="日付">
<xsl:value-of select="@日付" />
</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsl:if test="$日付 > 20170101">
<xsl:copy-of select="." />
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/">
<rdf:RDF xmlns="http://purl.org/rss/1.0/" xmlns:admin="http://webns.net/mvcb/" xmlns:lang="ja">
<channel>
<xsl:attribute name="rdf:about">
<xsl:value-of select="concat($サイト情報//総合情報/URL,$サイト情報//総合情報/RDF)" />
</xsl:attribute>
<title>
<xsl:value-of select="$サイト情報//総合情報/サイト名" />
</title>
<link>
<xsl:value-of select="$サイト情報//総合情報/URL" />
</link>
<dc:date>
<xsl:value-of select="yn:getDateTime()" />
</dc:date>
<items>
<rdf:Seq>
<xsl:apply-templates select="msxsl:node-set($記事)/*" mode="Seq">
<xsl:sort select="@日付" order="descending" />
</xsl:apply-templates>
</rdf:Seq>
</items>
</channel>
<xsl:apply-templates select="msxsl:node-set($記事)/*">
<xsl:sort select="@日付" order="descending" />
</xsl:apply-templates>
</rdf:RDF>
</xsl:template>
<xsl:template match="記事" mode="Seq">
<xsl:variable name="cat" select="カテゴリ" />
<xsl:variable name="subcat" select="サブカテゴリ" />
<xsl:variable name="en_subtitle" select="@見出し" />
<xsl:variable name="dtlabel">
<xsl:call-template name="日付表示">
<xsl:with-param name="形式" select="'YYYYMMDD'" />
<xsl:with-param name="日付">
<xsl:value-of select="@日付" />
</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="link">
<xsl:choose>
<xsl:when test="contains($subcat,'翻訳ツッコミ')">
<xsl:value-of select="concat($サイト情報//カテゴリ情報/カテゴリ[@name=$cat]/サブカテゴリ[@name='翻訳ツッコミ']/値[@name='リンク'],'#',$台帳//t:エピ[t:原題=$en_subtitle]/t:シリーズ名,$台帳//t:エピ[t:原題=$en_subtitle]/t:シーズン番号)" />
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="count($サイト情報//カテゴリ情報/カテゴリ[@name=$cat]/サブカテゴリ)">
<xsl:value-of select="concat($サイト情報//カテゴリ情報/カテゴリ[@name=$cat]/サブカテゴリ[@name=$subcat]/値[@name='リンク'],'#',$dtlabel)" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($サイト情報//カテゴリ情報/カテゴリ[@name=$cat]/値[@name='リンク'],'#',$dtlabel)" />
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<rdf:li>
<xsl:attribute name="rdf:resouce">
<xsl:value-of select="concat($サイト情報//総合情報/URL,$link,'#he',$dtlabel)" />
</xsl:attribute>
</rdf:li>
</xsl:template>
<xsl:template match="記事">
<xsl:variable name="cat" select="カテゴリ" />
<xsl:variable name="subcat" select="サブカテゴリ" />
<xsl:variable name="en_subtitle" select="@見出し" />
<xsl:variable name="dtlabel">
<xsl:call-template name="日付表示">
<xsl:with-param name="形式" select="'YYYYMMDD'" />
<xsl:with-param name="日付">
<xsl:value-of select="@日付" />
</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="link">
<xsl:choose>
<xsl:when test="contains($subcat,'翻訳ツッコミ')">
<xsl:value-of select="concat($サイト情報//カテゴリ情報/カテゴリ[@name=$cat]/サブカテゴリ[@name='翻訳ツッコミ']/値[@name='リンク'],'#',$台帳//t:エピ[t:原題=$en_subtitle]/t:シリーズ名,$台帳//t:エピ[t:原題=$en_subtitle]/t:シーズン番号)" />
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="count($サイト情報//カテゴリ情報/カテゴリ[@name=$cat]/サブカテゴリ)">
<xsl:value-of select="concat($サイト情報//カテゴリ情報/カテゴリ[@name=$cat]/サブカテゴリ[@name=$subcat]/値[@name='リンク'],'#',$dtlabel)" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($サイト情報//カテゴリ情報/カテゴリ[@name=$cat]/値[@name='リンク'],'#',$dtlabel)" />
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<item>
<xsl:attribute name="rdf:about">
<xsl:value-of select="concat($サイト情報//総合情報/URL,$link,'#he',$dtlabel)" />
</xsl:attribute>
<title>
<xsl:value-of select="concat('【',$サイト情報//カテゴリ情報/カテゴリ[@name=$cat]/値[@name='リンク名'],'】 ',$subcat)" />
</title>
<link>
<xsl:value-of select="concat($サイト情報//総合情報/URL,$link)" />
</link>
<dc:date>
<xsl:value-of select="@日付" />
</dc:date>
<description>
<xsl:value-of select="@見出し" />
</description>
</item>
</xsl:template>
<xsl:template match="表題|副題|要旨|段落|カテゴリ|サブカテゴリ|キーワード"></xsl:template>
</xsl:stylesheet>
【スタイルシート(rdf.xsl)】
対象期間の限定がある。全日記のXML化が完了している「ぷろぐらまyonetch」「マネーの虎yonetch」は、十数年分の記事がすべて含まれる。が、RDFで更新を告知する対象に、今更そこまで含める必要はないから、まぁ、今年分だけを... と思って日付で限定するというのが、まことにメンドウだった。
<xsl:variable name="記事">
<xsl:for-each select="//記事[@状態!='テンプレ' and @状態!='下書き' and @日付!='']">
<xsl:variable name="日付">
<xsl:call-template name="日付表示">
<xsl:with-param name="形式" select="'YYYYMMDD'" />
<xsl:with-param name="日付">
<xsl:value-of select="@日付" />
</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsl:if test="$日付 > 20170101">
<xsl:copy-of select="." />
</xsl:if>
</xsl:for-each>
</xsl:variable>
【スタイルシートより抜粋(rdf.xsl)】
後は、この部分集合変数に対して、同じようにテンプレートを適用して... と思ったらそれができないのだ。その説明は、このサイトが参考になった。以下に抜粋引用する。Firefox 2のXSLTプロセッサはXSLT 1.0のdocument関数が使えるのはいいんですが、結果ツリーフラグメント(Result Tree Fragment)をノードセットとして評価することができないようです。
そもそも結果ツリーフラグメントって何かというと、大雑把に言えばxsl:variable要素やxsl:param要素の内容としての値です。例えば、
<xsl:variable name="result">
<level>3</level>
<number>1-1</number>
</xsl:variable>
上記のような変数resultがあった場合、$resultはlevelとnumberの二つのノードを持つノードセットのように見えますが、これはノードセットにはなりません。結果ツリーフラグメントと呼ばれます。結果ツリーフラグメントに対しては文字列操作しか許されず、勿論/や//、[]などのノードセットに対してのみ使える演算子は使えません。
ではどうするかというと、上の記事と異なり msxsl では、 <xsl:apply-templates select="msxsl:node-set($記事)/*">
<xsl:sort select="@日付" order="descending" />
</xsl:apply-templates>
【スタイルシートより抜粋(rdf.xsl)】
というように、msxsl:node-set(ツリーフラグメント)を使用することでノードセット化できる。追記: 実は、この記事は書きかけでほったらかされており、半年以上を経て公開している。この当時書いていたxslファイルの中身は、半ば忘却の彼方なのであった...(^^;;
<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:t="urn:tables" xmlns:yn="urn:yonetch" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns="http://purl.org/rss/1.0/" xmlns:admin="http://webns.net/mvcb/" xmlns:lang="ja">
<channel rdf:about="http://www1.coralnet.or.jp/yonetch/yonetch.rdf">
<title>yonetch Works</title>
<link>http://www1.coralnet.or.jp/yonetch/</link>
<dc:date>2017-12-03T20:42:03+09:00</dc:date>
<items>
<rdf:Seq>
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/XML-ization.html#20171203#he20171203" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/XML-ization.html#20171202#he20171202" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/personal_log.html#20171121#he20171121" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DS91#he20171121" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20171115" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/XML-ization.html#20171112#he20171112" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#TNG7#he20171111" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20171110" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20171104" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/##he20171028" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/personal_log.html#20171025#he20171025" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20171025" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20171021" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20171014" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20171007" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/personal_log.html#20171002#he20171002" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20171002" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20170930" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/personal_log.html#20170926#he20170926" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT4#he20170910" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT4#he20170909" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT4#he20170909" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT4#he20170903" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/personal_log.html#20170902#he20170902" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170827" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170826" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170826" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170820" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170814" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170814" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170716" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170710" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170709" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170703" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/#20170622#he20170622" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170620" />
<rdf:li rdf:resouce="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170608" />
</rdf:Seq>
</items>
</channel>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/XML-ization.html#20171203#he20171203">
<title>【XML化プロジェクト】 技術メモ</title>
<link>http://www1.coralnet.or.jp/yonetch/XML-ization.html#20171203</link>
<dc:date>2017-12-03</dc:date>
<description>RSS生成</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/XML-ization.html#20171202#he20171202">
<title>【XML化プロジェクト】 技術メモ</title>
<link>http://www1.coralnet.or.jp/yonetch/XML-ization.html#20171202</link>
<dc:date>2017-12-02</dc:date>
<description>大元の変換テンプレートっす</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/personal_log.html#20171121#he20171121">
<title>【トレッカーyonetch】 Personal Log</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/personal_log.html#20171121</link>
<dc:date>2017-11-21</dc:date>
<description>シリーズ中休み</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DS91#he20171121">
<title>【トレッカーyonetch】 翻訳ツッコミ DS9第1シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DS91</link>
<dc:date>2017-11-21</dc:date>
<description>THE NAGUS</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20171115">
<title>【トレッカーyonetch】 翻訳ツッコミ DSC第1シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1</link>
<dc:date>2017-11-15</dc:date>
<description>INTO THE FOREST I GO</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/XML-ization.html#20171112#he20171112">
<title>【XML化プロジェクト】 </title>
<link>http://www1.coralnet.or.jp/yonetch/XML-ization.html#20171112</link>
<dc:date>2017-11-12</dc:date>
<description>リンクの自動生成</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#TNG7#he20171111">
<title>【トレッカーyonetch】 翻訳ツッコミ TNG第7シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#TNG7</link>
<dc:date>2017-11-11</dc:date>
<description>PARALLELS</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20171110">
<title>【トレッカーyonetch】 翻訳ツッコミ DSC第1シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1</link>
<dc:date>2017-11-10</dc:date>
<description>SI VIS PACEM, PARA BELLUM</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20171104">
<title>【トレッカーyonetch】 翻訳ツッコミ DSC第1シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1</link>
<dc:date>2017-11-04</dc:date>
<description>MAGIC TO MAKE THE SANEST MAN GO MAD</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/##he20171028">
<title>【XML化プロジェクト】 スター・トレック翻訳ツッコミ</title>
<link>http://www1.coralnet.or.jp/yonetch/#</link>
<dc:date>2017-10-28</dc:date>
<description>TTML正式採用</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/personal_log.html#20171025#he20171025">
<title>【トレッカーyonetch】 Personal Log</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/personal_log.html#20171025</link>
<dc:date>2017-10-25</dc:date>
<description>制作快調!</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20171025">
<title>【トレッカーyonetch】 翻訳ツッコミ DSC第1シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1</link>
<dc:date>2017-10-25</dc:date>
<description>LETHE</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20171021">
<title>【トレッカーyonetch】 翻訳ツッコミ DSC第1シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1</link>
<dc:date>2017-10-21</dc:date>
<description>CHOOSE YOUR PAIN</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20171014">
<title>【トレッカーyonetch】 翻訳ツッコミ DSC第1シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1</link>
<dc:date>2017-10-14</dc:date>
<description>THE BUTCHER'S KNIFE CARES NOT FOR THE LAMB'S CRY</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20171007">
<title>【トレッカーyonetch】 翻訳ツッコミ DSC第1シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1</link>
<dc:date>2017-10-07</dc:date>
<description>CONTEXT IS FOR KINGS</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/personal_log.html#20171002#he20171002">
<title>【トレッカーyonetch】 Personal Log</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/personal_log.html#20171002</link>
<dc:date>2017-10-02</dc:date>
<description>本格始動!</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20171002">
<title>【トレッカーyonetch】 翻訳ツッコミ DSC第1シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1</link>
<dc:date>2017-10-02</dc:date>
<description>BATTLE AT THE BINARY STARS</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1#he20170930">
<title>【トレッカーyonetch】 翻訳ツッコミ DSC第1シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#DSC1</link>
<dc:date>2017-09-30</dc:date>
<description>THE VULCAN HELLO</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/personal_log.html#20170926#he20170926">
<title>【トレッカーyonetch】 Personal Log</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/personal_log.html#20170926</link>
<dc:date>2017-09-26</dc:date>
<description>新作がやってきた!</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT4#he20170910">
<title>【トレッカーyonetch】 翻訳ツッコミ ENT第4シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT4</link>
<dc:date>2017-09-10</dc:date>
<description>DEMONS</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT4#he20170909">
<title>【トレッカーyonetch】 翻訳ツッコミ ENT第4シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT4</link>
<dc:date>2017-09-09</dc:date>
<description>AFFLICTION</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT4#he20170909">
<title>【トレッカーyonetch】 翻訳ツッコミ ENT第4シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT4</link>
<dc:date>2017-09-09</dc:date>
<description>DIVERGENCE</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT4#he20170903">
<title>【トレッカーyonetch】 翻訳ツッコミ ENT第4シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT4</link>
<dc:date>2017-09-03</dc:date>
<description>THE FORGE</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/personal_log.html#20170902#he20170902">
<title>【トレッカーyonetch】 Personal Log</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/personal_log.html#20170902</link>
<dc:date>2017-09-02</dc:date>
<description>新作がやってくる!</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170827">
<title>【トレッカーyonetch】 翻訳ツッコミ ENT第3シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3</link>
<dc:date>2017-08-27</dc:date>
<description>COUNTDOWN</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170826">
<title>【トレッカーyonetch】 翻訳ツッコミ ENT第3シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3</link>
<dc:date>2017-08-26</dc:date>
<description>DAMAGE</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170826">
<title>【トレッカーyonetch】 翻訳ツッコミ ENT第3シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3</link>
<dc:date>2017-08-26</dc:date>
<description>THE COUNCIL</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170820">
<title>【トレッカーyonetch】 翻訳ツッコミ ENT第3シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3</link>
<dc:date>2017-08-20</dc:date>
<description>AZATI PRIME</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170814">
<title>【トレッカーyonetch】 翻訳ツッコミ ENT第3シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3</link>
<dc:date>2017-08-14</dc:date>
<description>STRATAGEM</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170814">
<title>【トレッカーyonetch】 翻訳ツッコミ ENT第3シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3</link>
<dc:date>2017-08-14</dc:date>
<description>HATCHERY</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170716">
<title>【トレッカーyonetch】 翻訳ツッコミ ENT第3シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3</link>
<dc:date>2017-07-16</dc:date>
<description>PROVING GROUND</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170710">
<title>【トレッカーyonetch】 翻訳ツッコミ ENT第3シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3</link>
<dc:date>2017-07-10</dc:date>
<description>CHOSEN REALM</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170709">
<title>【トレッカーyonetch】 翻訳ツッコミ ENT第3シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3</link>
<dc:date>2017-07-09</dc:date>
<description>THE SHIPMENT</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170703">
<title>【トレッカーyonetch】 翻訳ツッコミ ENT第3シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3</link>
<dc:date>2017-07-03</dc:date>
<description>EXILE</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/#20170622#he20170622">
<title>【更新日記】 </title>
<link>http://www1.coralnet.or.jp/yonetch/#20170622</link>
<dc:date>2017-06-22</dc:date>
<description>Outlook - iCloud 連携に問題がッ!</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170620">
<title>【トレッカーyonetch】 翻訳ツッコミ ENT第3シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3</link>
<dc:date>2017-06-20</dc:date>
<description>IMPULSE</description>
</item>
<item rdf:about="http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3#he20170608">
<title>【トレッカーyonetch】 翻訳ツッコミ ENT第3シーズン</title>
<link>http://www1.coralnet.or.jp/yonetch/startrek/eval.html#ENT3</link>
<dc:date>2017-06-08</dc:date>
<description>RAJIIN</description>
</item>
</rdf:RDF>
【生成されたRDFファイル】
閉じタグの有無だ。まともな(?) XMLへの道の第一歩は、XHTML化することだった。何が違うって、dlタグ内の、dt、ddタグに、HTMLでは閉じタグがないのである。ワタシの日記は、これをベースにしているので最も使用頻度が高い(と思う)。まずはこれを何とかせねば...
Clean up your Web pages詳細は省くが、これで整形をかけるとHTMLがXHTMLになって出てくる。ほぼそのままで、XML Notepad で読みこめるようになった。
with HTML TIDY
補足: for-eachループとposition()を使って、奇数行、偶数行を決め打ちでやってみたりもしたが、途中からタイトルと本文がずれていく。何か誤認識してるな... ボツ。
XSLTにて、同一階層にあるElementのグループ化について良い方法をご存じでしたらご教授いただけませんでしょうか?
[やりたいこと]
Aから次のAまでElementを1つのグループにする
#XML
<ROOT>
<A>A1</A>
<B>B1</B>
<C>C1</C>
<A>A2</A>
<C>C2</C>
<A>A3</A>
<A>A4</A>
<B>B2</B>
</ROOT>
#結果の想定
<ROOT>
<GROUP>
<A>A1</A>
<B>B1</B>
<C>C1</C>
</GROUP>
<GROUP>
<A>A2</A>
<C>C2</C>
</GROUP>
<GROUP>
<A>A3</A>
</GROUP>
<GROUP>
<A>A4</A>
<B>B2</B>
</GROUP>
</ROOT>
(略)
あ、なるほど。
matchを使っての再帰とかもできるんですね。(そりゃそうですよね。)
再帰 = call-template のイメージがあったので勉強になりました。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" />
<xsl:template match="/">
<xsl:element name="ROOT">
<xsl:for-each select="ROOT/A">
<GROUP>
<xsl:copy-of select="." />
<xsl:call-template name="func">
<xsl:with-param name="node" select="following-sibling::*[1]" />
</xsl:call-template>
</GROUP>
</xsl:for-each>
</xsl:element>
</xsl:template>
<xsl:template name="func">
<xsl:param name="node" />
<xsl:if test="name($node)='B' or name($node)='C'">
<xsl:copy-of select="$node" />
<xsl:call-template name="func">
<xsl:with-param name="node" select="$node/following-sibling::*[1]" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
【[XSLT]同一階層のElementのグループ化】
備考: その本文を、さらに小見出しと地の文に分けて<段落>タグに落とさねばならないが、それはまた別の機会に譲る
<xsl:template match="dl">
<xsl:for-each select="dt">
<記事>
<xsl:attribute name="日付">
<xsl:value-of select="@日付"/>
</xsl:attribute>
<xsl:attribute name="見出し">
<xsl:value-of select="."/>
</xsl:attribute>
<xsl:attribute name="状態">公開</xsl:attribute>
<xsl:call-template name="mydl">
<xsl:with-param name="node" select="following-sibling::*[1]" />
</xsl:call-template>
</記事>
</xsl:for-each>
</xsl:template>
<xsl:template name="mydl">
<xsl:param name="node" />
<xsl:if test="name($node)='dd'">
<xsl:apply-templates select="$node" />
<xsl:call-template name="mydl">
<xsl:with-param name="node" select="$node/following-sibling::*[1]" />
</xsl:call-template>
</xsl:if>
</xsl:template>
XPathの理解に努めること、それを避けて通ることはできなさそうだ。ちょっとWikiPedia「XML Path Language」から引用してみよう。
- 省略構文による簡単なロケーションパスの記述例
/A/B/C
- 少し複雑なロケーションパスの例
A//B/*[1]
- 省略しない完全な構文によって書き直す
/child::A/child::B/child::Cchild::A/descendant-or-self::node()/child::B/child::*[1]
ここまで自分が使ってきたのは、最初の省略形。ごくたまに2番目の形。最後の「完全な構文」なんぞ、全く認識したことがなかった。少なくとも上のコードを読み下せるよう、理解を進めていきたい。
- タイトル
説明
- タイトル
説明
つまり、表現的には dl でなく ul で、一行目にタイトルを強調表示し、改行後説明を表示する。本サイトではそこら中にあるパターンだが、ul で書くのもメンドウなので、ワタシのXML内でdlを使った場合は、上記のように表現することにした。補足: ちなみに、似たような表現をCSSでなんとかできないかとイジってみたが、(理解不足もあって)思ったようにはならなかった。
<xsl:template match="dl">
<xsl:element name="ul">
<xsl:for-each select="dt">
<li>
<b>
<xsl:apply-templates />
</b>
<br />
<xsl:call-template name="mydl">
<xsl:with-param name="node" select="following-sibling::*[1]" />
</xsl:call-template>
</li>
</xsl:for-each>
</xsl:element>
</xsl:template>
<xsl:template name="mydl">
<xsl:param name="node" />
<xsl:if test="name($node)='dd'">
<xsl:value-of select="$node" />
<xsl:call-template name="mydl">
<xsl:with-param name="node" select="$node/following-sibling::*[1]" />
</xsl:call-template>
</xsl:if>
</xsl:template>
【mydl実装部】
ツッコミ記事へのリンクです。
<ツッコミ>THE VULCAN HELLO</ツッコミ>
DSC"THE VULCAN HELLO"(邦題:「バルカン式の挨拶」)
<ツッコミ オプション="1">CHOOSE YOUR PAIN</ツッコミ>
オプション1:邦題表示
オプション2:シリーズ名表示
それ以外 :シリーズ名、邦題表示
<?xml version="1.0" encoding="shift_jis"?> <?xml-stylesheet type="text/xsl" href="diary.xsl"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:t="urn:tables" >
<xsl:output method="xml" encoding="Shift_JIS" />
<xsl:key name="シリーズ情報" match="t:略称" use="@name"/>
<xsl:key name="評価情報" match="t:レベル" use="@name"/>
<xsl:key name="エピソード情報" match="t:エピ" use="t:原題"/>
<xsl:template match="/">
<日記>
<xsl:for-each select="スタートレック//エピ[(not(@状態) and ./原題!='テンプレ') or @状態='公開']">
<xsl:sort select="更新日" order="descending"/>
<記事>
<xsl:attribute name="日付">
<xsl:value-of select="更新日"/>
</xsl:attribute>
<xsl:attribute name="見出し">
<xsl:value-of select="原題"/>
</xsl:attribute>
<xsl:attribute name="状態">公開</xsl:attribute>
<カテゴリ>スター・トレック</カテゴリ>
<サブカテゴリ>翻訳ツッコミ</サブカテゴリ>
</記事>
</xsl:for-each>
</日記>
</xsl:template>
</xsl:stylesheet>
【tsukkomi_list.xsl】
<日記>
<記事 日付="2017-11-11" 見出し="PARALLELS" 状態="公開">
<カテゴリ>スター・トレック</カテゴリ>
<サブカテゴリ>翻訳ツッコミ</サブカテゴリ>
</記事>
<記事 日付="2017-11-10" 見出し="SI VIS PACEM, PARA BELLUM" 状態="公開">
<カテゴリ>スター・トレック</カテゴリ>
<サブカテゴリ>翻訳ツッコミ</サブカテゴリ>
</記事>
<記事 日付="2017-11-04" 見出し="MAGIC TO MAKE THE SANEST MAN GO MAD" 状態="公開">
<カテゴリ>スター・トレック</カテゴリ>
<サブカテゴリ>翻訳ツッコミ</サブカテゴリ>
</記事>
<記事 日付="2017-10-25" 見出し="LETHE" 状態="公開">
<カテゴリ>スター・トレック</カテゴリ>
<サブカテゴリ>翻訳ツッコミ</サブカテゴリ>
</記事>
<記事 日付="2017-10-21" 見出し="CHOOSE YOUR PAIN" 状態="公開">
<カテゴリ>スター・トレック</カテゴリ>
<サブカテゴリ>翻訳ツッコミ</サブカテゴリ>
</記事>
</日記>
【tsukkomi_list.xml (変換結果)】
補足: ちなみに、ツッコミテンプレートの方は、もう一つ、with-quotというオプションがあります
- option 1:邦題表示
- option 2:シリーズ名表示
- それ以外 :シリーズ名、邦題表示
- with-quot 0: ダブルクォーテーションなし
- それ以外 :ダブルクォーテーションあり
<xsl:variable name="ツッコミリスト" select="document('tsukkomi_list.xml')"/>
<xsl:template name="ツッコミ">
<xsl:param name="en_subtitle"/>
<xsl:param name="option">-1
</xsl:param>
<xsl:param name="with-quot">1
</xsl:param>
<xsl:variable name="series" select="$台帳//t:エピ[t:原題=$en_subtitle]/t:シリーズ名"/>
<xsl:variable name="html_fn" select="concat($series,$台帳//t:シリーズ/t:略称[@name=$series]/t:値[@name='シリーズシーズンセパレータ'],$台帳//t:エピ[t:原題=$en_subtitle]/t:シーズン番号,'.html')"/>
<xsl:variable name="ja_subtitle" select="concat('(邦題:「',$台帳//t:エピ[t:原題=$en_subtitle]/t:邦題,'」)')"/>
<xsl:variable name="ep_subtitle">
<xsl:choose>
<xsl:when test="$option='0'">
<xsl:choose>
<xsl:when test="$with-quot='0'">
<xsl:value-of select="$en_subtitle"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('"',$en_subtitle,'"')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$option='1'">
<xsl:value-of select="concat('"',$en_subtitle,'"',$ja_subtitle)"/>
</xsl:when>
<xsl:when test="$option='2'">
<xsl:value-of select="concat($series,'"',$en_subtitle,'"')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($series,'"',$en_subtitle,$ja_subtitle)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="count($ツッコミリスト//記事[@見出し=$en_subtitle]) > 0">
<A>
<xsl:attribute name="href">
<xsl:value-of select="concat($html_fn,'#',$en_subtitle)"/>
</xsl:attribute>
<xsl:value-of select="$ep_subtitle"/>
</A>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$ep_subtitle"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="ツッコミ">
<xsl:call-template name="ツッコミ">
<xsl:with-param name="en_subtitle">
<xsl:value-of select="."/>
</xsl:with-param>
<xsl:with-param name="option">
<xsl:value-of select="@オプション"/>
</xsl:with-param>
</xsl:call-template>
</xsl:template>
htmlファイル名, 原題, 評価Aの個数, 評価Bの個数, ..., 評価Eの個数, Newの有無
このCSVデータを生成するのが、以下のXSLファイルです(字下げ位置改変)。<?xml version="1.0" encoding="shift_jis"?> <?xml-stylesheet type="text/xsl" href="diary.xsl"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:t="urn:tables" >
<xsl:output method="text" encoding="Shift_JIS" />
<xsl:include href="commonlib.xsl" />
<xsl:template match="/">
<xsl:for-each select="スタートレック//エピ[(not(@状態) and ./原題!='テンプレ') or @状態='公開']">
<xsl:variable name="更新日MJD">
<xsl:call-template name="ymd2mjd">
<xsl:with-param name="ymd">
<xsl:value-of select="更新日"/>
</xsl:with-param>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="serif" select="台詞" />
<xsl:value-of select="concat(../../@略称,key('シリーズ情報',../../@略称)/t:値[@name='シリーズシーズンセパレータ'] ,../@シーズン番号,'.html')"/>,"
<xsl:value-of select="原題"/>",
<xsl:value-of select="count($serif/吹替[@評価='A'])" />,
<xsl:value-of select="count($serif/吹替[@評価='B'])" />,
<xsl:value-of select="count($serif/吹替[@評価='C'])" />,
<xsl:value-of select="count($serif/吹替[@評価='D'])" />,
<xsl:value-of select="count($serif/吹替[@評価='E' or @評価='F'])" />,
<xsl:choose>
<xsl:when test="$基準日MJD - $更新日MJD < 180">1</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
<xsl:text></xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
これで作ったCSVファイルを、サーバにアップしました。前にも別件で書いたとおり、サーバ側の集計CGIは(スクリプト作成以後にできた)TASやDSCのことを考慮していません。さてどうなるのかと思ったんですが、少々の不具合はあるものの、一応集計表としては機能できているようです。結果オーライ(^^)/ネトフリの字幕情報がTTMLだったのである!
備考: 人物名を出すんなら、agent属性を使ってそれを地の文に表示する/しないのオプションを設ける、とかした方が論理的だと思うが...
備考: ネトフリのTTMLは、台詞毎に一行にまとまっているため、行ベースの処理系である Perl の方が手っ取り早かった、ということもある
11/2追記: 表示タイミングをhh:mm:ss形式に変換するように変更。DSC第7話で、同じセリフが何度も出てきて映像との照らし合わせがメンドウだったから(^^;)
11/6追記: 下のスクリプト、スタイル名の置換のところでバグってましたんで暫定版に書き換えました。
#ネトフリの字幕TTMLファイルを、yonetch式TTMLモドキに変換する
##########################################################
#斜体スタイル名は "italic" と書き換える
#タイミング指定をtick単位から、hh:mm:ss形式に変換
#本部の先頭に「-(マイナス記号)」がついていて、かつ<br/>(改行)が入っている台詞を2つの要素に分割する
#台詞の先頭に役名が入っているものを、agent属性にする
#agent属性が入っていない場合も、属性のみ追加する(値はヌル)
while(<>)
{
#tickRateを探す
if(/<tt[^<>]+ttp:tickRate="(\d+)"/){
$rate = int($1);
print $rate;
}
#フォントにitalicを使っているスタイルを探す
if(/<style[^<>]+tts:fontStyle="italic"[^<>x]+xml:id="([^<>]+)"[^<>\/]?\/>/){
$italic_style = $1;
#print $italic_style;
}
#s/$italic_style/italic/g; #斜体スタイル名は "italic" と書き換える
s/style_3/italic/g; #style_3 を italic と書き換える
s/<span[^<>]+\/>//g; # まれに値のない<span />タグがあるのであらかじめ削除
#タイミング指定をtick単位から、hh:mm:ss形式に変換
if(/^(<p )begin="(\d+)t" end="(\d+)t"(.+)$/){
$_ = sprintf("%sbegin=\"%s\" end=\"%s\"%s\n",$1,&serial2time($2,$rate),&serial2time($3,$rate),$4);
}
#本部の先頭に「-(マイナス記号)」がついていて、かつ<br/>(改行)が入っている台詞を2つの要素に分割する
# 台詞の先頭に役名が入っているものを、agent属性にする
# agent属性が入っていない場合も、属性のみ追加する(値はヌル)
if(/<br ?\/>/ and /<span[^<>]+>\-/){
/^<p (.+) xml:id="([^<>]+)">(<span[^<>]+>)\-(\[([^\[\]]+)\])?(.*)(<\/span>)<br ?\/>(<span[^<>]+>)\-(\[([^\[\]]+)\])?(.*)(<\/span>)<\/p>$/;
print "<p $1 xml:id=\"$2\" ";
print $6 eq '' ? "agent=\"\">$3-$4$7<\/p>\n": "agent=\"$5\">$3-$6$7<\/p>\n";
print "<p $1 xml:id=\"$2-2\" ";
print $11 eq '' ? "agent=\"\">$8-$9$12<\/p>\n": "agent=\"$10\">$8-$11$12<\/p>\n";
}elsif(/^<p (.+) xml:id="([^<>]+)">(<span[^<>]+>)(\[([^\[\]]+)\])?(.*)(<\/span>)<\/p>$/){
print "<p $1 xml:id=\"$2\" ";
print $6 eq '' ? "agent=\"\">$3$4$7<\/p>\n": "agent=\"$5\">$3$6$7<\/p>\n";
}else{
print;
}
}
sub serial2time {
my ($serial,$rate) = @_;
my $sec = $serial/$rate;
return sprintf("%02d:%02d:%02d",$sec/(60*60),$sec/60,$sec%60);
}
【make_ynttml.pl】
<tt ttp:tickRate="10000000" ttp:timeBase="media">
<head>
<ttp:profile use="http://netflix.com/ttml/profile/dfxp-ls-sdh"/>
<styling>
<style tts:color="white" tts:fontSize="100%" tts:fontStyle="italic" tts:fontWeight="normal" xml:id="style_3"/>
<style tts:color="white" tts:fontSize="100%" tts:fontWeight="normal" xml:id="style_4"/>
</styling>
<layout>
<region tts:displayAlign="before" tts:extent="80.00% 40.00%" tts:origin="10.00% 10.00%" tts:textAlign="center" xml:id="region_1"/>
<region tts:displayAlign="after" tts:extent="80.00% 40.00%" tts:origin="10.00% 50.00%" tts:textAlign="center" xml:id="region_2"/>
</layout>
</head>
<body>
<div xml:space="preserve">
(略)
<p begin="1997412084t" end="2022854167t" region="region_2" xml:id="subtitle44">
<span style="style_4">Georgiou to </span>
<span style="style_3">Shenzhou:</span>
<span style="style_4"> two to transport.</span>
</p>
<p begin="2048296250t" end="2064562500t" region="region_2" xml:id="subtitle45">
<span style="style_4">[thunder crashing nearby]</span>
</p>
<p begin="2065400000t" end="2085000000t" region="region_2" xml:id="subtitle46">
<span style="style_4">[Burnham]</span>
<br/>
<span style="style_4">The storm is faster than I thought.</span>
</p>
(略)
<p begin="3060560000t" end="3095600000t" region="region_2" xml:id="subtitle71">
<span style="style_4">And you? What will you do</span>
<br/>
<span style="style_4">if we're trapped here for 89 years?</span>
</p>
<p begin="3096426667t" end="3115195417t" region="region_2" xml:id="subtitle72">
<span style="style_4">That's easy. I'd escape.</span>
</p>
<p begin="3129380000t" end="3144810000t" region="region_2" xml:id="subtitle73">
<span style="style_4">[Burnham] These are our footprints.</span>
</p>
<p begin="3151064584t" end="3184014167t" region="region_2" xml:id="subtitle74">
<span style="style_4">-You've walked us in a circle.</span>
<br/>
<span style="style_4">-Not exactly a circle.</span>
</p>
(略)
</div>
</body>
</tt>
【ネトフリ版TTML】
<tt ttp:tickRate="10000000" ttp:timeBase="media">
<head>
<ttp:profile use="http://netflix.com/ttml/profile/dfxp-ls-sdh"/>
<styling>
<style tts:color="white" tts:fontSize="100%" tts:fontStyle="italic" tts:fontWeight="normal" xml:id="italic"/>
<style tts:color="white" tts:fontSize="100%" tts:fontWeight="normal" xml:id="style_4"/>
</styling>
<layout>
<region tts:displayAlign="before" tts:extent="80.00% 40.00%" tts:origin="10.00% 10.00%" tts:textAlign="center" xml:id="region_1"/>
<region tts:displayAlign="after" tts:extent="80.00% 40.00%" tts:origin="10.00% 50.00%" tts:textAlign="center" xml:id="region_2"/>
</layout>
</head>
<body>
<div xml:space="preserve">
(略)
<p begin="00:03:19" end="00:03:22" region="region_2" xml:id="subtitle44" agent="">
<span style="style_4">Georgiou to </span>
<span style="italic">Shenzhou:</span>
<span style="style_4"> two to transport.</span>
</p>
<p begin="00:03:26" end="00:03:28" region="region_2" xml:id="subtitle45" agent="">
<span style="style_4">[thunder crashing nearby]</span>
</p>
<p begin="00:03:26" end="00:03:28" region="region_2" xml:id="subtitle46" agent="Burnham">
<span style="style_4"/>
<br/>
<span style="style_4">The storm is faster than I thought.</span>
</p>
(略)
<p begin="00:03:26" end="00:03:28" region="region_2" xml:id="subtitle71" agent="">
<span style="style_4">And you? What will you do</span>
<br/>
<span style="style_4">if we're trapped here for 89 years?</span>
</p>
<p begin="00:03:26" end="00:03:28" region="region_2" xml:id="subtitle72" agent="">
<span style="style_4">That's easy. I'd escape.</span>
</p>
<p begin="00:03:26" end="00:03:28 region="region_2" xml:id="subtitle73" agent="Burnham">
<span style="style_4"> These are our footprints.</span>
</p>
<p begin="00:03:26" end="00:03:28 region="region_2" xml:id="subtitle74" agent="">
<span style="style_4">-You've walked us in a circle.</span>
</p>
<p begin="00:03:26" end="00:03:28 region="region_2" xml:id="subtitle74-2" agent="">
<span style="style_4">-Not exactly a circle.</span>
</p>
(略)
</div>
</body>
</tt>
【yonetch版TTML】
<xsl:param name="cmdline" select="cmdline"/>
<xsl:template match="/ and $cmdline='公開'">
:
(略)
:
</xsl:template>
matchの引数に使えなくとも、メイン部分では使えるはずだ。ということで、少々読みづらいが次のようにした。<xsl:param name="cmdline" select="cmdline"/>
<xsl:template match="/">
<xsl:if test="not(cmdline) or not(@状態) or @状態!='下書き'">
:
(略)
:
</xsl:if>
</xsl:template>
msxslコマンドの引数に、cmdline=true という引数を与える(値は何でもいい)と、xslでは状態属性が下書きのものは処理しない。これにより、XML Notepadではプレビューされるが、msxslでは変換されないという目的を果たせた。備考: ついでといってはナンだが、状態属性の値として'テンプレ'も加えた。この場合は、XML Notepadでもmsxslコマンドでも一切処理されない。
追記: ENT第2シーズンのコンテンツが空であることに気付いた(遅っ)。確認すると、この「状態」属性の扱いにバグがあった。状態属性を取り入れる前に書いた記事に後からその属性を追加することはしていない(手抜き^^;)。そのために、属性のないものは公開対象にならなかったことが原因だった。xslを修正した。
1
02:51:21,184 --> 02:51:24,415
<i>Captain's Starlog, March 21, 2153.</i>
2
02:51:24,721 --> 02:51:27,212
<i>After three days exploring</i>
<i>an uninhabited planet...</i>
3
02:51:27,324 --> 02:51:30,259
<i>Commander Tucker and I have been</i>
<i>called back to</i> Enterprise...
4
02:51:30,360 --> 02:51:32,157
<i>to greet an unexpected visitor.</i>
5
02:51:32,262 --> 02:51:34,389
Maybe you were light-headed
from the altitude.
6
02:51:34,531 --> 02:51:37,898
I didn't slip. That overhang gave way
the moment I put my foot on it.
7
02:51:38,035 --> 02:51:41,004
- I walked on the same rocks you did.
- Maybe you loosened them.
【SRT形式】
追記: 正規TTMLへの準拠を旨とするため、<i>タグは廃止。詳細は10/28付記事にて
補足: 分割した場合は、idでのソートで順番が狂わないように気をつけて附番する必要があるだろう。7/17追記: 台詞分割の手間が割とバカにならないので、srt2xmlの時点で分割してしまうことにした(本来のTTMLからどんどん遠ざかる...^^;)
余談: 定義もスキーマ形式で書ければいいのだけれど、現状理解が追い付いてない(>_<)
<tt xmlns:tt="http://www.w3.org/ns/ttml" xmlns:ttm="http://www.w3.org/ns/ttml#metadata" xmlns:ttp="http://www.w3.org/ns/ttml#parameter" xmlns:tts="http://www.w3.org/ns/ttml#styling" ttp:tickRate="10000000" ttp:timeBase="media" xmlns="http://www.w3.org/ns/ttml">
<head>
<ttp:profile use="http://netflix.com/ttml/profile/dfxp-ls-sdh"/>
<styling>
<style tts:color="white" tts:fontSize="100%" tts:fontWeight="normal" xml:id="style_1"/>
<style tts:color="white" tts:fontSize="100%" tts:fontStyle="italic" tts:fontWeight="normal" xml:id="italic"/>
</styling>
</head>
<body>
<div>
<p xml:id="1" begin="02:51:21,184" end="02:51:24,415" agent="Archer">
<span style="italic">Captain's Starlog, March 21, 2153.</span>
</p>
<p xml:id="2" begin="02:51:24,721" end="02:51:27,212" agent="Archer">
<span style="italic">After three days exploring</span>
<br />
<span style="italic">an uninhabited planet...</span>
</p>
<p xml:id="3" begin="02:51:27,324" end="02:51:30,259" agent="Archer">
<span style="italic">Commander Tucker and I have been</span>
<br />
<span style="italic">called back to</span> Enterprise...
</p>
<p xml:id="4" begin="02:51:30,360" end="02:51:32,157" agent="Archer">
<span style="italic">to greet an unexpected visitor.</span>
</p>
<p xml:id="5" begin="02:51:32,262" end="02:51:34,389" agent="Archer">
Maybe you were light-headed<br />
from the altitude.
</p>
<p xml:id="6" begin="02:51:34,531" end="02:51:37,898" agent="Tucker">
I didn't slip. That overhang gave way<br />
the moment I put my foot on it.
</p>
<p xml:id="7" begin="02:51:38,035" end="02:51:41,004" agent="Archer">
- I walked on the same rocks you did.</p>
<p xml:id="7-2" begin="02:51:38,035" end="02:51:41,004" agent="Tucker">
- Maybe you loosened them.
</p>
</div>
</body>
</tt>
【ネトフリ版TTML形式(改)】
7/17追記: 台詞分割は、行頭に'-(ハイフン)'がついていたら分割、とした。それに合致しないケースもあるかもしれない。盲信はしないようにしよう。
10/26追記: ヘッダー部をネトフリ仕様になるように変更。台詞分割は依然必要なので、「モドキ」である状態は変わらない(^^)
'18/7/18追記: 斜体指定の<i>タグを、TTML仕様の<span>タグに置換するよう変更
use Switch;
$flag_in = 0;
$processing = 0;
$tmp_tag ="";
#print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
#print "<tt xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n";
#print "<body><div>\n";
print <<"EOM";
<tt xmlns:tt="http://www.w3.org/ns/ttml" xmlns:ttm="http://www.w3.org/ns/ttml#metadata" xmlns:ttp="http://www.w3.org/ns/ttml#parameter" xmlns:tts="http://www.w3.org/ns/ttml#styling" ttp:tickRate="10000000" ttp:timeBase="media" xmlns="http://www.w3.org/ns/ttml">
<head>
<ttp:profile use="http://netflix.com/ttml/profile/dfxp-ls-sdh"/>
<styling>
<style tts:color="white" tts:fontSize="100%" tts:fontWeight="normal" xml:id="style_1"/>
<style tts:color="white" tts:fontSize="100%" tts:fontStyle="italic" tts:fontWeight="normal" xml:id="italic"/>
</styling>
</head>
<body><div>
EOM
while(<>)
{
s/<i>/<span style="italic">/g;
s/<\/i>/<\/span>/g;
switch ($_){
case /^(\d+)$/
{
$flag_in = 1;
$id = $_+0;
print "<p xml:id=\"$id\"";
}
case /-->/
{
s/^([\d:,]+) --> ([\d:,]+)$/\tbegin=\"\1\" end=\"\2\" agent=\"\" >/;
$idx = $_;
print $idx;
}
case /^$/
{
s/^$/<\/p>/;
print "$line$_";
$flag_in = 0;
$processing = 0;
$line="";
}
else
{
$line =~ s/(?=\n)/<tmp>/mg;
if($line =~ /^\-/){
$line =~ s/<tmp>/<\/p><p xml:id=\"$id-2\" $idx/mg;
} else {
$line =~ s/<tmp>/<br \/>/mg;
}
$line = "$line$_";
$processing=$processing+1;
}
}
}
print "</div></body></tt>\n";
【srt2xml.pl (ネトフリTTML対応版)】
<台詞>
<原語>
<字幕id>5</字幕id>
</原語>
<吹替 評価="">高さに足がすくんで滑ったんだろう。</吹替>
<直訳 />
<所感 />
</台詞>
<台詞>
<原語>
<字幕id>6</字幕id>
</原語>
<吹替 評価="">滑ったんじゃありません。足をかけた途端に崩れたんです。</吹替>
<直訳 />
<所感 />
</台詞>
<台詞>
<原語>
<字幕id>7</字幕id>
</原語>
<吹替 評価="">あの岩は私も踏んだ。</吹替>
<直訳 />
<所感 />
</台詞>
<台詞>
<原語>
<字幕id>7-2</字幕id>
<字幕id>8</字幕id>
</原語>
<吹替 評価="C">だから崩れたんだ。少しダイエットした方がいいですよ。</吹替>
<直訳>多分船長が乗ったから弛んだんですよ。船長は私より数キロ重いですからね。</直訳>
<所感>許容範囲とは思うが... やはり端折り傾向は否めない。</所感>
</台詞>
【ENT2.xml(抜粋)】
<xsl:template match="原語[字幕id]">
<B>●
<xsl:variable name="en_subtitle" select="../../原題"/>
<!--
<xsl:variable name="字幕" select="document($台帳//t:エピ[t:原題=$en_subtitle]/t:収録[@メディア='DVD']/字幕ファイル)"/>
-->
<xsl:variable name="字幕">
select="document($台帳//t:エピ[t:原題=$en_subtitle]/t:収録[@メディア='DVD']/字幕ファイル)"/>
<xsl:for-each select="字幕id">
<xsl:variable name="id" select="text()"/>
<xsl:variable name="soushoku" select="装飾"/>
<xsl:for-each select="$字幕//p[@xml:id=$id]">
<xsl:choose>
<xsl:when test="$soushoku!=''">
<xsl:value-of select="substring-before(.,$soushoku)"/>
<xsl:element name="{$soushoku/@tag}"><xsl:value-of select="$soushoku"/></xsl:element>
<xsl:value-of select="substring-after(.,$soushoku)"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:if test="position()=last()"> [<xsl:value-of select="$字幕//p[@xml:id=$id]/@agent"/>]</xsl:if>
</xsl:for-each>
</B><BR/>
</xsl:template>
【st_eval.xsl(原語台詞を字幕ファイルとリンクする部分)】
【HTML変換結果】
<?xml version="1.0" encoding="shift_jis"?>
<?xml-stylesheet type="text/xsl" href="diary.xsl"?>
<日記>
<表題>yonetch Works XML化プロジェクトページ</表題>
<副題>〜XMLおよび周辺技術習得のためのメモ〜</副題>
<要旨>本サイト自体のコンテンツを例題として、XMLを中心とした(必ずしもコンテンツ管理に限らない)データ処理に役立つ要素技術を集めるためのメモページです。かなり取り留めのないものになりそうな予感...</要旨>
<記事 見出し="サイト(内部的に)リニューアル計画" 日付="2017-05-03" 状態="公開">
<段落 小見出し="というワケで">さて、経緯の方は<a href="diary2017-2018.html#20170503">更新日記</a>の方で述べましたが、概要だけ再掲しておきます。本サイトyonetch WorksをXML化します。当面の目標は以下の通りです。
<ul><li>日記形式ページのXML書式を策定する</li><li>更新日記をXMLl化する</li><li>更新日記XMLから、以下の各HTMLファイルを自動で生成できるようにする<ul><li>更新日記</li><li>トップページの What's New (直近の更新三項目のリスト)、及び</li><li>rdfファイル</li></ul></li></ul>
以上三点です。なお、XML書式については、暫定的に作成、今このページはXMLで書いています。基本のフォーマットは押さえていますが、既存の日記では他にもいろんなHTMLタグを使っているので、その辺の対応を随時進めていきます。</段落>
<段落 小見出し="早速とばかり">で、ちょっと先を考えると頭が痛いハナシがあります。ワタシ的XML化の本来の目的として、情報と表現の分離、というのがあります。記事の見出しが何、小見出しが何、日付がいつ... というのは本来それをどう表示するかとは別の話です。</段落>
<段落 小見出し="アレもコレも">ですが、最終的な目的が表示にあることも明白です。では現存のHTMLコンテンツで様々なタグを使って作った記事はどうXML化すべきなのか?どう情報と表現を分離すべきなのか?野良プログラマたるワタシは、その辺の系統だった指針とか今時流行の形式、あるいは標準仕様みたいなものには疎いのです。何かありそうな気はしますが... <追記 キャプション="参考">デジタル日記の最たるモノであるブログ、そのデータ形式であるMovable Type形式を調べてみました(<a href="https://www.sixapart.jp/movabletype/manual/3.3/f_import_format/" target="_blank">こちら</a>)。うーん、XML形式じゃないですね(^^;)。ただ、項目とかはこのままパクってウチに合わせて拡張するのでもいいかも... もしかして、この書式に従えば、トラックバックもできるのかな?(それこそ10年遅れてるが...)</追記></段落>
<カテゴリ>XML化プロジェクト</カテゴリ>
<サブカテゴリ>その他</サブカテゴリ>
<キーワード></キーワード>
</記事>
<記事 見出し="" 日付="2017-05-03" 状態="下書き">
<段落 小見出し=""></段落>
<カテゴリ>XML化プロジェクト</カテゴリ>
<サブカテゴリ></サブカテゴリ>
<キーワード></キーワード>
</記事>
</日記>
【XMLファイル(抜粋)】
<?xml version="1.0" encoding="shift_jis"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/xsl/transform" version="1.0">
<?xml-stylesheet type="text/css" href="hpbsite.css"?>
<xsl:output method="html" encoding="shift_jis" />
<xsl:template match="/">
<html>
<head>
<title>
<xsl:value-of select="//表題" />
</title>
<link rel="stylesheet" type="text/css" href="http://www1.coralnet.or.jp/yonetch/hpbsite.css" />
</head>
<body>
<h1>
<xsl:value-of select="//表題" />
</h1>
<blockquote>
<h2>
<xsl:value-of select="//副題" />
</h2>
<xsl:value-of select="//要旨" />
</blockquote>
<hr />
<dl>
<xsl:for-each select="//記事[@状態='公開']">
<xsl:sort select="@日付" order="descending" />
<dt>
<xsl:call-template name="日付表示">
<xsl:with-param name="日付">
<xsl:value-of select="@日付" />
</xsl:with-param>
</xsl:call-template>
<xsl:value-of select="concat(' ',@見出し)" />
</dt>
<xsl:apply-templates />
</xsl:for-each>
</dl>
<hr />
<br />
</body>
</html>
</xsl:template>
<xsl:template match="段落[not(@状態) or @状態='公開']">
<dd>
<b>●<xsl:value-of select="@小見出し" /></b>
<br />
<xsl:apply-templates />
</dd>
</xsl:template>
<xsl:template match="ul|li">
<xsl:copy>
<xsl:for-each select="@*">
<xsl:copy />
</xsl:for-each>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="追記">
<blockquote>
<font size="-1">
<xsl:if test="@日付 and @日付!=''">
<xsl:call-template name="日付表示">
<xsl:with-param name="日付">
<xsl:value-of select="@日付" />
</xsl:with-param>
<xsl:with-param name="形式">
<xsl:value-of select="@形式" />
</xsl:with-param>
<xsl:with-param name="ラベル付">
<xsl:value-of select="@ラベル付" />
</xsl:with-param>
</xsl:call-template>
</xsl:if>
<xsl:choose>
<xsl:when test="@キャプション!=''">
<xsl:value-of select="@キャプション" />
</xsl:when>
<xsl:otherwise>追記</xsl:otherwise>
</xsl:choose>
<xsl:value-of select="': '" />
<xsl:apply-templates />
</font>
</blockquote>
</xsl:template>
<xsl:template match="ソース">
<pre>
<xsl:apply-templates />
</pre>
</xsl:template>
</xsl:stylesheet>
【XSLファイル "diary.xsl"(抜粋)】
参考: デジタル日記の最たるモノであるブログ、そのデータ形式であるMovable Type形式を調べてみました(こちら)。うーん、XML形式じゃないですね(^^;)。ただ、項目とかはこのままパクってウチに合わせて拡張するのでもいいかも... もしかして、この書式に従えば、トラックバックもできるのかな?(それこそ10年遅れてるが...)追記: MT形式に倣い、<記事>タグの属性値に「状態」を追加。“公開”“下書き”の値によって変換対象とするかどうかを使い分けられるようにした(これまでは、適当な属性なり要素の値に“テンプレ”という値を入れるなどしていた)。