2011年4月28日木曜日

Oracle XPathを使用してテキストノードの値を取得する場合の注意点

Pl/SQLでもXpathを使用して簡単にXMLノードの値を取得することが可能だが、以下のような空ノードの値を取得する際は注意が必要。
<document>
<content></content>
</document>
この状態で extract('/document/content/text()').getStringVal()を行うと「ORA-30625: NULL SELF引数のメソッド・ディスパッチは使用できません」のエラーが発生する。

これを回避したい場合は一旦EXISTSNODEでノード内に値があるかを確認し、ある場合に取得するといった対応が必要となる。

以下は、そのための簡単なFUNCTIONの例。

・安全にテキストノードの値を取得するための関数

  FUNCTION GET_TEXT_NODE_VALUE(xmlData XMLTYPE,xpathStr VARCHAR2 ) RETURN VARCHAR2 IS
lvJudge NUMBER(1);
  BEGIN
lvJudge := xmlData.existsNode(xpathStr);
IF lvJudge = 0 THEN --空ノードの場合
RETURN NULL;
ELSE
RETURN xmlData.extract(xpathStr).getStringVal();
END IF;
  END;


・使い方
GET_TEXT_NODE_VALUE(xmlData,'/document/content/text()');


参考リンク
Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス
10g リリース2(10.2) - 198 XMLTYPE

GAE BigTableをJQueryで操作

Google App Engine の BigTable をJQueryで処理できるgaedirectというツールがあるそうだ。

http://www.atmarkit.co.jp/fwcr/rensai2/gaedirect01/01.html

JavaScriptがクライアントサイドのリソースをくってしまう点やMVCの観点から言えば邪道な
気もするが、記事にあるように「すぐに簡単なサイトを・・・」というときにいちいちJavaで開発
するのも確かに面倒だ。

内内で使用する出席管理のツールとか、それこそ災害時の安否連絡などには十分使える
のではないかと思う。

2011年4月27日水曜日

Google デザイン10原則

Googleにおける「ユーザー エクスペリエンス向上のためのデザイン10原則」と要点を転載


1. Focus on people their lives, their work, their dreams. ユーザー(ユーザーの生活、仕事、夢)を大切にする

・言葉では表現できないようなニーズを含め、常にユーザーが実際に必要としていることを発見すべく努力する


2. Every millisecond counts. 1ミリ秒も無駄にしない

・ユーザーにとってスピードは大きなメリット


3. Simplicity is powerful. シンプルが強みになる

・最適な設計は、ユーザーが目的を果たすうえで、必要最低限の機能のみが含まれている設計

・大がかりな機能と複雑なデザインが必要な場合であっても、それをシンプルかつパワフルなサービスにする


4. Engage beginners and attract experts. 初心者もエキスパートも魅了する


・最高の設計とは、見た目は非常にシンプルでありながら、高度な機能を必要とするユーザーがその機能を簡単に手に入れられるような設計


5. Dare to innovate. 大胆に革新する


・ユーザーのニーズを満たすためであれば、失敗を恐れず革新的な設計を採用する


6. Design for the world. 世界仕様の設計を導入する


・ユーザーにとって合理的なメディアや方法で利用できるようにすること


7. Plan for today's and tomorrow's business. 現在と将来のビジネスを見据える


・すべてのサービスで収益を上げる必要はありません

・すべてのユーザーに役立つサービスを提供することが重要


8. Delight the eye without distracting the mind. 見て楽しくても気は散らない


・第一印象が良いサービスは、ユーザーを快適にし、安心感と信頼感を抱かせるだけでなく、サービスを積極的に利用しようとする意欲をかきたてる


9. Be worthy of people's trust. 人々の信頼に応える


・信頼感の土台になるのは、基本的なことの積み重ね

・自分のデータは自分で制御できるというユーザーの権利を尊重すること

・「Don't be evil(悪になるな)」というモットーを体現すること


10. Add a human touch. 人間味を加える

・設計にも個性

・文章やデザインは、親しみやすくユーモアにあふれスマートにする


*** 詳細はリンク参照 ***

ユーザー エクスペリエンス向上のための 10 原則
http://www.google.com/corporate/ux.html

What makes a design "Googley"?
http://googleblog.blogspot.com/2008/04/what-makes-design-googley.html

IE6からIE8への移行 検証ポイント リンク集

セッション共有
http://blogs.wankuma.com/oakbow/archive/2009/09/13/181169.aspx

MS拡張CSS
http://msdn.microsoft.com/ja-jp/ie/dd218499.aspx

IEのバージョンと使用できるCSSプロパティ
http://msdn.microsoft.com/en-us/library/ms531207(VS.85).aspx
http://www.tutorialfeed.org/2009/10/visual-cheat-sheet-css-compatiblity.html
http://msdn.microsoft.com/library/cc351024.aspx
http://msdn.microsoft.com/ja-jp/library/cc351024(v=VS.85).aspx
http://msdn.microsoft.com/ja-jp/library/bb250395

標準モード・互換モード間の違い
http://www.justmystage.com/home/hodogaya/css09.html
http://w3g.jp/others/data/doctype_switching
http://html-coding.co.jp/knowhow/tips/000015/

IE6バグ
http://mb.blog7.fc2.com/blog-entry-83.html
http://webtech-walker.com/archive/2007/05/21215114.html
http://css-bug.jp/win/ie/
http://technet.microsoft.com/ja-jp/library/ff943760(WS.10).aspx
http://www10.plala.or.jp/palm84/css_memo.html

2011年4月26日火曜日

DOSからのレジストリ操作

DOSバッチ間で、レジストリを経由して情報共有するケースのメモ

※ケース説明
ある2本のプログラム(PG-A、PG-B)において、PG-Bが時間起動で稼動した際、
PG-Aが実行中か否かで処理を分岐させるケース

※レジストリ取得
reg queryの戻り値はOSに依存、環境に応じてfor文を要調整

(以下はWinXPpro環境での例)


<PG-A>
rem ***レジストリ初期化***
REG DELETE HKLM\Software\TESTFD /v CHKPG_DATE /f
REG DELETE HKLM\Software\TESTFD /v CHKPG_FLG /f
REG DELETE HKLM\Software\TESTFD /v CHKPG_NAME /f

rem ***レジストリSET*** システム日付,フラグ(=1),PG名
REG ADD HKLM\Software\TESTFD /v CHKPG_DATE /d %date:~-10,4%%date:~-5,2%%date:~-2% /f
REG ADD HKLM\Software\TESTFD /v CHKPG_FLG /d 1 /f
REG ADD HKLM\Software\TESTFD /v CHKPG_NAME /d HOGE0123 /f


(処理記述)


rem ***レジストリ削除***
REG DELETE HKLM\Software\TESTFD /v CHKPG_FLG /f

rem ***レジストリSET*** フラグ(=0)
REG ADD HKLM\Software\TESTFD /v CHKPG_FLG /d 0


<PG-B>
rem ***レジストリ値取得***
FOR /F "TOKENS=1,2,*" %%I IN ('REG QUERY "HKLM\Software\TESTFD" /v "CHKPG_DATE"') DO IF "%%I"=="CHKPG_DATE" SET CHKPGDATE=%%K
FOR /F "TOKENS=1,2,*" %%I IN ('REG QUERY "HKLM\Software\TESTFD" /v "CHKPG_FLG"') DO IF "%%I"=="CHKPG_FLG" SET CHKPGFLG=%%K
FOR /F "TOKENS=1,2,*" %%I IN ('REG QUERY "HKLM\Software\TESTFD" /v "CHKPG_NAME"') DO IF "%%I"=="CHKPG_NAME" SET CHKPGNAME=%%K

rem ***PG-A稼動チェック(システム日付とフラグ(=1)で判定)***
if not %CHKPGDATE%==%date:~-10,4%%date:~-5,2%%date:~-2% goto STEP_OK
if not %CHKPGFLG%==1 goto STEP_OK

rem ***NG***
:STEP_NG
echo 「%CHKPGNAME%」は実行中です


(処理記述)


goto STEP_END

rem ***OK***
:STEP_OK


(処理記述)



rem ***終了***
:STEP_END

2011年4月22日金曜日

ASP.NETでネットワーク BIOS コマンド制限に達しましたが発生する

Visual Studioで開発サーバーを使用していると、唐突に表題のメッセージが出ることがある。
そんなときは以下リンクを参考に対応。

マイクロソフトサポート

設定する値については、以下のようにした。
MaxCmds :64
MaxMpxCt:800

ここの画面写真を参照

ASP.NET Site.Masterに設定するJavaScriptファイルのパスについて

ASP.NETでは、SiteMasterを使用することでレイアウトや読み込むCSS/JavaScriptファイルを共有できる
(各ページで別々に設定しなくていい)。

ただ、このときJavaScriptファイルへのパスの設定には注意が必要。以下のようにしておかないと、
ページの階層によってはリンクのパスが切れてしまう。
※cssファイルの方は、なぜか相対パスが自動的に解釈される。

<script src="<%= ResolveUrl("~/Scripts/jquery.min.js") %>" type="text/javascript"></script>

2011年4月21日木曜日

VB.NETにおけるstatic

VB.NETにおけるstaticとJavaなどの言語におけるstaticは意味が違う!ので備忘的に記載。

参考サイト

・VB.NETにおけるstatic
 メソッドの呼び出し間で値を維持する静的ローカル変数のために使われる。
 (ABAPにおけるSTATICSと同じ・・・といってもぴんと来る人はいないか・・・)。
 →前に呼び出されたときに計算した値を保持しておくことが出来る

 Javaなどの言語におけるstaticと同じ意味を持つのはShared。ただ、Const型には使用できないのでpublic static final のような使い方は出来ない(単純にPublic Constとする)

・Javaなどにおけるstatic
 インスタンスに属さずクラスに属するメンバを宣言するために使用される

Oracle PL/SQL XMLデータをFunctionで受け取る

PL/SQLでXMLデータを受け取り、処理する方法。
ASP.NET側で入力フォームの情報をXML化し、そのXMLをPL/SQLで受け取って更新処理をするという寸法。
・OracleへのアクセスはODP.NETを使用。更新対象のテーブルはOracleのデフォルト環境scott/tigerにあるDEPTテーブルとしている。

ASP.NET側 ※msgLabelに処理結果を出力する想定
'XML型のデータを作成し更新を行う
Dim blr As StringBuilder = New StringBuilder()

'Oracle更新処理
Dim conStr As String = ConfigurationManager.ConnectionStrings("ConnectionString").ToString()
Dim ocon As OracleConnection = New OracleConnection(conStr)
Dim oCommand As OracleCommand = New OracleCommand("XML_UPDATER.XML_UPDATE", ocon)
oCommand.CommandType = CommandType.StoredProcedure

Dim rv As OracleParameter = oCommand.Parameters.Add("rv", OracleDbType.Varchar2)
rv.Direction = ParameterDirection.ReturnValue
rv.Size = 10000 'サイズは適当

Dim p1 As OracleParameter = oCommand.Parameters.Add("p1", OracleDbType.XmlType)
p1.Direction = ParameterDirection.Input

blr.Append("<?xml version=""1.0""?><depts>")
blr.Append("<dept>")
blr.Append("<dept><dname>DNAME_HOGE</DNAME><LOC ADRCODE=""1"">LOC_HOGE</LOC>
</DEPT>")
blr.Append("</DEPT>")
blr.Append("</DEPTS>")
p1.Size = blr.Length
p1.Value = blr.ToString

Try
ocon.Open()
oCommand.ExecuteNonQuery()
If IsDBNull(oCommand.Parameters("rv").Value) Or oCommand.Parameters("rv").Value.ToString = "null" Then
msgLabel.Text = "SUCCESS"
Else
msgLabel.Text = oCommand.Parameters("rv").Value.ToString
End If
Catch ex As Exception
msgLabel.Text = "Oracle:" + oCommand.Parameters("rv").Value.ToString + " ASP:" + ex.Message
Finally
ocon.Close()

End Try



PL/SQL側(パッケージを作成。パッケージヘッドは省略)
CREATE OR REPLACE PACKAGE BODY SCOTT.XML_UPDATER
IS
FUNCTION XML_UPDATE(pvXml XMLTYPE ) RETURN VARCHAR2 IS
xmlDoc dbms_xmldom.DomDocument;
nodeList dbms_xmldom.DomNodeList;
lvList dbms_xmldom.DomNode;
lvRow SCOTT.DEPT%ROWTYPE;
BEGIN
xmlDoc := xmldom.newDomDOcument(pvXml);
nodeList := xmldom.getElementsByTagName(xmlDoc, 'DEPT');

IF NOT xmldom.isNull(nodeList) THEN
FOR i IN 0 .. xmldom.getLength(nodeList) - 1 LOOP
lvList := xmldom.item(nodeList,i);
lvRow.DNAME := GET_ELEMENT_VALUE_BY_TAG_NAME(lvList,'DNAME');

lvRow.LOC := GET_ELEMENT_ATTR_BY_TAG_NAME(lvList,'LOC','ADRCODE');
lvRow.LOC := GET_ELEMENT_VALUE_BY_TAG_NAME(lvList,'LOC') || '-' || lvRow.LOC;

lvRow.DEPTNO := GET_ELEMENT_VALUE_BY_TAG_NAME(lvList,'DEPTNO');
IF lvRow.DEPTNO IS NULL OR lvRow.DEPTNO = '' THEN
SELECT MAX(DEPTNO) INTO lvRow.DEPTNO FROM SCOTT.DEPT;
lvRow.DEPTNO := lvRow.DEPTNO + 1;
INSERT INTO SCOTT.DEPT VALUES lvRow;
ELSE
UPDATE SCOTT.DEPT SET ROW = lvRow WHERE DEPTNO = lvRow.DEPTNO;
END IF;
END LOOP;
END IF;

COMMIT;
RETURN NULL;

EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RETURN SQLERRM;
END ;

--テキストノードの値を取得
FUNCTION GET_ELEMENT_VALUE_BY_TAG_NAME(domEl dbms_xmldom.DomElement,tagName VARCHAR2) RETURN VARCHAR2 IS
tempList dbms_xmldom.DomNodeList;
oneItem dbms_xmldom.DomNode;
BEGIN
tempList := xmldom.getElementsByTagName(domEl,tagName);
oneItem := xmldom.item(tempList,0); --要素内に、タグ名に合致するノードは1つしかないと想定
RETURN xmldom.getNodeValue(xmldom.getFirstChild(oneItem));
END ;

FUNCTION GET_ELEMENT_VALUE_BY_TAG_NAME(domNd dbms_xmldom.DomNode,tagName VARCHAR2) RETURN VARCHAR2 IS
BEGIN
RETURN GET_ELEMENT_VALUE_BY_TAG_NAME(xmldom.makeElement(domNd),tagName);
END ;

--ノードの属性値を取得
FUNCTION GET_ELEMENT_ATTR_BY_TAG_NAME(domEl dbms_xmldom.DomElement,tagName VARCHAR2,attrName VARCHAR2) RETURN VARCHAR2 IS
tempList dbms_xmldom.DomNodeList;
oneItem dbms_xmldom.DomElement;
BEGIN
tempList := xmldom.getElementsByTagName(domEl,tagName);
oneItem := xmldom.makeElement(xmldom.item(tempList,0));
RETURN xmldom.getAttribute(oneItem,attrName);
END;

FUNCTION GET_ELEMENT_ATTR_BY_TAG_NAME(domNd dbms_xmldom.DomNode,tagName VARCHAR2,attrName VARCHAR2) RETURN VARCHAR2 IS

BEGIN
RETURN GET_ELEMENT_ATTR_BY_TAG_NAME(xmldom.makeElement(domNd),tagName,attrName);
END;

END XML_UPDATER;
/

2011年4月18日月曜日

Oracleクライアントインストールディレクトリ

いつからか、クライアントのインストール先が変わっている模様

(少なくとも)8まで
C:\oracle\

(少なくとも)11g以降
C:\app\(ユーザー名)\product
→ODP.NETを入れている場合、有用なサンプルコードが以下フォルダにあるので要チェック
 C:\app\\(ユーザー名)\product\11.2.0\client_3\odp.net\samples

Oracleでテーブルの列定義を取得する

以下SQLで可能。

select * from USER_TAB_COLUMNS

ORDER BY COLUMN_ID をつけると、実際の定義順でデータを取得できる。
ALL_TAB_COLUMNS だとそれ以外のテーブル定義も取れる模様。

2011年4月15日金曜日

ASP.NETからの、ODPを使用したOracleFunctionの呼出

ODPを使用する場合の一番のネックになるのは、最初に設定するパラメータは返り値でないといけないということ。
これをミスるとパラメータの長さが違いますみたいなエラーが延々と出てドハマリする

参考リンク

Oracle側
CREATE OR REPLACE FUNCTION SaveData(en varchar2) RETURN VARCHAR2 IS
hoge varchar2(100);
Begin
hoge := en || ' is inputed ';
Insert into TestSaveData values(hoge);
Return hoge;
End;


ASP.NET側
Try
Dim cnn As New Oracle.DataAccess.Client.OracleConnection("Data Source=OracleG;User Id=Scott;password=Tiger")
Dim cmd As New Oracle.DataAccess.Client.OracleCommand("SAVEDATA", cnn)
cmd.CommandType = CommandType.StoredProcedure

cmd.Parameters.Add("RS", Oracle.DataAccess.Client.OracleDbType.Varchar2, ParameterDirection.ReturnValue)
cmd.Parameters.Add("EN", Oracle.DataAccess.Client.OracleDbType.Varchar2, 100, "INPUT", ParameterDirection.Input)

cnn.Open()
Dim ooo As Object = cmd.ExecuteScalar()
Dim q As Object = cmd.Parameters("RS").OracleDbType.ToString()
Dim s As String = q
cnn.Close()
Catch ex As Oracle.DataAccess.Client.OracleException
MsgBox(ex.Message())
End Try