2017/07/27
PerlのXMLパーサーモジュール、XML::LibXMLで文字コードShift_JISのXMLをパースしようとしてしばらくハマったので将来の自分用にメモを残しておきます。
$doc = $parser->parse_file(〜)でエラー
XML::LibXMLは$doc = $parser->parse_file(〜)の書式で外部XMLファイルのパスを指定して直接読み込めるのですが、どうもうまくいきません。
用意した読み込み元のXMLは次のような感じ。
|
<?xml version="1.0" encoding="Shift_JIS"?> <TEST> <CONTENTS> <PARAGRAPH>吾輩は猫である。名前はまだ無い。</PARAGRAPH> <PARAGRAPH>どこで生れたかとんと見当がつかぬ。</PARAGRAPH> <PARAGRAPH>何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。</PARAGRAPH> <PARAGRAPH>吾輩はここで始めて人間というものを見た。</PARAGRAPH> <PARAGRAPH>しかもあとで聞くとそれは書生という人間中で一番獰悪な種族であったそうだ。</PARAGRAPH> </CONTENTS> </TEST> |
これを以下のコードでパースしようとして
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
#!/usr/bin/perl use utf8; use warnings; use XML::LibXML; use Encode qw/encode decode/; #変換するXMLファイルのパスを取得 my $convertXmlFilePath = $ARGV[0]; $convertXmlFilePath = decode('UTF-8', $convertXmlFilePath); #ファイルを読み込んでパース my $parser = XML::LibXML->new(); $parser->no_network(1); my $dom = $parser->parse_file($convertXmlFilePath); #<TEST>タグの中身取得 my $tags = $dom->findnodes('///TEST'); #テキスト化して配列収納 my @eachLines; foreach my $tag(@$tags){ push (@eachLines, $tag->serialize); } #テスト出力 my $joinedTxt = join("\x0A",@eachLines); $joinedTxt = encode('UTF-8', $joinedTxt); print $joinedTxt . "\n"; |
以下のようなエラーが返ります。

読み込み元のXMLの文字コード(と宣言文)をUTF-8に変えてやれば普通に読み込めるので、Shift_JIS由来の問題に間違いないようです。どうもXML::LibXMLの$doc = $parser->parse_file(〜)がShift_JISに対応していないのが原因のよう。
$doc = $parser->parse_string(〜)でもエラーになる
困ったなということでネットでいろいろ情報を集めたのですが、use utf8;を宣言していない例とかしか引っかからなくて困りました。Perlの内部コードをShit_JISにしてやりゃそりゃ読めるでしょうが、Unicodeにしかない文字とか扱う可能性があるのでそれじゃダメなのよ。
ということで作戦2として、一旦encodeモジュールを使って内部文字列として読み込んでやり、それを$doc = $parser->parse_string(〜)でパースしてみます。コードは以下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
#!/usr/bin/perl use utf8; use warnings; use XML::LibXML; use Encode qw/encode decode/; #変換するXMLファイルのパスを取得 my $convertXmlFilePath = $ARGV[0]; $convertXmlFilePath = decode('UTF-8', $convertXmlFilePath); #内部文字列として一度展開 open(IN,"$convertXmlFilePath"); @eachLineTxts = <IN>; $xmlTxt = join("",@eachLineTxts); $xmlTxt = decode('Shift_JIS', $xmlTxt); close (IN); #ファイルを読み込んでパース my $parser = XML::LibXML->new(); $parser->no_network(1); my $dom = $parser->parse_string($xmlTxt); #<TEST>タグの中身取得 my $tags = $dom->findnodes('///TEST'); #テキスト化して配列収納 my @eachLines; foreach my $tag(@$tags){ push (@eachLines, $tag->serialize); } #テスト出力 my $joinedTxt = join("\x0A",@eachLines); $joinedTxt = encode('UTF-8', $joinedTxt); print $joinedTxt . "\n"; |
しかしこれでもエラー。

んー・・・
$doc = $parser->読み込んだ文字列内の文字コード宣言の部分を置換して読み込ませて解決
どうしたものかなとしばらくいろいろ($dom = XML::LibXML->load_xml();方面とか)試していたのですがうまくいかず。
もう一度エラー内容とコードを眺めていたら、もしかして読み込みXMLソース内の「encoding="Shift_JIS"」の宣言がイタズラしてるのでは?と思い、一行追加。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
#!/usr/bin/perl use utf8; use warnings; use XML::LibXML; #use XML::LibXML::XPathContext; use Encode qw/encode decode/; #変換するXMLファイルのパスを取得 my $convertXmlFilePath = $ARGV[0]; $convertXmlFilePath = decode('UTF-8', $convertXmlFilePath); #内部文字列として一度展開 open(IN,"$convertXmlFilePath"); @eachLineTxts = <IN>; $xmlTxt = join("",@eachLineTxts); $xmlTxt = decode('Shift_JIS', $xmlTxt); close (IN); #エンコーディング宣言の部分を置換(↓この行を追記) $xmlTxt =~ s@encoding=\"Shift_JIS\"@encoding=\"UTF-8\"@; #ファイルを読み込んでパース my $parser = XML::LibXML->new(); $parser->no_network(1); my $dom = $parser->parse_string($xmlTxt); #<TEST>タグの中身取得 my $tags = $dom->findnodes('///TEST'); #テキスト化して配列収納 my @eachLines; foreach my $tag(@$tags){ push (@eachLines, $tag->serialize); } #テスト出力 my $joinedTxt = join("\x0A",@eachLines); $joinedTxt = encode('UTF-8', $joinedTxt); print $joinedTxt . "\n"; |
これでうまくパースできました。

◇
いやあ文字コードって本当に面倒ですね。
(2017.7.27)
タグ: Perl, Shift_JIS, XML, XML::LibXML, パース
カテゴリー: 未分類 | コメントはまだありません »
2017/07/18
XojoでドロップレットのUIを作る必要があって調べたので備忘録として記しておきます。そのうちまた必要になりそうだし。なおMacで作ってます。Winでどうなのかはテストしてないのでわからないけど流れは多分ほぼ同じ。
アプリアイコンへのドラッグアンドドロップ
アプリアイコンへのドラッグアンドドロップのやり方は以下。
1 ファイルタイプグループを作成
新規にファイルタイプグループを作成し、適宜ドロップしたいファイルタイプを登録する。豊富にファイルタイプのバリエーションが用意されているのでその中から選ぶ感じ。なければ作る。
2 ビルド設定でドロップできるようにするファイルタイプを選択
ビルド設定でドロップできるようにするファイルタイプを選択する。1で適切にファイルタイプを設定していれば選択できるようになっているはず。
3 Appのイベントハンドラ種別でOpenDocumentを選んでコードを記述
AppのイベントハンドラでOpenDocumentを選んで実行したいコードを書く。例えば以下のような感じ。例では拡張子が.TXT以外のものをハネるようにチェックを入れている。もうちょいスマートな方法がありそうなのだが。
|
If item <> Nil And item.exists Then dim path as String = item.NativePath '++++++++++++++TXTファイルかどうかのチェック++++++++++++++ Dim txtOrNotValue As Boolean txtOrNotValue = checkTxtFileOrNotValue(path) if txtOrNotValue then MsgBox path Else Exit End if Else MsgBox(item.name+" doesn't seem to exist") End If quit |
チェック用メソッドは
|
Dim txtOrNot As Boolean = True '++++++++++++++TXTファイルかどうかのチェック++++++++++++++ Dim rg as New RegEx Dim myMatch as RegExMatch rg.SearchPattern= "\.txt$" myMatch=rg.search(checkFilePath) if myMatch <> Nil then Return True else Return False End if |
単純に正規表現で拡張子をチェックしてマッチするかどうかでTrue/Falseを返して判定してる感じ。
特定のウィンドウ内領域へのドラッグアンドドロップ
特定のウィンドウ内領域へのドラッグアンドドロップのやり方は以下。
1 ファイルタイプグループを作成
新規にファイルタイプグループを作成し、適宜ドロップしたいファイルタイプを登録する。豊富にファイルタイプのバリエーションが用意されているのでその中から選ぶ感じ。なければ作る。
2 ドラッグ&ドロップの対象にしたいエリアを作る
ドラッグ&ドロップの対象にしたいエリアを適宜作る。例ではWindow1の中にdropAreaという領域を設定している。
3 イベントハンドラ「Open」を設定
ドラッグ&ドロップの対象エリアにイベントハンドラ「Open」を作り、コードを記述する。コードは以下。
|
me.AcceptFileDrop(DropTypes.Text) |
DropTypes.Textの部分は適宜変える。ドロップされるファイルの種別区分をしないならDropTypes.Allとか。
4 イベントハンドラ「DropObject」を設定
ドラッグ&ドロップの対象エリアにイベントハンドラ「DropObject」を作り、コードを記述する。コードは以下。
|
if obj.FolderItemAvailable then dim f as FolderItem = obj.FolderItem dim path as String = f.NativePath '++++++++++++++TXTファイルかどうかのチェック++++++++++++++ Dim txtOrNotValue As Boolean txtOrNotValue = checkTxtFileOrNotValue(path) if Not txtOrNotValue then Exit End if If f <> Nil Then dropArea.Text = path End If end |
記述例では拡張子が.TXTかどうかをチェックした上で.TXTだった場合にパスをエリア内に記述している。チェックメソッドのコードは上と同じなので割愛。
複数ファイルをドロップして連続実行させるには「do〜Loop Until Not obj.NextItem」で全体を囲む。
(2017.7.19)
※「RegExはデフォルトで大文字小文字を区別しない」との情報をいただいたのでコードをプチ修正しました。
(2017.7.19追記)
※複数ファイルドロップの場合について追記
(2022.3.4追記)
タグ: Xojo, ドラッグアンドドロップ, ドロップレット
カテゴリー: 未分類 | コメントはまだありません »
2017/07/11
こちらのエントリは、JAGAT XMLパブリッシング準研究会で今期の研究テーマとして、W3C文書「日本語組版処理の要件」(JLREQ)と、これに関連してVivliostyleの村上真雄さんたちが提出したW3Cメンバーサブミッション「Web技術を用いた日本語組版の現状」を取り扱っていることに伴い、会員以外の方の意見を広く求めるとともに、記録を残しておく目的で議事録をベースに補足したものを公開するものです。
間違い、補足などございましたらご意見いただければ幸いです。なお、当ブログはコメント許可制を取っているため、反映に時間がかかります。あらかじめご理解ください。
方針としましてはW3C文書「日本語組版処理の要件」(JLREQ)を先頭から読んでいき、各要素に対応するCSSが存在するのか、存在するとして実用段階なのか、InDesignなどの組版ソフトではどういった形で機能を実現しているのか(いないのか)、などについて見ています。なお全体に対しての包括的な説明の部分に関しては、細かな部分は次回以降にその部分の説明が出てきた時に掘り下げる、としてスルーしている箇所があります。
なお、こちらで取り上げております各CSSプロパティはまだドラフト仕様の段階のものも多いため、今現在すぐに使えるものばかりではありません。Webブラウザで使用出来るかどうかはこちらなどでご確認ください。また、電子書籍のRSで使用出来るかどうかは、現在広範に調査した資料がありません。いずれ当研究会の活動として調査を行いたく考えていますが、しばらく時間はかかるかと思います。
縦組み、横組みそれぞれの柱とノンブルの代表的配置例が示されている。ただし、DTPによるレイアウトが一般化した現在では、ここの例に留まらない様々なレイアウトが行われている。
CSS:柱とノンブル
CSS paged media module level 3で規定されている。
ノンブル、柱の表示指定は「@page{ }」の中に書く。CSSでのページ関連プロパティ指定の基本。
・@page :right/@page :left
左右ページの指定疑似クラス(pseudo-class)。
・@page :first
先頭ページ(扉など)の指定疑似クラス。
・@page :blank
空白ページの指定疑似クラス(改丁などで生じるもの)。
・@bottom-center { content: counter(page) }
ノンブルの記述方法。@bottom-centerは表示位置指定。
・@top-center { content: “Sample Contents” }
柱文字の記述方法。この場合は「Sample Contents」が肩文字として表示される。@top-centerは表示位置指定。
表示位置の指定はこちらを参考に。
特定ページのみノンブルを隠すのはclass名を定義して@pageで指定すれば一応可能。
「柱には,両柱方式と片柱方式とがある」。
CSS:複数ノンブル(時計数字と通常ノンブルetc)
Page Based Countersでスタイルを指定する
・content: counter(page, lower-roman)
などでそれぞれのノンブルを指定してやる。漢数字などで表示させることもできる(参考)。
なお、epub等でよく見られるように複数ファイルを通しでノンブルを振るような仕組みが現状CSSにはない。これは提言があってもよいかも。
・font-feature-settings:"onum"
ノンブルにオールドスタイル字形を使うことができる。他にもさまざまな数字の表示指定が可能。
縦組と横組で形が異なる約物には、以下のものがある。
■句点類と読点類
「縦組では,句点類には,句点[。]を,読点類には読点[、]を使用する.」
「横組で使用する句点類と読点類の組合せには,次の3つの方式がある.」
コンマ[,]とピリオド[.]を使用する
コンマ[,]と句点[。]を使用する
読点[、]と句点[。]を使用する.
■かぎ括弧(始めかぎ括弧[「]及び終わりかぎ括弧[」])とクォーテーションマーク(左ダブルクォーテーションマーク[“] 及び右ダブルクォーテーションマーク[”] 並びに左シングルクォーテーションマーク[‘] 及び右シングルクォーテーションマーク[’])
「縦組では,始めかぎ括弧[「] 及び終わりかぎ括弧[」] を用いる」
「横組では,始めかぎ括弧[「] 及び終わりかぎ括弧[」] に替えて左ダブルクォーテーションマーク[“] 及び右ダブルクォーテーションマーク[”] ,又は左シングルクォーテーションマーク[‘] 及び右シングルクォーテーションマーク[’] を用いる方法がある」
「ダブルクォーテーションマークに似た括弧類にダブルミニュート(始めダブルミニュート[〝] 及び終わりダブルミニュート[〟] )がある.これは,縦組専用の括弧類であり,横組では使用しない.」
※これは最近横組みでの用例が映像分野などでは見られたりする。
「ブラケット(始め大括弧[[] 及び終わり大括弧[]] )と,きっこう(始めきっこう括弧[〔] 及び終わりきっこう括弧[〕] ) ブラケット([ ])を縦組用に変形したものが,きっこう(〔 〕)である.したがって,特別な場合を除き,横組ではブラケットを使用する.」
これは縦横の明白な使い分けが今ひとつピンと来ない。両方あるような。
他、長音記号なども縦横でグリフ(字形)が変わる。
「読点類,句点類,始め括弧類,終わり括弧類及び中点類の字幅は,半角であるが,これらの約物が漢字等,平仮名又は片仮名と連続する場合は,原則として,それぞれの約物の前又は後ろ(中点類は,その前及び後ろ)に一定の空き量をとることで,結果として全角というサイズになる」
カギの中のカギ、小カギはUnicodeでは分離されていない。
行頭括弧類の字下げ量について。以下の3つの方針がある。
「改行行頭の字下げは全角アキ,折返し行頭は行頭に空き量をとらない配置法である天付きとする.」
「改行行頭の字下げは全角半(全角の1.5倍)アキ,折返し行頭の字下げは二分アキとする.」
「改行行頭の字下げは二分アキ,折返し行頭は天付きとする」
CSS Text Module Level 4 10.1.3にそれぞれの実現方法の記述例がある。
CSSでの基本的方針として行末に来た全角スペースは自動で取って欲しいという要望が出た。ぶら下がりの対象文字に全角スペースを含める方式がよいのではないか。
CSS:ぶら下げ
・hanging-punctuation:force-end / hanging-punctuation:allow-end
強制的にぶら下げがforce-end、ぶら下げを許容するのがallow-endか
今回はここまで。
(2017.7.11)
タグ: CSS, JAGAT, JLREQ, W3C, Web技術を用いた日本語組版の現状, 日本語組版, 日本語組版処理の要件
カテゴリー: 未分類 | 2 件のコメント »