プロデルでネ申Excel作成を自動化したい フォントサイズ編 #1


手順を整理する

前回では端折りましたが、具体的に整理すると次のような手順になります。

sharedStrings.xmlのsst/si下のt要素に入っている記号に従って、所定の文字列(タイトル、日付、氏名etc)と置き換えた後に、
1. si要素のインデックス番号を取得(上から何番目か、番号は0起点)。
2. sheet1.xmlのsheetData/row/c下の v要素の値から、1.と一致するものを探す(文字列セルは t属性="s"で、直下にv要素を持つ)。
3. 一致した v要素の親である c要素から、その s属性の値を取得(これが書式定義のインデックス番号、sとする)。
4. styles.xmlのstyleSheet/cellXfs下の s番目のxf要素をコピーして、親ノードに追加。(これも1.と同様に上から何番目かがインデックス番号になる)。
5. 追加したxf要素のfontId属性の値を取得(fとする)。
6. styleSheet/fonts下の上から f番目のfont要素をコピーして、親ノードに追加(これがフォントの定義)。
7. 追加したxf要素のfontId属性の値を、6.で追加したfont要素のインデックス番号に変更する。
8. sheet1.xmlのsheetData/row下の c要素のs属性の値を、4.で追加したxf要素のインデックス番号に変更する。

要素や属性のコピーはどうするか?

 この中で、4.と6.はひと手間以上かかりそうです。要素や属性を取得→それを新たに追加という処理を延々と書き連ねてもいいのでしょうが、後々の為にもなるべく簡潔にまとめたいところです。font要素については、子要素が設定値を持っているので、適当な要素のXMLを取得して使えばいいのですが、xf要素については要素自身の属性に設定値を持たせているので、このやり方は使えません。親ノードのXMLから必要な部分を切り出すことになりそうです。これって正規表現でどう書けばいいんだろう?

試したシート

 ともかく書いてみようということで、このような単純なシートで試すことにしました。

右のセル(セル2)だけフォントサイズを20ptにします。.rdrファイルと同じフォルダ内のtempフォルダにこの.xlsxファイルが解凍してあるものとします。

xlsx書式操作.rdr
書式xmlは、「[プログラムの位置]temp\xl\styles.xml」をXMLとして開いたもの
シートxmlは、「[プログラムの位置]temp\xl\worksheets\sheet1.xml」をXMLとして開いたもの
文字列xmlは、「[プログラムの位置]temp\xl\sharedStrings.xml」をXMLとして開いたもの
文字列番号一覧は、{}
セル書式番号一覧は、{}
フォントサイズ一覧は、{}

臨時一覧は、文字列xmlから「sst\si」を取得したもの
[臨時一覧の個数]回値へカウントしながら繰り返す
    [臨時一覧(値)の要素一覧]を箱へそれぞれ繰り返す
        もし箱の名前が「t」かつ箱の内容が「セル2」ならば
            文字列番号一覧に(値-1)を加える
        もし終わり
    繰り返し終わり
繰り返し終わり

臨時一覧は、シートxmlから「worksheet\sheetData\row」を取得したもの
[臨時一覧の個数]回値へカウントしながら繰り返す
    [臨時一覧(値)の要素一覧]を箱へそれぞれ繰り返す
        箱の属性一覧を器へそれぞれ繰り返す
            もし器の名前=「t」かつ器の内容=「s」かつ[箱の要素一覧](1)の内容=文字列番号一覧(1)ならば    ーーt属性が存在するとは限らないのでこうする
                箱を、セル書式番号一覧に加える   ーーv要素の値が一致したc要素を格納
            もし終わり
        繰り返し終わり
    繰り返し終わり
繰り返し終わり

ーーフォント定義を追加
臨時一覧は、書式xmlから「styleSheet\fonts\font」を取得したもの
テンプレは、臨時一覧(1)のXML
臨時は、書式xmlから「styleSheet\fonts」を取得したもの
新規フォントidは、臨時(1)の「count」の内容
臨時(1)の「count」の内容は、[新規フォントid]+1
臨時(1)へ「font」という要素を作って臨時に加える
臨時(2)のXMLを、[正規表現でテンプレを「sz val="[[]\d.[]]+\d+"」から「sz val="20"」へ置換したもの]に変える
ーー属性から名前空間定義を削除
臨時(1)のXMLを、[正規表現で臨時(1)のXMLを「xmlns="[[]^"[]]*"」から「」へ置換したもの]に変える

ーーセルの書式定義を追加
臨時一覧は、書式xmlから「styleSheet\cellXfs」を取得したもの
s属性は、セル書式番号一覧(1)の「s」の内容
s属性を報告
テンプレは、[[臨時一覧(1)のXML]から「<xf[[]^>[]]+>[[]^>[]]+></xf>」という正規表現で区別して取り出したもの](s属性+1)
臨時一覧(1)のXMLは、臨時一覧(1)のXML&テンプレ
臨時一覧(1)のXMLを報告
xf要素は、[臨時一覧(1)の要素一覧]([臨時一覧(1)の要素一覧]の個数)   ーー末尾のxf要素を取得
xf要素の「fontId」の内容は、新規フォントid

新規xf要素idは、臨時一覧(1)の「count」の内容
臨時一覧(1)の「count」の内容は、[新規xf要素id]+1
ーー属性から名前空間定義を削除
削除前は、[臨時一覧(1)のXML]
削除後は、[正規表現で[削除前]を「xmlns="[[]^"[]]*"」から「」へ置換したもの]
臨時一覧(1)のXMLを、削除後に変える
セル書式番号一覧(1)の「s」の内容は、新規xf要素id

「[プログラムの位置]temp\xl\styles.xml」に書式xmlを保存する
「[プログラムの位置]temp\xl\worksheets\sheet1.xml」にシートxmlを保存する

変更したxmlファイルをzip圧縮してExcelで開くとこうなりました。

書式の崩れもなくうまく変更できたようです。
 因みに、プロデルでは要素を追加すると名前空間を設定するxmlns属性がしっかりと付きます。XMLファイル冒頭の名前空間が入るのですが、空白のままの場合もあるようなので、念のため削除しておくことにしました。font要素とxf要素とを追加したそれぞれの部分でチマチマと実行していますが、xf要素の方ではうまく削除できていないようです。同一の名前空間であれば動作に影響はないのでしょうか。