故郷を離れて三十数年、関東で暮らす永遠の少年のどーってことない日記
xxSEARCHxx
プロフィール

ST☆FF

Author:ST☆FF
HTTといえばインテルの Hyper-Threading Technology!・・・ではなく、放課後ティータイムのことだと思います。

最近の記事
最近のコメント
最近のトラックバック
月別アーカイブ
カテゴリー
ブロとも申請フォーム
ブログ内検索
RSSフィード
リンク

最近の記事


スポンサーサイト 

--/--/-- --:--/--
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

CATEGORY:スポンサー広告 | CM(-) | TB(-) |

Excel VBAで動的ジャグ配列を使う 

2017/03/18 21:09/Sat
Excel VBAで動的ジャグ配列を使う必要に迫られ、その際にテストで書いたコードをメモしときます。
古いバージョンのExcelでも問題なく動くと思います。(検証はしていません。)

' ************************************************************
' Excel2016:VBAで動的ジャグ配列を使う
' 参照設定:なし
' ************************************************************
Option Explicit

' 動的ジャグ配列を返す関数(厳密には3次元配列)
Private Function foo() As Variant

' 構造体などのユーザー定義型は扱いになにかと制限が多いので使わない
' ここでは最小単位をLong値のペアとし要素数2の配列で表現する
' 開始インデックスはWorksheetと相性が良い One Origin とする

Dim arr1() As Variant ' 1次元目の配列(戻り値)
Dim arr2() As Variant ' 2次元目
Dim arr3(1 To 2) As Long ' 3次元目(最小単位)

' ******* arr1(1) *****************************
arr3(1) = 10: arr3(2) = 11 ' 最小単位を編集
ReDim Preserve arr2(1 To 1) ' 2次元目を初期化し
arr2(1) = arr3 ' そこに格納

arr3(1) = 20: arr3(2) = 21 ' 最小単位を編集
ReDim Preserve arr2(1 To 2) ' 2次元目を拡張し
arr2(2) = arr3 ' そこに格納
' -----------
ReDim Preserve arr1(1 To 1) ' 1次元目を初期化し
arr1(1) = arr2 ' そこに格納
' -----------

' ******* arr1(2) *****************************
arr3(1) = 30: arr3(2) = 31 ' 最小単位を編集
ReDim Preserve arr2(1 To 1) ' 2次元目を初期化し
arr2(1) = arr3 ' そこに格納
' -----------
ReDim Preserve arr1(1 To 2) ' 1次元目を拡張し
arr1(2) = arr2 ' そこに格納
' -----------

' ******* arr1(3) *****************************
arr3(1) = 40: arr3(2) = 41 ' 最小単位を編集
ReDim Preserve arr2(1 To 1) ' 2次元目を初期化し
arr2(1) = arr3 ' そこに格納

arr3(1) = 50: arr3(2) = 51 ' 最小単位を編集
ReDim Preserve arr2(1 To 2) ' 2次元目を拡張し
arr2(2) = arr3 ' そこに格納

arr3(1) = 60: arr3(2) = 61 ' 最小単位を編集
ReDim Preserve arr2(1 To 3) ' 2次元目を拡張し
arr2(3) = arr3 ' そこに格納
' -----------
ReDim Preserve arr1(1 To 3) ' 1次元目を拡張し
arr1(3) = arr2 ' そこに格納
' -----------

' 戻り値
foo = arr1

End Function

Private Sub main()

' 表示用変数
Dim strMsg As String
Dim boundary As String
boundary = "------ 開始 ------"

' 作業用中間オブジェクト
Dim arrArr, arr As Variant

' 動的ジャグ配列を受け取る
arrArr = foo()

' ジャグ配列の内容を文字列に書き出す
Dim i, j As Integer
For i = 1 To UBound(arrArr, 1)
strMsg = strMsg + boundary + vbCrLf

arr = arrArr(i)
For j = 1 To UBound(arr, 1)
strMsg = strMsg + CStr(arr(j)(1)) + " - " + CStr(arr(j)(2)) + vbCrLf
Next
boundary = "------ 境界 ------"
Next
strMsg = strMsg + "------ 終了 ------"

' 結果表示
Call MsgBox(strMsg)

End Sub
' ************************************************************


実行結果です。
実行結果20170318





スポンサーサイト
CATEGORY:仕事関係 | CM(0) | TB(0) |

SQL文を作成するVB.netコードを吐くSQL文 

2015/08/24 21:28/Mon
なんだかややこしいタイトルですが、そのまんま「VB.netのコードを自動生成するSQL文」です。
新規プロジェクトでテーブルにデータを挿入するメソッドを書くのは非常にメンドクサイものです。
特にカラム数が多いほどメンドクサイ(笑)
そこでこのSQLが便利です!
--**********************************************************************
-- 指定テーブルのINSERT文を作るVBコードを吐くSQL
-- Object Browser のクリップボード経由だとEXCEL貼り付け用に「"」が「""」に
-- されてしまうのでExcelシート(.xlsx)にファイル出力してから利用する
--**********************************************************************
SELECT 'Public Function GetInsertSql(ByVal argSrt As object) As String' AS VB_CODE FROM DUAL
UNION ALL
SELECT 'Dim sb As New System.Text.StringBuilder' AS VB_CODE FROM DUAL
UNION ALL
SELECT 'sb.Append("insert into ' || 'TABLE_01' || ' (")' AS VB_CODE FROM DUAL -- < YOUR TABLE ID
UNION ALL
SELECT 'sb.Append(" ' || COL_ENUM1.COLUMN_COMMA || '")' AS VB_CODE
FROM (SELECT USER_COL_COMMENTS.COLUMN_NAME || ',' AS COLUMN_COMMA
FROM USER_TAB_COLUMNS
INNER JOIN USER_COL_COMMENTS
ON USER_TAB_COLUMNS.TABLE_NAME = USER_COL_COMMENTS.TABLE_NAME
AND USER_TAB_COLUMNS.COLUMN_NAME = USER_COL_COMMENTS.COLUMN_NAME
WHERE USER_TAB_COLUMNS.TABLE_NAME = 'TABLE_01' -- < YOUR TABLE ID
ORDER BY USER_TAB_COLUMNS.COLUMN_ID) COL_ENUM1
UNION ALL
SELECT 'sb.Append(") values(")' AS VB_CODE FROM DUAL
UNION ALL
SELECT 'sb.Append("''" + argSrt.' || COL_ENUM2.COLUMN_NM || ' + "'',") ' || ''' ' || COL_ENUM2.COLUMN_WAMEI AS VB_CODE
FROM (SELECT USER_COL_COMMENTS.COLUMN_NAME AS COLUMN_NM
, USER_COL_COMMENTS.COMMENTS AS COLUMN_WAMEI
FROM USER_TAB_COLUMNS
INNER JOIN USER_COL_COMMENTS
ON USER_TAB_COLUMNS.TABLE_NAME = USER_COL_COMMENTS.TABLE_NAME
AND USER_TAB_COLUMNS.COLUMN_NAME = USER_COL_COMMENTS.COLUMN_NAME
WHERE USER_TAB_COLUMNS.TABLE_NAME = 'TABLE_01' -- < YOUR TABLE ID
ORDER BY USER_TAB_COLUMNS.COLUMN_ID) COL_ENUM2
UNION ALL
SELECT 'sb.Append(")")' AS VB_CODE FROM DUAL
UNION ALL
SELECT 'Return sb.ToString' AS VB_CODE FROM DUAL
UNION ALL
SELECT 'End Function' AS VB_CODE FROM DUAL

3ヶ所のテーブルIDを対象のものに変更して実行すると、こんな感じのテキストを吐きます。
VB_CODE
Public Function GetInsertSql(ByVal argSrt As object) As String
Dim sb As New System.Text.StringBuilder
sb.Append("insert into TABLE_01 (")
sb.Append(" COLUMN_01,")
sb.Append(" COLUMN_02,")
sb.Append(" COLUMN_03,")
sb.Append(" COLUMN_04,")
sb.Append(" COLUMN_05,")
sb.Append(" COLUMN_06,")
sb.Append(" COLUMN_07,")
sb.Append(" COLUMN_08,")
sb.Append(" COLUMN_09,")
sb.Append(" COLUMN_10,")
sb.Append(") values(")
sb.Append("'" + argSrt.COLUMN_01 + "',") ' カラム01
sb.Append("'" + argSrt.COLUMN_02 + "',") ' カラム02
sb.Append("'" + argSrt.COLUMN_03 + "',") ' カラム03
sb.Append("'" + argSrt.COLUMN_04 + "',") ' カラム04
sb.Append("'" + argSrt.COLUMN_05 + "',") ' カラム05
sb.Append("'" + argSrt.COLUMN_06 + "',") ' カラム06
sb.Append("'" + argSrt.COLUMN_07 + "',") ' カラム07
sb.Append("'" + argSrt.COLUMN_08 + "',") ' カラム08
sb.Append("'" + argSrt.COLUMN_09 + "',") ' カラム09
sb.Append("'" + argSrt.COLUMN_10 + "',") ' カラム10
sb.Append(")")
Return sb.ToString
End Function

後は引数の型を実際の構造体型に打ち変え、最後のカラム名直後と最後の構造体メンバ名直後のカンマを削除すればOKです。
全カラムがキャラであると想定しているので、それ以外(NumberとかDateとか)のカラムは適宜カスタマイズしてください。



CATEGORY:仕事関係 | CM(0) | TB(0) |

log4netをapp.config設定なしで使う 

2015/04/10 22:05/Fri
久しぶりのプログラムネタで、今日は「log4net」について少々。

オープンソースのロギング・サービスである「log4net」は、御承知の通り、本当に便利で、また奥が深いツールです。
ただ、これを使うにはアプリケーション構成ファイルに環境定義を記述する必要があり、ちょっとした使用にあたっては意外に手間のかかるイメージがあります。
今回は思い切って、アプリケーション構成ファイルの編集なしに、コードだけでお手軽にlog4netを使う方法を模索してみました。同一スレッド内で処理毎に別ファイルにログを吐きたい場合に応用出来る方法です。

大袈裟なものはないのですが、強いてメリットをあげると

1)アプリケーション構成ファイルを編集する必要がない。
2)対象のログファイル名を動的に生成して何本でも動的に切り替えることが出来る。

こんなところです。

説明する程のものではありませんので、早速コードを掲載しましょう。
' Formスレッドで使用するLogger
Private _logger As log4net.ILog = log4net.LogManager.GetLogger( _
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType)

'''
''' ログファイル切り替えサンプル
'''

''' VisualStudio2008
Private Sub MultiAppenderTest()

' 共通レイアウト
Const layout As String = _
"%-5level %date{yyyy/MM/dd_HH:mm:ss,fff} [%thread] %logger - %message%newline"
Const LOOPS As Integer = 500

' Appender作成
' ファイルサイズで世代管理するAppender
Dim appender1 = New log4net.Appender.RollingFileAppender() With { _
.Name = "RollingFileAppender1", _
.File = "D:\ap\log4net_log\MultiLog\appender1.log", _
.AppendToFile = True, _
.RollingStyle = log4net.Appender.RollingFileAppender.RollingMode.Size, _
.MaxSizeRollBackups = 5, _
.MaximumFileSize = "12KB", _
.StaticLogFileName = True, _
.Layout = New log4net.Layout.PatternLayout(layout) _
}

' 日付時刻フォルダで世代管理するAppender
Dim appender2 = New log4net.Appender.RollingFileAppender() With { _
.Name = "RollingFileAppender2", _
.File = "D:\ap\log4net_log\MultiLog/", _
.DatePattern = "yyyyMMdd-HHmm'/appender2.log'", _
.AppendToFile = True, _
.RollingStyle = log4net.Appender.RollingFileAppender.RollingMode.Date, _
.StaticLogFileName = False, _
.Layout = New log4net.Layout.PatternLayout(layout) _
}
' appender2にシンプルなフィルタをかけてみる(Infoのみ出力)
Dim lrf = New log4net.Filter.LevelRangeFilter()
lrf.LevelMin = log4net.Core.Level.Info
lrf.LevelMax = log4net.Core.Level.Info
appender2.AddFilter(lrf)

' 現在のLoggerに全Appenderを登録
Dim currentLogger = DirectCast(_logger.Logger, log4net.Repository.Hierarchy.Logger)
With currentLogger
.Level = log4net.Core.Level.All
.AddAppender(appender1)
.AddAppender(appender2)
End With

' 登録後に任意のAppenderを有効化する
For Each apdr as log4net.Appender.FileAppender In currentLogger.Repository.GetAppenders()
' 名称で識別
If apdr.Name.Equals("RollingFileAppender1") Then ' または"RollingFileAppender2"
apdr.ActivateOptions()
Exit For
End If
Next

' 設定完了通知(出力許可)
_logger.Logger.Repository.Configured = True

' ログ出力
Dim title As String = "/" + LOOPS.ToString + "]" + " log4net test"
For i As Integer = 1 To LOOPS
Threading.Thread.Sleep(50)
Me.Text = i.ToString("[000") + title
_logger.InfoFormat("INFO情報出力-loop:{0}", i.ToString("000"))
_logger.WarnFormat("WARN情報出力-loop:{0}", i.ToString("000"))
Application.DoEvents()
Next

' ファイルClose
_logger.Logger.Repository.Shutdown()

MessageBox.Show("終了.")

End Sub
End Class

出力の形式としては最も需要の多いと思われる、ログローテートを2種類取り上げました。
ひとつはファイルサイズでのローテート、もう一つは日付フォルダでのローテートです。
日付でのローテートはファイル名に日付文字を埋め込むのが一般的ですが、今回は捻ってファイル名は固定にして、代わりに日付文字を使ったサブフォルダでのローテートを取り上げています。
サンプルでは日付フォルダでのローテートを短時間でシミュレートするため、DatePatternを1分単位でローテートするように設定してあります。

試し方は簡単で、テストフォームにコマンドボタンをひとつ配置し、そのクリックイベントハンドラに MultiAppenderTest() と記述するだけです。
出力ログファイルを変更して試すには、57行目の比較対象アペンダ名を書き換えて実行します。



CATEGORY:仕事関係 | CM(0) | TB(0) |

jQuery による HTML セルの動的展開・収納 

2013/09/08 17:01/Sun
複雑なリレーションを伴った膨大なデータ量を扱うWEB系システムの画面の悩みといえば、データ検索における問い合わせから結果画面表示完了までの待ち時間がどうしても長くなりがちなことです。
いっそのこと詳細データは省略して、上位キーの情報だけを先にレスポンスとして返して画面を構成出来ればDBへの負担も通信データ量も軽減することが出来ます。

これを何とか実現出来ないものかと前々から思案していたのですが、先日久しぶりに顔を合わせた昔の仕事仲間からかなり突っ込んだヒントを貰うことが出来たので、まとまった時間をとってコードを書いてみました。
最近のjQueryで関連するらしきアドオンとしては footable があるようですが情報が探しきれませんでした。そこで今回は特にそういったものを使うことなく、標準モジュールのみで実装する方法になります。

本来ならばAJAXを使用しサーバからデータを受信して動かすところですが、面倒なのでイベントハンドラ内部にスタブコードを書いてその中でダミーのJSONデータを作り、表示しています。
ただのHTMLファイルですから、クライアントマシン上のブラウザだけで動くようになっています。

コードを追いやすいように画面イメージを先にお見せします。
展開収納画面
列名ヘッダの上には一括展開レベルを選択するためのラジオボタンをつけてみました。
「レベル1まで」を指示してトップレベルの展開セルをクリックすると下画面の様になります。
レベル1の展開セルも同時に展開イベントが起動してcol4列の値が表示されますが、レベル2の展開セルは収納状態で表示されます。

それでは実際のコードを見てみましょう。

ところでHTML形式のコードをブログに貼り付けたら、勝手に広告コードが入ってしまいました。ハイライト表示にしてあるところが挿入された広告部分です。
その際にbodyタグは勝手に取り込まれ、html終了タグは消去されてしまっているので、動かしたい方は適宜補完して下さい。











- expand(jquery-1.4.2にて動作確認)-




























一括展開




col1 col2 col3 col4 col5 col6
値1
値2



上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。
-->

なお、1,2,4,64行目は私がコメントアウトしたのでここもコメントをはずして下さい。
62行目<!-- ここにjavascriptコードを記述 -->
とある部分に、以降に掲載するjavascriptコードを書いていきます。


最初のコードでは、ユーザ関数adjRowspan()とexpand()を追加してライブラリを拡張します。

adjRowspan関数(4行目)
引数numはRowspan属性値の増減を指定する整数値です。
展開/収納イベント発生セルの左側に存在する全セルのRowspan属性値を書き換える機能を持たせます。
展開時には挿入行数分を増分し、収納時には1にするために使用します。
// 展開&収納設定
$.fn.extend({
//自階層と上位階層の rowspan 調整
adjRowspan: function(num) {
var me = this;
return me.prevAll().add(me.parent().prevAll().children(function() {
//上位階層の rowspan 調整対象セレクタ
var selectors = ["dmy"];
for (var i = 0; i < me.attr("class").match(/lv(\d)/)[1]; i++) {
selectors.push(".collapse.lv" + i + ":first");
}
return selectors.join();

} ()).prevAll()).attr("rowspan", function(i, attr) { return attr + num; }).end().end();

},
//展開
expand: function(getHtml) {
var me = this;
var level = me.attr("class").match(/lv(\d)/)[1];

// 実務では非表示inputタグのvalue属性に
// パラメータ(PK情報)付きのasp URLを持たせる
var keyval = me.children().val();

$.ajax({
//.aspのURL
//url: me.children().val(),
url: "about:blank", // デモ用:""でも可
cache: false,
dataType: "json",
success: function(json) {
//rowspan の調整と行追加
var d = eval(json).reverse();
me.adjRowspan(d.length);
$.each(d, function() { me.parent().after(getHtml(this)); });

//一括展開
setTimeout(function() {
me.parent().nextUntil(":has(.lv0)")
// ヘッダで選択されたラジオボタンからセレクタ文字列を取得
.filter(":has(.expand):has(" + $("#autoExpand :checked").val() + "):first")
.children(":last").click();
});
},
// 簡略化の為、サーバ処理は書かずに通信完了イベントに対して
// 正常処理系callbackをバインド(スタブ)
complete: function() {
var jsondata = null;

// レベル切り替え(スタブ)
if (level === '0') { //Level0の展開
if (keyval === 'pk01') {
jsondata = [
{ITEM1:'値11',ITEM2:'値11A',ITEM3:'pk11'},
{ITEM1:'値12',ITEM2:'値12A',ITEM3:'pk12'},
{ITEM1:'値13',ITEM2:'値13A',ITEM3:'pk13'}
]
} else if (keyval === 'pk02') {
jsondata = [
{ITEM1:'値21',ITEM2:'値21A',ITEM3:'pk21'},
{ITEM1:'値22',ITEM2:'値22A',ITEM3:'pk22'},
{ITEM1:'値23',ITEM2:'値23A',ITEM3:'pk23'}
]
};
} else if (level ==='1') { //Level1の展開
if (keyval === 'pk11') {
jsondata = [
{ITEM1:'値111',ITEM2:'pk101'},
{ITEM1:'値112',ITEM2:'pk101'}
]
} else if (keyval === 'pk12') {
jsondata = [
{ITEM1:'値121',ITEM2:'pk103'}
]
} else if (keyval === 'pk13') {
jsondata = [
{ITEM1:'値131',ITEM2:'pk104'},
{ITEM1:'値132',ITEM2:'pk105'}
]
} else if (keyval === 'pk21') {
jsondata = [
{ITEM1:'値211',ITEM2:'pk201'},
{ITEM1:'値212',ITEM2:'pk202'}
]
} else if (keyval === 'pk22') {
jsondata = [
{ITEM1:'値221',ITEM2:'pk203'}
]
} else if (keyval === 'pk23') {
jsondata = [
{ITEM1:'値231',ITEM2:'pk204'}
]
};
} else if (level ==='2') { //Level2の展開
if (keyval === 'pk101') {
jsondata = [
{ITEM1:'値1111',ITEM2:'値1111A'}
]
} else if (keyval === 'pk102') {
jsondata = [
{ITEM1:'値1121',ITEM2:'値1121A'}
]
} else if (keyval === 'pk103') {
jsondata = [
{ITEM1:'値1211',ITEM2:'値1211A'},
{ITEM1:'値1212',ITEM2:'値1212A'}
]
} else if (keyval === 'pk104') {
jsondata = [
{ITEM1:'値1311',ITEM2:'値1311A'}
]
} else if (keyval === 'pk105') {
jsondata = [
{ITEM1:'値1321',ITEM2:'値1321A'}
]
} else if (keyval === 'pk201') {
jsondata = [
{ITEM1:'値2111',ITEM2:'値2111A'},
{ITEM1:'値2112',ITEM2:'値2112A'}
]
} else if (keyval === 'pk202') {
jsondata = [
{ITEM1:'値2121',ITEM2:'値2121A'}
]
} else if (keyval === 'pk203') {
jsondata = [
{ITEM1:'値2211',ITEM2:'値2211A'}
]
} else if (keyval === 'pk204') {
jsondata = [
{ITEM1:'値2311',ITEM2:'値2311A'},
{ITEM1:'値2312',ITEM2:'値2312A'},
{ITEM1:'値2313',ITEM2:'値2313A'}
]
};
};
//.after()する為、予め逆順にする
var d = eval(jsondata).reverse();
me.adjRowspan(d.length);

$.each(d, function() { me.parent().after(getHtml(this)); });

//下層にレベル0のTRタグが現れるまで一括展開
setTimeout(function() {
me.parent().nextUntil(":has(.lv0)")
.filter(":has(.expand):has(" + $("#autoExpand :checked").val() + "):first")
.children(":last").click(); });
}
});
}
});
expand関数(18行目)
引数getHtmlはサーバから受け取ったJSON形式のデータをHTMLに成形する関数へのポインタです。
24行目ではスタブで利用する為だけにkeyvalを取っています。
26-45行目はサーバとの通信が書いてありますが、本版はサーバ処理を必要としないデモ用なので32行目のsuccessが呼ばれることはなく、代わりに必ず呼ばれる48行目のcompleteにcallback関数を書いてあります。
callback関数内では、まずlevelとkeyvalに応じてJSONデータを模造します。
その後139行目で、展開イベント発生セルの直下に挿入する為の準備としてデータの並び順を逆転しています。
140行目では左側に存在する全セルのRowspan属性値を増分した後、142行目で各データに対し、HTML変換と自行直下への挿入を行います。
144行目以下の処理は一括展開の実装部です。画面上部のラジオボタンで自動展開レベルを指定可能にしました。
指定されたレベル毎にセレクタ文字列を取得し、マッチする全イベントセルの展開イベントを起動しています。


次はレベル毎のイベントセルに対応するハンドラの登録部分です。
展開ハンドラ内では無名関数を使用し、その中で拡張関数expand()を呼んでいます。
expand関数の引数はHTML変換関数へのポインタで、この関数の処理を内側の無名関数で記述しています。
HTML変換処理は、関数の引数であるJSONデータdからHTMLタグ文字列を生成して返しているだけです。
//レベル0の展開
$("div.tableview1 td.expand.lv0").live("click", function() {
$(this).expand(function(d) {
return "" +
"" + d.ITEM1 + "" +
"" + d.ITEM2 + "" +
"" +
"開" + "" +
"" +
"";
});
});
//レベル1の展開
$("div.tableview1 td.expand.lv1").live("click", function() {
$(this).expand(function(d) {
return "" +
"" + d.ITEM1 + "" +
"" +
"開" + "" +
"" +
"";
});
});
//レベル2の展開
$("div.tableview1 td.expand.lv2").live("click", function() {
$(this).expand(function(d) {
return "" +
"" + d.ITEM1 + "" +
"" + d.ITEM2 + "" +
"";
});
});

収納ハンドラ内では、無名関数を使用し、イベントセルの左側に存在する全セルのRowspan属性値が1になるまでデクリメントしながら、同時に下層にぶら下がっているデータ行を削除しています。
// 収納
$("div.tableview1 td.collapse").live("click", function() {
//rowspan の調整と下層行の削除
while ($(this).prev().attr("rowspan") > 1) $(this).adjRowspan(-1).parent().next().remove();

//収納によりスクロールが無効になる場合、
//ヘッダ位置調整
$("div.tableview1").scroll();
});

最後はイベントセルの開閉文字をトグル切り替えする処理です。
実業務では更にGIFアイコン等を使用して視覚的に仕上げるのも良いかもしれません。
//クリック毎に収納⇔展開を切替
$("div.tableview1 td.collapse,div.tableview1 td.expand").live("click", function(e) {
$(this)
.toggleClass("collapse").toggleClass("expand")
.html(function(i, htm) {
return $(this).hasClass("collapse") ? htm.replace("開", "閉") : htm.replace("閉", "開");
});
});

以上、簡単に説明をして来ましたが、jQueryは時間さえ許せばなかなか面白いものかもしれません。
仕事で使う分には、単純に「面白い/楽しい」では済まされないものではありますが・・・。



CATEGORY:仕事関係 | CM(0) | TB(0) |

アプリケーション構成ファイルとの格闘2 

2013/04/20 17:18/Sat
以前「アプリケーション構成ファイルとの格闘」において、タグ(のセット)を可変個数設定する方法について書きました。
今回、XMLファイルを別ファイルにすることでシンプルかつ編集可能にもする方法を見つけたので書きたいと思います。
XMLをバリバリ使いこなしておられる諸兄にはイロハのイでしょうが、私の職場環境は良くも悪くもアプリケーション構成ファイルに
ズブズブの状態であるため、掘り下げる機会もあまりなく、ほとんど初心者レベルなのであります。

今回の素材には「ID」と「氏名」を記述するXMLファイルを用い、変化をつけるため「ID」は数値として扱ってみます。
百聞は一見に如かず、下のような感じです。

【Persons.xml】
<?xml version="1.0" encoding="utf-8" ?>
<Settings>
<Person>
<ID>1</ID>
<Name>サンプル一郎</Name>
</Person>
<Person>
<ID>2</ID>
<Name>サンプルニ郎</Name>
</Person>
<Person>
<ID>3</ID>
<Name>サンプル三郎</Name>
</Person>
</Settings>

以降がこのファイルにアクセスするためのクラスです。
上位から順に見ていきます。
まず、ルートにある「Settings」タグを展開するためのクラスを定義します。
直下の「Person」タグの展開用に「CPerson」クラスオブジェクトを要素に持たせます。
「Person」タグの繰り返しは配列として表現します。

【Settings.vb】
Imports System.Xml.Serialization

''' <summary>
''' ルート要素となる「Settings」の内容を定義するクラス
''' </summary>
''' <remarks>"Person"タグが可変個数定義対応</remarks>
<XmlRoot("Settings")> _
Public Class CSettings

' Personタグ
' 可変個数定義を配列として表現
<XmlElement("Person")> _
Public person As CPerson()

End Class

次に「Settings」タグ直下の「Person」タグを展開するための「CPerson」クラスを定義します。
数値型の「ID」と文字列型の「氏名」を要素に持たせます。

【Person.vb】
Imports System.Xml.Serialization

''' <summary>
''' ルート要素直下の子要素「Person」の内容を定義するクラス
''' </summary>
''' <remarks></remarks>
Public Class CPerson

' IDタグ
<XmlElement("ID")> _
Public ID As Integer

' Nameタグ
<XmlElement("Name")> _
Public Name As String

End Class

最後にテスト用のコードです。
ボタン一つを配置したフォームを用意し、Clickイベントに下記コードを配置します。

【Form1.vb】
Imports System.IO
Imports System.Xml.Serialization

Public Class Form1
Private order As String() = _
{"", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十"}
Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click

' 読み込み対象とするファイルパスを指定
' 以下は、実行ファイルと同じパスにXMLファイルがある前提
Dim path As String = _
System.IO.Path.Combine(Application.StartupPath, "Persons.xml")
Dim serializer As New XmlSerializer(GetType(CSettings))
Dim wkSettings As New CSettings
Try
' XMLファイルのEncodingを取得
Dim xmlDoc As New XmlDocument
xmlDoc.Load(path)
' 最初の子要素<?xml>(宣言部)を取得
' 取得した<?xml>要素(XmlNode型)をXmlDeclarationに
' キャストしてからEncoding属性を取りだす
Dim xmlEnc As System.Text.Encoding = _
System.Text.Encoding.GetEncoding(CType(xmlDoc.FirstChild, XmlDeclaration).Encoding)
' XMLファイルを読み込む
Using stream As FileStream = New FileStream(path, FileMode.Open)
' デシリアライズ処理
' Settingsクラスのオブジェクトに展開
wkSettings = CType(serializer.Deserialize(stream), CSettings)
End Using

' 最終メンバの情報を表示
Dim msg As String = "ID = " + wkSettings.person(wkSettings.person.Length - 1).ID.ToString() + vbNewLine + _
"Name = " + wkSettings.person(wkSettings.person.Length - 1).Name.ToString()
MessageBox.Show(msg, "最終メンバ")

' 最終メンバのIDを変更
wkSettings.person(wkSettings.person.Length - 1).ID = wkSettings.person.Length + 100

' 10人目まではメンバを追加
If wkSettings.person.Length < order.Length - 1 Then
Dim p As New CPerson
p.ID = wkSettings.person.Length + 1
p.Name = "サンプル" + order(p.ID) + "郎"
ReDim Preserve wkSettings.person(wkSettings.person.Length)
wkSettings.person(wkSettings.person.Length - 1) = p
End If

' 変更した内容を元のXMLファイルに上書き保存する
Using xmlWtr As New System.Xml.XmlTextWriter(path, xmlEnc)
' 字下げ(改行付き)で書き出す
xmlWtr.Formatting = Xml.Formatting.Indented ' 字下げ有効
xmlWtr.IndentChar = " "c ' 字下げキャラクタ
xmlWtr.Indentation = 2 ' 字下げ幅

' シリアライズ処理(保存)
serializer.Serialize(xmlWtr, wkSettings)
End Using

Catch ex As Exception
MessageBox.Show(ex.Message, "例外発生")

End Try

End Sub
End Class

ボタンをクリックすると、末尾「Person」の内容を表示してから、そのIDに100を加算し、新たな「Person」を追加して保存します。






CATEGORY:仕事関係 | CM(0) | TB(0) |
xx HOME xx Old Entries≫

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。