<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="http://psychocat.net/scriptNote/rss/style.css" type="text/css"?>
<rdf:RDF xmlns="http://purl.org/rss/1.0/"
         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:content="http://purl.org/rss/1.0/modules/content/"
         xmlns:dc="http://purl.org/dc/elements/1.1/"
         xml:lang="ja">
<channel rdf:about="http://psychocat.net/scriptNote/rss/recent.php">
<title>Script Note</title>
<link>http://psychocat.net/scriptNote/index.php</link>
<dc:date>2008-01-24T12:48:22+0900</dc:date>
<description>
Script Note - RSS (RDF Site Summary) Feed.
</description>
<items>
<rdf:Seq>
<rdf:li rdf:resource="http://psychocat.net/scriptNote/article.php?id=128" />
<rdf:li rdf:resource="http://psychocat.net/scriptNote/article.php?id=127" />
<rdf:li rdf:resource="http://psychocat.net/scriptNote/article.php?id=126" />
<rdf:li rdf:resource="http://psychocat.net/scriptNote/article.php?id=125" />
<rdf:li rdf:resource="http://psychocat.net/scriptNote/article.php?id=124" />
</rdf:Seq>
</items>
</channel>
<item rdf:about="http://psychocat.net/scriptNote/article.php?id=128">
<title>このブログの更新を終了させていただきます</title>
<link>http://psychocat.net/scriptNote/article.php?id=128</link>
<dc:date>2008-01-24T12:48:22+0900</dc:date>
<description>誠に勝手ながら、このブログの更新を終了することにしました。
仕事が忙しくなったことが大きな利用ですが、それを克服してでもブログを書き続ける気力が私にはなくなってしまったのです。
もともとこのブログを立ち上げた第一の目的は、名古屋で同業者を探...</description>
<content:encoded>
<![CDATA[
<p>誠に勝手ながら、このブログの更新を終了することにしました。</p>
<p>仕事が忙しくなったことが大きな利用ですが、それを克服してでもブログを書き続ける気力が私にはなくなってしまったのです。</p>
<p>もともとこのブログを立ち上げた第一の目的は、名古屋で同業者を探すことでした。リアルな世界において知人が欲しかったのです。しかし、どうやらそれは無理なことだったようです。</p>
<p>名古屋にもスクリプトを書かれている方はいらっしゃると思います。しかし、その方々は自社内でのコミュニケーションで十分試行錯誤してスクリプトを書いていくことが可能な環境をお持ちなんだと、私は思うようになりました。だから外部には見えてこない・・・</p>
<p>見つけられなかった原因は私自身にもあると思います。私はあまり、あちこちの掲示板に書き込みをしません。また、自分のこのURLを宣伝することもありませんでした。そんなことでは訪れていただける人も少ないですよね。</p>
<p>と、いろいろといい訳じみたことを書き連ねてもしかたがないので、ここまでにしておきます。</p>
<p>さて、短い期間でしたが、私に有益な情報を教えてくださった方々にお礼申し上げます。ほんとうにありがとうございました。</p>
<p>【Lesson1】はゴールできませんでした。ごめんなさい。これがあったために今日のこの告知が遅くなってしまいました。これだけは更新を続けてゴールさせようと心の中で葛藤あったのですが・・・</p>
<p>それから、このブログはしばらくは削除しません。いつ削除するかはまだ考えていません。今後ブログは書きませんが、wikiのメモだけは公開することにしました。私もネットでいろいろと情報を得ているので、もらうばかりというのは気がとがめます。だから、自分にできるレベル、範囲で情報を公開するつもりです。</p>
<p>
<a href="http://psychocat.net/note/script/index.cgi">Script Note Book</a>
</p>
<p>積極的な更新は望めませんが、こちらは続けることができると思います。</p>
<p>では、みなさん、ごきげんよう。</p>

]]>
</content:encoded>
</item>
<item rdf:about="http://psychocat.net/scriptNote/article.php?id=127">
<title>Excel と XML</title>
<link>http://psychocat.net/scriptNote/article.php?id=127</link>
<dc:date>2007-08-24T13:08:01+0900</dc:date>
<description>ここ数日、さんざん AppleScript で Excel をいじっていました。初めての Excelのスクリプティングで苦労したことには間違いないのですが、まぁ、一度解ってしまえばお気楽な仕事かな？とも感じていました。しかしその後、さらなる...</description>
<content:encoded>
<![CDATA[
<p>ここ数日、さんざん AppleScript で Excel をいじっていました。初めての Excelのスクリプティングで苦労したことには間違いないのですが、まぁ、一度解ってしまえばお気楽な仕事かな？とも感じていました。しかしその後、さらなる要求がクライアントからありました。</p>
<!-- more -->
<p>それを聞いて「う〜ん、困った」・・・ほんとうに困りました。その要求に応えるには、どうやらフィルター参照（AppleScriptの機能の１つ）でリファレンスを得ないことには現実的に無理そうです。私のフィルター参照形式の記述が間違っているのかもしれませんが、どうしても必要な部分の参照が取れません（Excleが対応してないからだと思いますが）。どう、回答しようか？と悩んでいましたが、解決策が見つかりました。</p>
<p>Excel を XML で扱えば良かったんです。たったそれだけです。そうすれば XPath が使えます。attributeを指定して search すれば（AppleScriptに比べれば）瞬速で希望のリファレンスが得られます。セルの Type まで解るじゃありませんか ;-)  前回のブログの、数値と文字列問題も一挙に解決です。最初から XMLを採用すべきだった。</p>
<p>マシンに Perl のXML関連のモジュールをインストールする必要がありますが、もうこだわっている場合じゃありません。作業するマシンにはインストールしてもらいましょう。Excelで適用範囲を取得するのは AppleScriptでゲットするとして、データの処理はやはり Perlです。<span class="note">（欲を言えば、Rubyなんだろうなぁ。RubyでAppleScript）</span>
</p>
<p>今まで <em>CSV</em>か<em>タブ区切りデータ</em>でしか扱わなかったので、まったく気がつきませんでした :-! 　最近 XMLづいてしまってますが、ほんとうに便利だなぁ <span class="important">XML</span>。</p>

]]>
</content:encoded>
</item>
<item rdf:about="http://psychocat.net/scriptNote/article.php?id=126">
<title>Excel と 結合セル</title>
<link>http://psychocat.net/scriptNote/article.php?id=126</link>
<dc:date>2007-08-16T12:49:38+0900</dc:date>
<description>
Excel のデータを扱うことは今までにも何度もありましたが、私の場合は大抵、テキストファイルに変換してから処理していました。だから AppleScript で Excel を直接操作するスクリプトは書いたことがありません。ところが、ある...</description>
<content:encoded>
<![CDATA[
<p>
<img  class="p_blog-icon"  src="http://psychocat.net/scriptNote/resources/AppleScript_icon.png" width="128" height="128" alt="" />Excel のデータを扱うことは今までにも何度もありましたが、私の場合は大抵、テキストファイルに変換してから処理していました。だから AppleScript で Excel を直接操作するスクリプトは書いたことがありません。ところが、ある案件で Excel を起動させ、どうにもそこから直接データを取り出すことが必要となりました。で、休み前に初めて Excelのスクリプトを書きました。</p>
<!-- more -->
<h3>結合セルは面倒だ</h3>
<p>HTMLにしろ InDesignにしろ、何かにつけて面倒な記述に table というものがあります。列方向、あるいや行方向に隣のセルが結合されたアレがイヤ。HTMLを手書きで書いた時も、InDesignタグの表を扱った時も、面倒この上ない・・・苦手です。</p>
<p>Excelでレイアウトされたスプレッドシートは、セル同士が隣り合っていて、そして値が同じならセルは結合されています。人間の目で見て、一瞬にして表の構造を把握するには当たり前の処理だと思います。ところが、これがプログラミングで処理するとなると・・・あ〜、面倒ですね〜。データベースの感覚で、同じ値であろうと省略せずにキッチリと入力してあると簡単なんですが。</p>
<h3>結合セルを含む表のデータをゲットする</h3>
<p>
<img src="http://psychocat.net/scriptNote/resources/20070816_1.png" width="395" height="184" alt="20070816_1.png" />
</p>
<p>さて、上のテーブルの３行、A,B,C列を選択した上で、AppleScript を使って値をゲットしてみます。</p>
<p>
<img src="http://psychocat.net/scriptNote/resources/AS_NEW.png" />
<a href="applescript://com.apple.scripteditor?action=new&amp;script=tell%20application%20%22Microsoft%20Excel%22%0a%09set%20selected_value%20to%20value%20of%20selection%0aend%20tell%0a">選択された部分の値を得る</a>
</p>
<pre class="oe_code">
tell application "Microsoft Excel"
  set selected_value to value of selection
end tell</pre>
<h4>Result</h4>
<p>{{"ABC", "DEF", "GHI"}, {123.0, "456", ""}, {"def", "ghi", ""}}</p>
<p>値の構造はある程度予測した通りでした。しかし、このリストからは結合セルの情報は読み取れません。「結合されて見えなくなっているセルの空白」と、単に「値が入力されていないセルの空白」との区別ができません。</p>
<h3>結合セルのプロパティはないのか？</h3>
<p>当然、結合セルのプロパティがあるに違いありません。そこで用語辞書を調べてみると <span class="important">merge cells</span> がそれに相当するようです。</p>
<p>
<img src="http://psychocat.net/scriptNote/resources/AS_NEW.png" />
<a href="applescript://com.apple.scripteditor?action=new&amp;script=tell%20application%20%22Microsoft%20Excel%22%0a%09set%20selected_value%20to%20merge%20cells%20of%20selection%0aend%20tell%0a%0a">選択されたセルが結合セルかどうか調べる</a>
</p>
<pre class="oe_code">tell application "Microsoft Excel"
  set selected_value to merge cells of selection
end tell</pre>
<p>セルを１つだけ選択して実行すると boolean値で結果がわかります。 「お、楽勝じゃないか！」と喜んでみたのですが、その考えは甘かったようです。<em>value of selection</em> で得たリストの空白部分が何を意味しているのか？　それを調べることが目的なんです。結合された結果、空白なのか？　意図的に未入力にしたから空白なのか？　それを達成するには、選択されたすべてのセルの <em>merge cells</em> の値を調べなくてはいけません。選択した範囲の <em>every cell</em> の参照が必要です。「選択した範囲」というオブジェクトがないので、個々のセルの参照が必要なんですね。列の数、行の数はわかっているのでアクセスするのは簡単です。</p>
<p>
<img src="http://psychocat.net/scriptNote/resources/AS_NEW.png" />
<a href="applescript://com.apple.scripteditor?action=new&amp;script=global%20colorValue%0a%0atell%20application%20%22Microsoft%20Excel%22%0a%09set%20rangeValue%20to%20get%20address%20of%20selection%0a%09set%20colorValue%20to%20%7b227%2c%20247%2c%20241%7d%0aend%20tell%0a%0a--%20get%20range%20infomation%20as%20bounds%20data%0aset%20bounds_cell%20to%20get_bounds_cell%20of%20me%20given%20range%3arangeValue%0a--%20convert%20alphabet%e3%80%80to%20ascii%20number%0aset%20item%202%20of%20bounds_cell%20to%20ASCII%20number%20%28item%202%20of%20bounds_cell%29%0aset%20item%204%20of%20bounds_cell%20to%20ASCII%20number%20%28item%204%20of%20bounds_cell%29%0a--%20marking%20merge%20cells%0arepeat%20with%20row_number%20from%20%28item%201%20of%20bounds_cell%29%20to%20%28item%203%20of%20bounds_cell%29%0a%09repeat%20with%20col%20from%20%28item%202%20of%20bounds_cell%29%20to%20%28item%204%20of%20bounds_cell%29%0a%09%09set%20col_string%20to%20ASCII%20character%20%28col%29%0a%09%09tell%20application%20%22Microsoft%20Excel%22%20to%20set%20aCell%20to%20range%20%28col_string%20%26%20row_number%29%0a%09%09merge_cells_check%20of%20me%20given%20cell%3aaCell%0a%09end%20repeat%0aend%20repeat%0a%0a-----------------------------------------------------------------------------------------%0a--%20marking%20merge%20cells%0aon%20merge_cells_check%20given%20cell%3aaCell%0a%09tell%20application%20%22Microsoft%20Excel%22%0a%09%09if%20merge%20cells%20of%20aCell%20then%0a%09%09%09set%20color%20of%20interior%20object%20of%20aCell%20to%20colorValue%0a%09%09end%20if%0a%09end%20tell%0aend%20merge_cells_check%0a%0a-----------------------------------------------------------------------------------------%0a--%20Getting%20bounds%20data%20as%20each%20value%3b%20top%2c%20left%2c%20bottom%2c%20right%0aon%20get_bounds_cell%20given%20range%3arangeValue%0a%09set%20range_array%20to%20split%20of%20me%20given%20stringValue%3arangeValue%2c%20delimitersChar%3a%22%3a%22%0a%09set%20left_top%20to%20split%20of%20me%20given%20stringValue%3aitem%201%20of%20range_array%2c%20delimitersChar%3a%22%24%22%0a%09set%20right_bottom%20to%20split%20of%20me%20given%20stringValue%3aitem%202%20of%20range_array%2c%20delimitersChar%3a%22%24%22%0a%09return%20%7bitem%203%20of%20left_top%2c%20item%202%20of%20left_top%2c%20item%203%20of%20right_bottom%2c%20item%202%20of%20right_bottom%7d%0aend%20get_bounds_cell%0a%0a---------------------------------------------------------------------------------------------------------------------------------%0a--%20This%20code%20return%20a%20array%20that%20is%20made%20from%20string%20using%20delimiters%20character.%0aon%20split%20given%20stringValue%3aaText%2c%20delimitersChar%3adeliChar%0a%09set%20aText%20to%20aText%20as%20Unicode%20text%0a%09set%20defaultDelimita%20to%20AppleScript%27s%20text%20item%20delimiters%0a%09try%0a%09%09set%20AppleScript%27s%20text%20item%20delimiters%20to%20deliChar%0a%09%09set%20array%20to%20text%20items%20of%20aText%20as%20list%0a%09%09set%20AppleScript%27s%20text%20item%20delimiters%20to%20defaultDelimita%0a%09on%20error%20errMsg%20number%20errNum%0a%09%09set%20AppleScript%27s%20text%20item%20delimiters%20to%20defaultDelimita%0a%09%09display%20dialog%20errMsg%20%26%20errNum%20buttons%20%7b%22Quit%22%7d%20default%20button%201%0a%09%09error%20number%20-128%0a%09end%20try%0a%09return%20array%0aend%20split%0a">選択した範囲内の、個々のセルの結合セル属性をチェックする。　</a>
　</p>
<pre class="oe_code"> 1 global colorValue
 2 
 3 tell application "Microsoft Excel"
 4   set rangeValue to get address of selection
 5   set colorValue to {227, 247, 241}
 6 end tell
 7 
 8 -- get range infomation as bounds data
 9 set bounds_cell to get_bounds_cell of me given range:rangeValue
10 -- convert alphabet　to ascii number
11 set item 2 of bounds_cell to ASCII number (item 2 of bounds_cell)
12 set item 4 of bounds_cell to ASCII number (item 4 of bounds_cell)
13 -- marking merge cells
14 repeat with row_number from (item 1 of bounds_cell) to (item 3 of bounds_cell)
15   repeat with col from (item 2 of bounds_cell) to (item 4 of bounds_cell)
16     set col_string to ASCII character (col)
17     tell application "Microsoft Excel" to set aCell to range (col_string & row_number)
18     merge_cells_check of me given cell:aCell
19   end repeat
20 end repeat
21 
22 -----------------------------------------------------------------------------------------
23 -- marking merge cells
24 on merge_cells_check given cell:aCell
25   tell application "Microsoft Excel"
26     if merge cells of aCell then
27       set color of interior object of aCell to colorValue
28     end if
29   end tell
30 end merge_cells_check
31 
32 -----------------------------------------------------------------------------------------
33 -- Getting bounds data as each value; top, left, bottom, right
34 on get_bounds_cell given range:rangeValue
35   set range_array to split of me given stringValue:rangeValue, delimitersChar:":"
36   set left_top to split of me given stringValue:item 1 of range_array, delimitersChar:"$"
37   set right_bottom to split of me given stringValue:item 2 of range_array, delimitersChar:"$"
38   return {item 3 of left_top, item 2 of left_top, item 3 of right_bottom, item 2 of right_bottom}
39 end get_bounds_cell
40 
41 ---------------------------------------------------------------------------------------------------------------------------------
42 -- This code return a array that is made from string using delimiters character.
43 on split given stringValue:aText, delimitersChar:deliChar
44   set aText to aText as Unicode text
45   set defaultDelimita to AppleScript's text item delimiters
46   try
47     set AppleScript's text item delimiters to deliChar
48     set array to text items of aText as list
49     set AppleScript's text item delimiters to defaultDelimita
50   on error errMsg number errNum
51     set AppleScript's text item delimiters to defaultDelimita
52     display dialog errMsg & errNum buttons {"Quit"} default button 1
53     error number -128
54   end try
55   return array
56 end split</pre>
<p>ちなみに以下のような複雑に結合している table で試してみました。結合セルの部分の背景が着色されます。</p>
<p>
<img src="http://psychocat.net/scriptNote/resources/20070816_2.png" width="623" height="271" alt="20070816_2.png" />
</p>
<p>これを見ると一見問題ないように見えますが、実は大きな落とし穴がありました。ここでつまずきました。</p>
<h3>merge cells の値だけでは、グルーピイングができない!</h3>
<p>つまり、例えば <em>E6</em> は結合セルです。<em>E8</em> は結合セルではありません。でも結合セルの範囲内です。そして、<em>D8</em> も結合セルです。さて、ここで <em>value of selection</em> で得たリスト構造を処理していく過程で、<em>E8</em> がどのセルに属する結合セルの一部なのか？　判断ができません。<em>D8</em> と結合しているのでしょうか？　個々のセルを単独に調べる限り、リストのデータを正しく処理できないようです。</p>
<p>ごめんなさい。私には文章を書く能力が不足しているようなので、うまくこの状態を説明することができません。実際に頭の中でデータのハンドリングを想像すると解ると思うのですが・・・・。</p>
<p>どうやら結合セルの範囲も含め、それらの情報をゲットできるのは <em>merge cells</em> で true が返ってきた時にその範囲を調べるしか方法がないようです。</p>
<p>さらに、一番の問題がここにあります。結合された範囲の参照を <em>get address</em> で得るには UI上で selection 状態にしないと得られませんでした。例えば、"E6" のセルが <em>merge cells</em> だからと言って、その range を引数にして <em>get address</em> で得ようとしても同じ結果が返ってくるだけです。UIで "E6" を選択状態にすれば、その結果、結合セルとして構成されている他のセルも選択され、初めて目的の range が得られる形になります。ただでさえ選択されたセルすべてをチェックしているスクリプトなのに、このうえさらに選択状態を繰り返すなんて・・・。これは避けたい。避けたいけど、他に方法が見つかりません。</p>
<h3>Excelの結合セルを含む table を扱うスクリプト</h3>
<p>私は普段、Ruby で書かれた <a href="http://hikiwiki.org/ja/">Hiki</a> というツールをメモとして利用しています。その中では結合セルも含めて Table を表示することができます。そこで、その Table を表示するための form を Excel から得るためのスクリプトを書きました。</p>
<p>
<img src="http://psychocat.net/scriptNote/resources/AS_NEW.png" />
<a href="applescript://com.apple.scripteditor?action=new&amp;script=global%20colorValue%0aglobal%20merge_cells_range%0aglobal%20merge_cells_list%0a%0aset%20merge_cells_range%20to%20%7b%7d%0a%0atell%20application%20%22Microsoft%20Excel%22%0a%09set%20rangeValue%20to%20get%20address%20of%20selection%0a%09set%20colorValue%20to%20%7b227%2c%20247%2c%20241%7d%0aend%20tell%0a--%20%e4%be%8b%e3%81%88%e3%81%b0%e3%80%81rangeValue%20%e3%81%ae%e5%80%a4%e3%81%af%20%22%24C%245%3a%24G%2411%22%20%e3%81%ae%e3%82%88%e3%81%86%e3%81%ab%e3%81%aa%e3%82%8b%e3%80%82%0a%0a--%20%e9%81%b8%e6%8a%9e%e3%81%95%e3%82%8c%e3%81%a6%e3%81%84%e3%82%8b%e3%82%bb%e3%83%ab%e3%81%ae%e5%ba%a7%e6%a8%99%e3%82%92%e5%be%97%e3%82%8b%0aset%20selected_area_bounds%20to%20get_selected_area_bounds%20of%20me%20given%20range%3arangeValue%0aget%20selected_area_bounds%0a%0a--%20%e5%88%97%e3%81%ae%e5%80%a4%ef%bc%88%e6%96%87%e5%ad%97%ef%bc%89%e3%82%92%e3%82%a2%e3%82%b9%e3%82%ad%e3%83%bc%e3%82%b3%e3%83%bc%e3%83%89%e3%81%ab%e7%bd%ae%e3%81%8d%e6%8f%9b%e3%81%88%e3%82%8b%0aset%20item%202%20of%20selected_area_bounds%20to%20ASCII%20number%20%28item%202%20of%20selected_area_bounds%29%0aset%20item%204%20of%20selected_area_bounds%20to%20ASCII%20number%20%28item%204%20of%20selected_area_bounds%29%0a%0a--%20%e7%b5%90%e5%90%88%e3%82%bb%e3%83%ab%e3%81%a0%e3%81%91%e3%82%92%e6%8a%bd%e5%87%ba%e3%81%99%e3%82%8b%0arepeat%20with%20row_number%20from%20%28item%201%20of%20selected_area_bounds%29%20to%20%28item%203%20of%20selected_area_bounds%29%0a%09repeat%20with%20col%20from%20%28item%202%20of%20selected_area_bounds%29%20to%20%28item%204%20of%20selected_area_bounds%29%0a%09%09set%20col_string%20to%20ASCII%20character%20%28col%29%0a%09%09tell%20application%20%22Microsoft%20Excel%22%20to%20set%20aCell%20to%20range%20%28col_string%20%26%20row_number%29%0a%09%09merge_cells_range_check%20of%20me%20given%20cell%3aaCell%0a%09end%20repeat%0aend%20repeat%0a--%20%e4%be%8b%e3%81%88%e3%81%b0%e3%80%81merge_cells_range%20%e3%81%ae%e5%80%a4%e3%81%af%20%20%7b%22%24E%245%3a%24F%245%22%2c%20%22%24C%246%3a%24C%247%22%2c%20%22%24E%246%3a%24E%248%22%2c%20%22%24F%247%3a%24F%249%22%2c%20%22%24D%248%3a%24D%249%22%2c%20%22%24C%2410%3a%24F%2410%22%2c%20%22%24C%2411%3a%24D%2411%22%7d%20%e3%81%ae%e3%82%88%e3%81%86%e3%81%ab%e3%81%aa%e3%82%8b%0a%0a--%20%e7%b5%90%e5%90%88%e3%82%bb%e3%83%ab%e3%81%ae%e5%ba%a7%e6%a8%99%e3%82%92%e5%be%97%e3%82%8b%0aset%20merge_cells_list%20to%20%7b%7d%0arepeat%20with%20merge_cell%20in%20merge_cells_range%0a%09--%20%e7%b5%90%e5%90%88%e3%82%bb%e3%83%ab%e3%81%ae%e7%af%84%e5%9b%b2%e3%82%92%e8%a7%a3%e6%9e%90%e3%81%99%e3%82%8b%0a%09set%20selected_area_bounds_local%20to%20get_selected_area_bounds%20of%20me%20given%20range%3amerge_cell%0a%09--%20%e9%81%b8%e6%8a%9e%e3%81%95%e3%82%8c%e3%81%9f%e7%af%84%e5%9b%b2%e5%86%85%e3%81%a7%e3%81%ae%e3%80%81%e3%82%bb%e3%83%ab%e3%81%ae%e3%82%a4%e3%83%b3%e3%83%87%e3%83%83%e3%82%af%e3%82%b9%e3%82%92%e5%be%97%e3%82%8b%0a%09set%20item%201%20of%20selected_area_bounds_local%20to%20%28item%201%20of%20selected_area_bounds_local%29%20-%20%28item%201%20of%20selected_area_bounds%29%20%2b%201%0a%09set%20item%202%20of%20selected_area_bounds_local%20to%20%28ASCII%20number%20%28item%202%20of%20selected_area_bounds_local%29%29%20-%20%28item%202%20of%20selected_area_bounds%29%20%2b%201%0a%09set%20item%203%20of%20selected_area_bounds_local%20to%20%28item%203%20of%20selected_area_bounds_local%29%20-%20%28item%201%20of%20selected_area_bounds%29%20%2b%201%0a%09set%20item%204%20of%20selected_area_bounds_local%20to%20%28ASCII%20number%20%28item%204%20of%20selected_area_bounds_local%29%29%20-%20%28item%202%20of%20selected_area_bounds%29%20%2b%201%0a%09--%20%e7%b5%90%e5%90%88%e3%82%bb%e3%83%ab%e3%81%ae%e7%af%84%e5%9b%b2%e3%82%92%e5%90%ab%e3%82%80%20%e3%82%a4%e3%83%b3%e3%83%87%e3%83%83%e3%82%af%e3%82%b9%e6%83%85%e5%a0%b1%e3%81%ae%e3%83%aa%e3%82%b9%e3%83%88%e3%82%92%e4%bd%9c%e6%88%90%e3%81%99%e3%82%8b%0a%09set%20merge_cells_list%20to%20merge_cells_list%20%26%20%c2%ac%0a%09%09%28%28item%201%20of%20selected_area_bounds_local%20as%20string%29%20%26%20%22-%22%20%26%20%28item%202%20of%20selected_area_bounds_local%20as%20string%29%20%26%20%c2%ac%0a%09%09%09%22-%22%20%26%20%28item%203%20of%20selected_area_bounds_local%20as%20string%29%20%26%20%22-%22%20%26%20%28item%204%20of%20selected_area_bounds_local%20as%20string%29%20%c2%ac%0a%09%09%09as%20string%29%0aend%20repeat%0a--%20%20%e4%be%8b%e3%81%88%e3%81%b0%e3%80%81merge_cells_list%20%e3%81%af%20%7b%221-3-1-4%22%2c%20%222-1-3-1%22%2c%20%222-3-4-3%22%2c%20%223-4-5-4%22%2c%20%224-2-5-2%22%2c%20%226-1-6-4%22%2c%20%227-1-7-2%22%7d%20%e3%81%ab%e3%81%aa%e3%82%8b%e3%80%82%0a--%20%224-2-5-2%22%e3%81%af%e3%80%81%e3%80%8c%ef%bc%92%e8%a1%8c%e7%9b%ae%e3%81%ae%20%ef%bc%94%e5%88%97%e7%9b%ae%e3%81%8b%e3%82%89%ef%bc%95%e5%88%97%e7%9b%ae%e3%80%8d%e3%82%92%e6%84%8f%e5%91%b3%e3%81%99%e3%82%8b%e3%80%82%0a%0a--%20%e3%82%bb%e3%83%ab%e5%86%85%e3%81%ae%e3%83%87%e3%83%bc%e3%82%bf%e3%82%92%e3%82%b2%e3%83%83%e3%83%88%e3%81%99%e3%82%8b%0atell%20application%20%22Microsoft%20Excel%22%0a%09set%20table_data%20to%20value%20of%20range%20%28rangeValue%29%0aend%20tell%0a%0a--%20Hiki%e9%a2%a8%e3%81%ae%e6%8e%a5%e9%a0%ad%e8%be%9e%e3%82%92%e7%b5%90%e5%90%88%e3%82%bb%e3%83%ab%e3%81%ae%e9%a0%85%e7%9b%ae%e3%81%ab%e4%bb%98%e5%8a%a0%e3%81%99%e3%82%8b%e3%80%82%0arepeat%20with%20merge_cell%20in%20merge_cells_list%0a%09set%20%7btop_i%2c%20left_i%2c%20bottom_i%2c%20right_i%7d%20to%20split%20of%20me%20given%20stringValue%3amerge_cell%2c%20delimitersChar%3a%22-%22%0a%09%0a%09--%20%e7%b5%90%e5%90%88%e3%82%bb%e3%83%ab%e3%81%ae%e3%83%87%e3%83%bc%e3%82%bf%e3%82%92%e5%8f%96%e5%be%97%0a%09set%20merge_value%20to%20%28item%20left_i%20of%20%28item%20top_i%20of%20table_data%29%29%20as%20Unicode%20text%0a%09%0a%09--%20%e6%a8%aa%e6%96%b9%e5%90%91%e9%80%a3%e7%b5%90%e3%81%af%20%22%3e%22%20%e3%82%92%e4%bb%98%e5%8a%a0%e3%81%99%e3%82%8b%e3%80%82%e9%80%a3%e7%b5%90%e3%81%99%e3%82%8b%e6%95%b0%e5%88%86%e3%80%82%0a%09set%20prefix_column%20to%20%22%22%0a%09set%20w%20to%20%28right_i%20as%20integer%29%20-%20%28left_i%20as%20integer%29%0a%09repeat%20w%20times%0a%09%09set%20prefix_column%20to%20prefix_column%20%26%20%22%3e%22%20as%20string%0a%09end%20repeat%0a%09set%20merge_value%20to%20prefix_column%20%26%20merge_value%20as%20Unicode%20text%0a%09%0a%09--%20%e7%b8%a6%e6%96%b9%e5%90%91%e9%80%a3%e7%b5%90%e3%81%af%20%22%5e%22%20%e3%82%92%e4%bb%98%e5%8a%a0%e3%81%99%e3%82%8b%e3%80%82%e9%80%a3%e7%b5%90%e3%81%99%e3%82%8b%e6%95%b0%e5%88%86%e3%80%82%0a%09set%20prefix_line%20to%20%22%22%0a%09set%20h%20to%20%28bottom_i%20as%20integer%29%20-%20%28top_i%20as%20integer%29%0a%09repeat%20h%20times%0a%09%09set%20prefix_line%20to%20prefix_line%20%26%20%22%5e%22%20as%20string%0a%09end%20repeat%0a%09set%20merge_value%20to%20prefix_line%20%26%20merge_value%20as%20Unicode%20text%0a%09%0a%09--%20%e3%83%aa%e3%82%b9%e3%83%88%e3%83%87%e3%83%bc%e3%82%bf%e3%81%ab%e6%88%bb%e3%81%99%0a%09set%20item%20left_i%20of%20%28item%20top_i%20of%20table_data%29%20to%20merge_value%0a%09%0a%09--%20%e7%b5%90%e5%90%88%e5%87%a6%e7%90%86%e3%81%ae%e3%81%9f%e3%82%81%e3%80%81%e9%9a%a0%e8%94%bd%e3%81%95%e3%82%8c%e3%81%a6%e3%81%84%e3%82%8b%e3%82%bb%e3%83%ab%e3%81%ab%e3%81%af%20%22null%22%20%e3%83%87%e3%83%bc%e3%82%bf%e3%82%92%e4%bb%a3%e5%85%a5%e3%81%99%e3%82%8b%e3%80%82%0a%09repeat%20with%20L%20from%20top_i%20to%20bottom_i%0a%09%09repeat%20with%20col%20from%20left_i%20to%20right_i%0a%09%09%09if%20item%20col%20of%20%28item%20L%20of%20table_data%29%20is%20%22%22%20then%20set%20item%20col%20of%20%28item%20L%20of%20table_data%29%20to%20null%0a%09%09end%20repeat%0a%09end%20repeat%0aend%20repeat%0a%0a--%20Hiki%e7%94%a8%e3%81%ae%20table%20form%20%e3%81%ab%e6%95%b4%e5%bd%a2%e3%81%99%e3%82%8b%20%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%0aset%20hiki_table_form%20to%20%22%22%0arepeat%20with%20L%20in%20table_data%0a%09repeat%20with%20aCell%20in%20L%0a%09%09if%20contents%20of%20aCell%20is%20not%20null%20and%20contents%20of%20aCell%20is%20not%20%22%22%20then%0a%09%09%09set%20hiki_table_form%20to%20hiki_table_form%20%26%20%22%7c%7c%22%20%26%20aCell%0a%09%09else%20if%20contents%20of%20aCell%20is%20%22%22%20then%0a%09%09%09set%20hiki_table_form%20to%20hiki_table_form%20%26%20%22%7c%7c%22%20%26%20%22%e3%80%80%22%0a%09%09end%20if%0a%09end%20repeat%0a%09set%20hiki_table_form%20to%20hiki_table_form%20%26%20return%0aend%20repeat%0a---%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%0a%0a--%20%e3%82%af%e3%83%aa%e3%83%83%e3%83%97%e3%83%9c%e3%83%bc%e3%83%89%e3%81%b8%e3%82%b3%e3%83%94%e3%83%bc%e3%81%99%e3%82%8b%0aset%20the%20clipboard%20to%20hiki_table_form%20as%20Unicode%20text%0a%0abeep%202%0atell%20application%20%22Finder%22%20to%20display%20dialog%20%22%e7%b5%82%e4%ba%86%e3%81%97%e3%81%be%e3%81%97%e3%81%9f%e3%80%82%22%20buttons%20%7b%22OK%22%7d%20default%20button%201%0a%0a%0a%0a---%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%0a--%20Subroutine%0a---%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%0a---------------------------------------------------------------------------------------------------------------------------------%0a--%20%e7%b5%90%e5%90%88%e3%82%bb%e3%83%ab%e3%82%92%e9%81%b8%e6%8a%9e%e3%81%97%e3%80%81%e3%81%9d%e3%81%ae%e7%af%84%e5%9b%b2%e3%82%92%e5%be%97%e3%82%8b%e3%80%82%0a--%20UI%e4%b8%8a%e3%81%a7%20selection%20%e3%81%97%e3%81%aa%e3%81%84%e3%81%a8%e7%b5%90%e5%90%88%e3%82%bb%e3%83%ab%e3%81%ae%20range%20%e3%81%8c%e3%82%b2%e3%83%83%e3%83%88%e3%81%a7%e3%81%8d%e3%81%aa%e3%81%8b%e3%81%a3%e3%81%9f%e3%80%82%0a--%20%e3%81%93%e3%81%ae%e5%87%a6%e7%90%86%e3%81%8c%e4%b8%80%e7%95%aa%e7%84%a1%e9%a7%84%e3%81%aa%e9%83%a8%e5%88%86%e3%81%a0%e3%81%a8%e6%80%9d%e3%81%86%e3%80%82%e3%81%aa%e3%82%93%e3%81%a8%e3%81%8b%e4%bb%96%e3%81%ae%e6%96%b9%e6%b3%95%e3%81%af%e3%81%aa%e3%81%84%e3%81%8b%ef%bc%9f%0aon%20merge_cells_range_check%20given%20cell%3aaCell%0a%09tell%20application%20%22Microsoft%20Excel%22%0a%09%09if%20merge%20cells%20of%20aCell%20then%0a%09%09%09select%20aCell%0a%09%09%09set%20selected_cells%20to%20get%20address%20of%20selection%0a%09%09%09if%20selected_cells%20is%20not%20in%20merge_cells_range%20then%0a%09%09%09%09set%20merge_cells_range%20to%20merge_cells_range%20%26%20selected_cells%0a%09%09%09end%20if%0a%09%09end%20if%0a%09end%20tell%0aend%20merge_cells_range_check%0a%0a---------------------------------------------------------------------------------------------------------------------------------%0a--%20%20%e7%b5%90%e5%90%88%e3%82%bb%e3%83%ab%e3%81%ae%e7%af%84%e5%9b%b2%e3%82%92%e8%a7%a3%e6%9e%90%e3%81%99%e3%82%8b%0aon%20get_selected_area_bounds%20given%20range%3arangeValue%0a%09set%20range_array%20to%20split%20of%20me%20given%20stringValue%3arangeValue%2c%20delimitersChar%3a%22%3a%22%0a%09set%20left_top%20to%20split%20of%20me%20given%20stringValue%3aitem%201%20of%20range_array%2c%20delimitersChar%3a%22%24%22%0a%09set%20right_bottom%20to%20split%20of%20me%20given%20stringValue%3aitem%202%20of%20range_array%2c%20delimitersChar%3a%22%24%22%0a%09return%20%7bitem%203%20of%20left_top%2c%20item%202%20of%20left_top%2c%20item%203%20of%20right_bottom%2c%20item%202%20of%20right_bottom%7d%0aend%20get_selected_area_bounds%0a%0a---------------------------------------------------------------------------------------------------------------------------------%0a--%20This%20code%20return%20a%20array%20that%20is%20made%20from%20string%20using%20delimiters%20character.%0aon%20split%20given%20stringValue%3aaText%2c%20delimitersChar%3adeliChar%0a%09set%20aText%20to%20aText%20as%20Unicode%20text%0a%09set%20defaultDelimita%20to%20AppleScript%27s%20text%20item%20delimiters%0a%09try%0a%09%09set%20AppleScript%27s%20text%20item%20delimiters%20to%20deliChar%0a%09%09set%20array%20to%20text%20items%20of%20aText%20as%20list%0a%09%09set%20AppleScript%27s%20text%20item%20delimiters%20to%20defaultDelimita%0a%09on%20error%20errMsg%20number%20errNum%0a%09%09set%20AppleScript%27s%20text%20item%20delimiters%20to%20defaultDelimita%0a%09%09display%20dialog%20errMsg%20%26%20errNum%20buttons%20%7b%22Quit%22%7d%20default%20button%201%0a%09%09error%20number%20-128%0a%09end%20try%0a%09return%20array%0aend%20split%0a%0a---------------------------------------------------------------------------------------------------------------------------------%0a--%20This%20script%20joins%20a%20array%20to%20a%20string%20with%20delimiters%20character.%0aon%20join%20given%20arrayValue%3aaArray%2c%20delimitersChar%3adeliChar%0a%09set%20defaultDelimita%20to%20AppleScript%27s%20text%20item%20delimiters%0a%09try%0a%09%09set%20AppleScript%27s%20text%20item%20delimiters%20to%20deliChar%0a%09%09set%20temp%20to%20text%20items%20of%20aArray%20as%20Unicode%20text%0a%09%09set%20AppleScript%27s%20text%20item%20delimiters%20to%20defaultDelimita%0a%09on%20error%20errMsg%20number%20errNum%0a%09%09set%20AppleScript%27s%20text%20item%20delimiters%20to%20defaultDelimita%0a%09%09display%20dialog%20errMsg%20%26%20errNum%20buttons%20%7b%22Quit%22%7d%20default%20button%201%0a%09%09error%20number%20-128%0a%09end%20try%0a%09return%20temp%0aend%20join%0a%0a%0a">Excelのセルを選択し、Hiki用 tableソースを生成する。</a>（長いので ブラウザー上への表示は省略します）</p>
<h4>使い方</h4>
<ul>
<li>Excel上のCellで、Hikiに記述したい部分を選択する。</li>
<li>このスクリプトを実行する。</li>
<li>クリップボードにテキストがコピーされるので、それをHikiにペーストする。</li>
<li>セル内改行には対応していません。</li>
</ul>
<p>
<img src="http://psychocat.net/scriptNote/resources/20070816_3.png" width="267" height="159" alt="20070816_3.png" />
</p>
<p>こんな感じで表示されます。背景にある罫線が表の罫線を見えにくくしていますが、ノートのようなデザインでHikiをレイアウトしているので勘弁してください。</p>
<pre class="oe_code">||　||ABC||>DEF||　
||^123.0||456.0||^^GHI||789.0||　
||　||^^JKL||　
||日本||^英国||　
||　||あいう||　
||>>>Global||　
||>かきく||Apple||Windows||Unix</pre>
<p>Hikiでの記述は上の通りです。空白のセルの部分には全角のスペースが代入されています。Safariで表示した場合、最後のセルを空白セルにするために必要でした。</p>
<p>一時は Perlのモジュールをダウンロードしたりしのですが、自分のマシン以外の環境で間違いなく使えるようにしなくてはいけない案件があり、それを踏まえての検証作業のため、こんな形になってしまいました。</p>
<h3>他にもおかしな部分が</h3>
<p>それにしても、文字列としてセルの書式は設定しているのに数値としてゲットしてしまう件も問題だ。はじめは結合セルの時だけ文字列としてゲットできないのかと考えましたが、そうでもないようです。いろいろ試してみましたが、どうも数値扱いにされてしまうパターンが読み取れません。課題は山積みです。</p>

]]>
</content:encoded>
</item>
<item rdf:about="http://psychocat.net/scriptNote/article.php?id=125">
<title>【Lesson1】選択された項目のデータを読み込む［拡張子問題］</title>
<link>http://psychocat.net/scriptNote/article.php?id=125</link>
<dc:date>2007-06-15T23:57:29+0900</dc:date>
<description>今回は、今作成しているスクリプトの中で、あまり触れたくない部分でもあります。使い勝ってがよろしくない。AppleScriptでユーザーインターフェイスが必要になると、いろいろな手を講じなければいけないのですが、標準機能だけでは手段がありませ...</description>
<content:encoded>
<![CDATA[
<p>今回は、今作成しているスクリプトの中で、あまり触れたくない部分でもあります。使い勝ってがよろしくない。AppleScriptでユーザーインターフェイスが必要になると、いろいろな手を講じなければいけないのですが、標準機能だけでは手段がありません。したがって、あくまでも学習用のツール作成という事を考慮し、大目に見て下さい。よろしくお願いします。</p>
<!-- more -->
<h3>「lineStock.txt」内の項目と、ファイル名のダブり問題</h3>
<p>前回の続きです。「現状のスクリプトでは困った状態があります。それはどのような状態でしょう？」と問題の残して終わりました。mixiの方で回答していただきましね。ありがとうございます (^^)</p>
<p>そうなんです。「lineStock.txt」内とブロック格納用のファイル名との間でダブルブッキングする可能性があるんです。次の図を見て下さい。</p>
<p>
<img src="http://psychocat.net/scriptNote/resources/20070615_1.png" width="208" height="243" alt="" />
</p>
<p>上の方にある split は「lineStock.txt」内にある項目。その他、下にある項目はブロック扱いの個々のファイル名に由来する項目。区別が付きません（汗;）今日はこの問題を話題にします。</p>
<h3>行単位のデータか、ブロック単位のデータかの判断</h3>
<p>前回書いたスクリプトでは、選択された項目名で始まるファイルの存在だけで判断しているので、このような状態では必ず <em>Block</em> の結果が戻ってきてしまいます。一番上の項目は行単位のデータですが、これも <em>Block</em> で返ってきます。</p>
<p>悲しいことに choose from list からは、ユーザーが選択した項目がリスト上の何番目に位置していたのか、その情報を返してくれません。もし、この情報が得られれば正しく判断できるのですが、それは望めないようです。</p>
<p>それではどうすれば良いのか？　choose from list に表示する項目名のリスト作成時に、どちらのカテゴリーに所属しているか <em>識別子</em> を付加しておく方法が考えられます。例えば、項目名の後ろに <em>[L]</em> <em>[B]</em> などを付けるんです。そして choose from list からの戻り値を得たら、そのの末尾にある [] 内の文字を読み取ればいいんです。しかし、この方法はリスト上で見た目に美しくないです。</p>
<h3>結論！</h3>
<p>結論を言いましょう (^^;　このツール作成はあくまでも学習用であり、「自分使い専用」の道具です。したがって、この仕様を前提としたソースファイルを用意しましょう。自分で作って、自分で使う分にはその程度の制限は構わないでしょう。</p>
<p>ロジック上で工夫して、たとえ正しく判定できるようにしたとしても、それ以前に、よ〜く考えてみてください。 choose from list のリストに同一の名称がいくつもあっては、選択する時に内容の判断ができませんよね。自分が困るだけです。</p>
<p>本来ならば、同じ項目名で登録できないような仕組みが必要なんだと思います。起動時に同一項目名があれば警告を出して終わらせる、とか。・・・しかし、そのあたりは省かせてください。そのような仕様にするなら「通常の使用」とは別に「データの登録」というプロセスを設けることになると思います。実は、私が使っているツールでは、スクリプトの起動時の表示用リスト作成は、起動時に毎回作成していないのです。ソースファイルの追加や項目名の修正があった場合に「データの登録」のプロセスを「通常の使用」とは別の起動のしかたで動かし実行しているんです。<span class="note">登録時はデータフォルダのドロップ。通常使用時はアプレットのダブルクリック</span>　このあたりもチュートリアルに加えると、少々記事を書くのは力不足なので控えさせてください・・・申し訳ないです。</p>
<p>と言うわけで<em>「lineStock.txt」内の項目と、ファイル名のダブり問題</em> についてはソースをファイルを作成する時にダブらないように、自分で気をつける！</em>　という対処方法で逃げます。(^^;</p>
<p>しかし、それだけでは済まない問題があるのです！　それは拡張子問題です。</p>
<h3>ファイル名の付け方によっては、困った状態になる</h3>
<h4>split が2つある!?</h4>
<p>
<img src="http://psychocat.net/scriptNote/resources/20070615_2.png" width="174" height="105" alt="" />
</p>
<p>上の図はファインダでファイルを見ています。「<em>split</em>」というファイル名が同名で2つ存在していますね。同じフォルダ内にあるのに何故、同一ファイル名が一緒に存在できるのでしょう？ 下の図は Terminalでこのディレクトリを表示したものです。（図の中の一部ファイル名がファインダとは違ってますね。数字が多い。意味はとくにありません）</p>
<h4>実は拡張子が隠れていた</h4>
<p>
<img src="http://psychocat.net/scriptNote/resources/20070615_3.png" width="283" height="100" alt="" />
</p>
<p>これを見るとわかるように「<em>split</em>」とファインダに表示されていた2つは「<em>split</em>」と「<em>split.txt</em>」だったのです。システム上では違うファイル名なんです。</p>
<p>通常は OS X のアプリケーションだけで使用している限り、このような状況にはなりません。OS 9 から OS X がリリースされた時に、基本的にファイル名には必ず拡張子が付ける習慣になったからです。たいていのアプリケーションはファイル名に拡張子を付けて保存します。ファインダで表示させないようにするためのチェックボタンはありますが、システム上は必ず拡張子を付けています。</p>
<h4>拡張子の表示・非表示について、デフォルトでの振る舞いを設定する</h4>
<p>ファインダの「環境設定...」です。</p>
<p>
<img src="http://psychocat.net/scriptNote/resources/20070615_4.png" width="344" height="171" alt="" />
</p>
<p>しかし、ファインダの「情報を見る」のパレットを使えば拡張子のないファイルに付け直すことは簡単です。</p>
<h4>個々のファイルで拡張子の表示・非表示が設定できる</h4>
<p>本当に拡張子を削除することも可能。</p>
<p>
<img src="http://psychocat.net/scriptNote/resources/20070615_6.png" width="275" height="96" alt="" />
</p>
<h4>これは正真正銘、拡張子がない！</h4>
<p>
<img src="http://psychocat.net/scriptNote/resources/20070615_5.png" width="271" height="93" alt="" />
</p>
<p>もちろん Terminalからの操作時はコマンドを叩いた人次第です。したがってファインダ上で <em>ファイル名が同一のもの</em> は、いくらでも、幾つでも存在できるんです。</p>
<p>
<strong class="stronger">split / split.txt / split.ai / split.doc / split.indd ....</strong>
</p>
<p>拡張子を隠したら、ぜ〜んぶ <em>split</em> です！　この状態で今までコーディングしてきたスクリプトを実行すると・・・・困りますね〜。これは今後の処理では大問題なんです。ペーストするデータを読み込むためには、該当するファイルにアクセスしなければいけません。choose from list からの戻り値の文字列だけで、正しくファイルを選択できるのでしょうか？</p>
<h3>意図したファイルに正しくアクセスしよう</h3>
<p>では、いつものようにサンプルスクリプトがあります。まずは準備してください。</p>
<p>
<img src="http://psychocat.net/scriptNote/resources/AS_NEW.png" />
<a href="applescript://com.apple.scripteditor?action=new&amp;script=set%20selected_element%20to%20%22split%22%0a%0atell%20application%20%22Finder%22%0a%09activate%0a%09set%20selections%20to%20selection%0a%09set%20aFolder%20to%20item%201%20of%20selections%0a%09if%20class%20of%20aFolder%20is%20not%20folder%20then%0a%09%09set%20aFolder%20to%20parent%20of%20aFolder%0a%09%09set%20selection%20to%20aFolder%0a%09end%20if%0a%09try%0a%09%09set%20targetFile%20to%20item%201%20of%20%28every%20item%20of%20aFolder%20whose%20name%20of%20it%20starts%20with%20selected_element%29%0a%09%09set%20selection%20to%20targetFile%0a%09on%20error%0a%09%09display%20dialog%20selected_element%20%26%20%22%20%e3%81%8c%e8%a6%8b%e3%81%a4%e3%81%8b%e3%82%8a%e3%81%be%e3%81%9b%e3%82%93%e3%80%82%22%0a%09end%20try%0aend%20tell%0a">選択しているフォルダ内のファイルをセレクトする</a>
</p>
<p>現在作成中のスクリプトの判定部分と同じコードが書かれています。（12行目）</p>
<pre class="oe_code"> 1 set selected_element to "split"
 2 
 3 tell application "Finder"
 4   activate
 5   set selections to selection
 6   set aFolder to item 1 of selections
 7   if class of aFolder is not folder then
 8     set aFolder to parent of aFolder
 9     set selection to aFolder
10   end if
11   try
12     set targetFile to item 1 of (every item of aFolder whose name of it starts with selected_element)
13     set selection to targetFile
14   on error
15     display dialog selected_element & " が見つかりません。"
16   end try
17 end tell</pre>
<p>サンプルとして使っている「sourceData」フォルダ内のファイルを複製して、適当にファイル名を変更してください。</p>
<ul>
<li>split（拡張子なし）<span class="important">split</span>
</li>
<li>split 23.applescript（半角スペースと "23" を追加）<span class="important">split 23</span>
</li>
<li>split.applescript（元々あるファイル）<span class="important">split</span>
</li>
</ul>
<p>この程度あればいいと思います。赤文字は choose from list に表示されるパターンです。</p>
<p>では、「sourceData」フォルダを選択して実行してましょう。"split" がファインダ上で選択されますね。確認してください。本当はこのような状態 − split（拡張子なし）と split.applescript は作らないようにした方がいいでしょう。choose from list で区別ができません。しかし、ファイルにアクセスするスクリプトを書く以上、一応こんな状況にも対処しておいた方がいいと思います。</p>
<p>次に、このスクリプトの1行目、<em>set selected_element to "split"</em> の "split" を "split 2" とかに書き換えてみましょう。"split 2" はファイルにはありませんが「lineStock.txt」内にはある可能性が十分あります。（2ではなく、実際は別の文字列でしょうが）そして実行してください。すると <em>split 23.applescript</em> が選択されてしまいます。<em>
<span class="important">split 2</span>3.applescript</em> 赤文字の部分にマッチしてしまうからです。意図した結果ではありません。これは防がなくてはいけません。「split 2 が見つかりません」と表示されるのが正しい結果です。</p>
<ul>
<li>split 2</li>
<li>split 23</li>
<li>split 234</li>
<li>split23</li>
<li>split</li>
<li>split2</li>
</ul>
<p>いろいろなパターンで実行してください。 choose form list の戻り値が変数selected_element に代入されていると考え、拡張子を含まない部分をだけを対象にして完全一致した場合だけファイルが選択されるうように、12行目を書くわけです。</p>
<p>注意点は、拡張子なしの split が存在していなくても、split.applescript が選択されなければいけません。（両方存在している時は、拡張子のない split が選択されます。拡張子を度外視したフルネームの名前での完全一致が最優先されれば安全）</p>
<p>とにかく何やら難しいですね。うまく説明できません。やりたいことはおわかりになりますか？　誤動作無く、選択した項目名（文字列）だけを使って、ファイルにアクセスをしたいのです。ネックなのは拡張子の存在をどう対処するかです。</p>
<p>今回もクイズとします。ただし、回答は下に掲載しておきます。（たぶん、これでいいと思うだけど（笑））間違っていたら教えてください。</p>
<p>
<img src="http://psychocat.net/scriptNote/resources/AS_NEW.png" />
<a href="applescript://com.apple.scripteditor?action=new&amp;script=set%20selected_element%20to%20%22split%202%22%0a%0atell%20application%20%22Finder%22%0a%09activate%0a%09set%20selections%20to%20selection%0a%09set%20aFolder%20to%20item%201%20of%20selections%0a%09if%20class%20of%20aFolder%20is%20not%20folder%20then%0a%09%09set%20aFolder%20to%20parent%20of%20aFolder%0a%09%09set%20selection%20to%20aFolder%0a%09end%20if%0a%09try%0a%09%09set%20targetFile%20to%20item%201%20of%20%28every%20item%20of%20aFolder%20whose%20name%20of%20it%20is%20selected_element%20or%20%c2%ac%0a%09%09%09displayed%20name%20of%20it%20starts%20with%20selected_element%20%26%20%22.%22%29%0a%09%09set%20selection%20to%20targetFile%0a%09on%20error%0a%09%09display%20dialog%20selected_element%20%26%20%22%20%e3%81%8c%e8%a6%8b%e3%81%a4%e3%81%8b%e3%82%8a%e3%81%be%e3%81%9b%e3%82%93%e3%80%82%22%0a%09end%20try%0aend%20tell%0a">解答</a>
</p>
<h3>まとめ</h3>
<h4>14th</h4>
<ul>
<li>「lineStock.txt」内の項目と、ファイル名のダブり問題</li>
<ul>
<li>choose from list を使う限り、解決できない。</li>
</ul>
<li>拡張子問題</li>
<ul>
<li>ファイル名はファインダで目視した通りとは限らない</li>
</ul>
<ul>
<li>拡張子の有無も考慮に入れて、ファイル参照する</li>
</ul>
</ul>
<p>AppleScript標準の機能だけで作成するとなると、少々キツい部分でした。ユーザーインターフィスが貧弱であることが原因ですね。</p>
<p>さて、今回も問題を残しておきました。出来る限り自分で試行錯誤することをお薦めします。パズルだと思えば楽しいものです。</p>
<p>こちらと連携しています。 <img src="http://psychocat.net/scriptNote/resources/icon_mixi.jpg" width="16" height="16" alt="" /> <a class="ex-ref" href="http://mixi.jp/view_bbs.pl?id=18693322&comment_count=1&comm_id=1403341" title="mixiの掲示板はこちら！" target="_blank">「DTP楽らく操作への道」掲示板</a> このブログの1ページと mixiの1トピックがリンクしています。</p>

]]>
</content:encoded>
</item>
<item rdf:about="http://psychocat.net/scriptNote/article.php?id=124">
<title>XMLの絶対ロケーションパス</title>
<link>http://psychocat.net/scriptNote/article.php?id=124</link>
<dc:date>2007-06-07T12:27:13+0900</dc:date>
<description>Perlでのお話です。XML::XPath を使って、コンテキストノードから absolute path を得る方法がどうしてもわかりませんでした。XPath自体の関数にはそのようなものは見当たりません。AppleScript の XMLL...</description>
<content:encoded>
<![CDATA[
<p>Perlでのお話です。XML::XPath を使って、コンテキストノードから absolute path を得る方法がどうしてもわかりませんでした。XPath自体の関数にはそのようなものは見当たりません。AppleScript の XMLLib でなら <em>XMLGetNodePath</em> が用意されているので悩むことなく期待した結果が得られるのですが、Perlで同じことが簡単にはできませんでした。</p>
<!-- more -->
<p>いつもは AppleScript よりも Perl の方が簡単なことが多いのですが、今回ばかりは時間がかかってしまいました。私が XPath をしっかり理解していないからでしょう。とくに position関数がわからない。自分で書くXPathの式に誤りがあると思い、何度も何度も書き直して試していました。</p>
<p>あまりにも解決しないため、しょうがないので absolute path を得られるサブルーチンを用意することにしました。引数は コンテキストノード。しかし、ここでもposition関数にこだわってしまい、悪戦苦闘しました (^^;　散々悩んだ挙げ句 <em>preceding-sibling</em> という軸のキーワードを使うことを思いつき、なんとかクリアできました。</p>
<h3>サンプルスクリプト</h3>
<pre class="oe_code">  1 #!/usr/bin/perl
  2 use strict;
  3 use POSIX;
  4 use XML::XPath;
  5 use XML::XPath::XMLParser;
  6 
  7 my $XML;
  8 my $start_time;
  9 my $past_time;
 10 my $temp_nodeset;
 11 my $current_node;
 12 
 13 # Reading a XML document.
 14 # clock() : returning the amount of spent processor time in microseconds.
 15 $start_time = clock();
 16 $XML        = XML::XPath->new( filename => $ARGV[0] );
 17 $past_time  = clock() - $start_time;
 18 print "To load XML document : $past_time microseconds.\n";
 19 
 20 # This block is dummy process.
 21 if ( $ARGV[2] eq '-d' ) {
 22     $start_time = clock();
 23     $temp_nodeset = $XML->find('/');
 24     $past_time = clock() - $start_time;
 25     print "Dummy process time   : $past_time microseconds.\n";
 26 }
 27 
 28 # Getting the target node using XPath.
 29 $start_time = clock();
 30 $temp_nodeset = $XML->find( $ARGV[1] );
 31 if ( !$temp_nodeset->size() ) {
 32     print "! The object element was not found.\n";
 33     exit;
 34 }
 35 $current_node = ( $temp_nodeset->get_nodelist )[0];
 36 $past_time = clock() - $start_time;
 37 print "To search for a node : $past_time microseconds.\n";
 38 
 39 # Translating into an absolute XPath string.
 40 $start_time = clock();
 41 my $absolute_path = <span class="important">get_absolute_path( $XML, $current_node )</span>;
 42 $past_time = clock() - $start_time;
 43 print "To get the full path : $past_time microseconds.\n";
 44 
 45 # Retry access using XPath that previously process has made.
 46 $start_time = clock();
 47 $temp_nodeset = $XML->find($absolute_path);
 48 if ( !$temp_nodeset->size() ) {
 49     print "! Retrying failed.\n";
 50     exit;
 51 }
 52 $current_node = ( $temp_nodeset->get_nodelist )[0];
 53 $past_time = clock() - $start_time;
 54 print "To retry get the node: $past_time microseconds.\n";
 55 
 56 # Show the absolute XPath.
 57 print "The absolute XPath   : $absolute_path\n";
 58 
 59 #-----------------------------------------------------------
 60 # following subroutines
 61 #-----------------------------------------------------------
 62 sub <span class="important">get_absolute_path</span> {
 63     my ( $aXML, $aNode ) = @_;
 64     my $parent_node   = '';
 65     my @element_names = ();
 66 
 67     # last node
 68     push @element_names, ( <span class="important">get_element_name_and_posi( $aXML, $aNode )</span> );
 69 
 70     # repeat seach node for some element until root.
 71     $parent_node = get_parent_node( $aXML, $aNode );
 72     while ($parent_node) {
 73         if ( ( ref $parent_node ) ne '' ) {
 74             push @element_names,
 75               ( <span class="important">get_element_name_and_posi( $aXML, $parent_node )</span> );
 76             $parent_node = get_parent_node( $aXML, $parent_node );
 77         }
 78     }
 79 
 80     # make XPath string
 81     return ( join '/', ( reverse @element_names ) );
 82 }
 83 
 84 #-----------------------------------------------------------
 85 sub get_parent_node {
 86     my ( $aXML, $node ) = @_;
 87     my $nodeset;
 88 
 89     $nodeset = $aXML->find( '..', $node );
 90     if ( !$nodeset->size() ) {
 91         return '';
 92     }
 93     else {
 94         return ( $nodeset->get_nodelist )[0];
 95     }
 96 }
 97 
 98 #-----------------------------------------------------------
 99 sub get_element_name_and_posi {
100     my ( $aXML, $current_node ) = @_;
101 
102     # name of element
103     my $current_node_name = $aXML->find( 'local-name(.)', $current_node );
104     if ( !$current_node_name ) {
105         return '';
106     }
107     else {
108         $current_node_name = $current_node_name->string_value();
109     }
110 
111     # position of element
112     my $expression_for_count_index =
113       'count(preceding-sibling::' . $current_node_name . ')';
114     my $count_preSibling =
115       $aXML->find( $expression_for_count_index, $current_node );
116     $count_preSibling = $count_preSibling->string_value();
117     ++$count_preSibling;    # The node position in XPath is based at 1, not 0.
118 
119     # add index
120     if ( $count_preSibling > 1 ) {
121         $current_node_name .= "\[$count_preSibling\]";
122     }
123     return $current_node_name;
124 }</pre>
<p>sample.xmlの内容は伏せさせて頂きます。で、上の結果の５行の簡単な説明は...</p>
<ol>
<li>XMLドキュメントファイルを読み込む時間</li>
<li>引数のXPathにより、そのノードのゲットに要した時間</li>
<li>今回用意したサブルーチンで absolute XPath の作成に要した時間</li>
<li>作成された absolute XPath を使って、再びノードのゲットに要した時間</li>
<li>作成された absolute XPath の式</li>
</ol>
<p>巨大なXMLを読み込んだ時に、あまりにも処理が遅かったので時間を計測してみました。例えば <em>iTunes Music Library.xml</em>のような・・・。ただし、どのみち、POSIX の clock()関数を使っているので、1秒以上必要な処理では計測できません。<span class="note">私の iTunes Music Library.xml では 3分近くかかってしまう(^^;　58673行あるんだ。（CPU:PowerPC G4 733 MHz / Memory:512MB / OS:10.4.9　ちなみに、この iTunesデータは自宅のマックの xmlファイルです。会社のマックに音楽データを入れているわけではありません）</span>
</p>
<p>それにしても 112行から117行の部分に苦労しました。ほんとうにわからなかった。苦労したわりに、CAPNにモジュールがあるかも知れないですね (^^;　でも見つけることができなかった。直接 CAPNを検索したわけではありません。それにググっても、絶対パスを取得する話題自体が少なかった気がします。それとも話題にならないくらいの定石な方法があるのでしょうか？</p>
<h3>今回のテストで気が付いたこと</h3>
<p>どんなXMLファイルを読み込んでも「XMLドキュメントファイルを読み込む時間」は <em>0</em> なんです。ファイルのリファレンスを記録しているだけのようです。そこで、引数の XPath でノードを得る前にダミー処理を実行してみようと考え、オプションを加えました。引数の XPath の後ろに <em>-d</em> を追加します。</p>
<pre class="oe_code">./translateXPath.pl 'XML/sample.xml' "//*[@objectID='card7']/yAxis[.='153.547']" <span class="important">-d</span>
</pre>
<p>これで実行すると、こんな感じになります。</p>
<pre class="oe_code">To load XML document : 0 microseconds.
Dummy process time   : 52 microseconds.
To search for a node : 16 microseconds.
To get the full path : 33 microseconds.
To retry get the node: 1 microseconds.
The absolute XPath   : /root/allocation/page[2]/group[3]/yAxis</pre>
<p>
<em>Dummy process time</em> として 52 microseconds. で先ほど 69 microseconds だった <em>To search for a node</em> は 16 microseconds になりました。オブジェクトを作った段階では parse されていないんですね。最初だけが時間がかかるようなので多少 XML::XPath が遅くても我慢することにします。実際の自動組版の最中は、何度も同じ tree にアクセスするので、2度目以降に激しいストレスを感じなければ問題ないと思います（希望的な予測）。</p>
<h3>追記</h3>
<p>
<em>-w</em> を付けて実行してみたら、警告の雨あられ。ごめんなさい、ごめんなさい。勢いだけでアップしてしまいました。先ほど修正しました。[June 8, 2007 5:23 PM]</p>
<p>しかし、<em>Use of uninitialized value in substitution</em> が抑え切れない。「未定義値を使用したと言われてもなぁ〜。 :-!</p>

]]>
</content:encoded>
</item>

</rdf:RDF>