|
事業仕分けによる次世代スーパーコンピューターの開発予算削減について、どうお考えですか?
|
XMLとXSLを使った高度なUIデザイン:パート1はじめにこの連載では、XMLとXSLを使った高度なUIデザインに挑戦します。1回に1つずつ、XMLとXSL(XML用のスタイルシート言語)を使用して高度なユーザーインタフェース(UI)コンポーネントを作成していきます。 今回は第1回として、XMLとXSLで深さ無制限のフォルダツリーを作成してみましょう。以下で説明するフォルダツリーは、XMLフィードとして与えられるフォーマットにXSLスタイルシートを適用し、その適用結果をクライアントに書き出すことで作成されます。ツリー自体とそこに含まれる諸エンティティの展開と折り畳み・最大化と最小化の要求は、すべてクライアント側で処理されます。本稿で使用するクライアントはInternet Explorer 5.5以降です。 作成したフォルダツリーのデモをサンプルとして用意しています。ダウンロードして、実行してみてください。このダウンロードサンプルには、フォルダツリーを構成する諸ファイル(「tree.xsl」「tree.xml」「tree.js」「tree.css」「common.js」および画像ファイル)が含まれています。 フォルダツリーに固有のアーキテクチャWebページオブジェクトには、いく通りもの作成方法があるのが普通で、フォルダツリーも同様です。フォルダツリーの開発では、フォルダツリー独特のアーキテクチャ条件に留意してください。たとえば、次のような条件です。
ネスティング図1 ブラウザ内でネスティングなし ![]() 図2 ブラウザ内でネスティングあり ![]() 図1と図2では、DOM(ドキュメントオブジェクトモデル)内にある各オブジェクトの相互関係とネスティング状態をわかりやすくするために、フォルダツリーに一時的に境界線を描いています。 関係線ツリー内部に関係線を引けば、見映えがよくなるだけでなく、大きなツリーの構造が把握しやすくなります。反面、パフォーマンスが低下するというマイナスもあります。100個の項目を含むツリーでは、エンティティ間の関係を表示するだけで約300個の画像が必要になります。画像のキャッシュ保存やプリロードを行うことで多少はパフォーマンス低下を防ぐことができますが、それでも、画像がDOM内に独立のオブジェクトとして存在することは変わりません。関係線なしのインデントだけでも親子関係を示すには十分ですから、本稿では、関係線のないツリーでいくことにします。 XML構造ツリーに何を求めるかは、それこそ千差万別です。私がツリーに望むこととあなたが望むことの間には、きっと大きな違いがあるでしょう。ツリーエンティティは、ツリーごとに特異です。そうした特異なツリーエンティティを記述するのに、XMLは最適なインタフェースを備えています。どのフォーマットを選ぶかで、XSLスタイルシートとクライアント動作が大きく変わります。私が選んだのは、再帰的XSLスタイルシートに適したフォーマットです。これは、本稿で取り上げている深さ無限のフォルダツリーという条件をよく満たしています。 私が作成したXMLドキュメントには、
実際のツリーでは、ツリー内部の各オブジェクトに関する具体的データを、エンティティ要素によって付加していきます。具体的データとは、たとえば、そのエンティティによって表されるデータベースレコードのIDかもしれません。次回以降では、各エンティティ固有のコンテキストを作成し、それを 本稿で使用するXMLは次のとおりです。ここでは、わかりやすいように静的XMLドキュメントとして作成していますが、動的XMLデータベースクエリとして実装することもできます。 <?xml version="1.0"?> <tree> <entity id="e1"> <description>Customers</description> <oncontextmenu></oncontextmenu> <image>images/book.gif</image> <imageOpen>images/bookOpen.gif</imageOpen> <contents> <entity id="e2"> <description>Microsoft</description> <image>images/book.gif</image> <imageOpen>images/bookOpen.gif</imageOpen> <onClick>displayCustomer(12345)</onClick> <contents> <entity id="e3"> <description>Orders</description> <image>images/book.gif</image> <imageOpen>images/bookOpen.gif</imageOpen> <onClick></onClick> <contents/> </entity> </contents> </entity> <entity id="e4"> <description>IBM</description> <image>images/book.gif</image> <imageOpen>images/bookOpen.gif</imageOpen> <onClick>displayCustomer(12346)</onClick> <contents> <entity id="e5"> <description>Orders</description> <image>images/book.gif</image> <imageOpen>images/bookOpen.gif</imageOpen> <onClick></onClick> <contents/> </entity> </contents> </entity> <entity id="e6"> <description>Sun Microsystems</description> <image>images/book.gif</image> <imageOpen>images/bookOpen.gif</imageOpen> <onClick>displayCustomer(12347)</onClick> <contents> <entity id="e7"> <description>Orders</description> <image>images/book.gif</image> <imageOpen>images/bookOpen.gif</imageOpen> <onClick></onClick> <contents> <entity id="e8"> <description>#12345</description> <image>images/paper.gif</image> <imageOpen>images/paper.gif</imageOpen> <onClick></onClick> <contents/> </entity> <entity id="e9"> <description>#12346</description> <image>images/paper.gif</image> <imageOpen>images/paper.gif</imageOpen> <onClick></onClick> <contents/> </entity> </contents> </entity> </contents> </entity> <entity id="e10"> <description>Oracle</description> <image>images/book.gif</image> <imageOpen>images/bookOpen.gif</imageOpen> <onClick>displayCustomer(12348)</onClick> <contents> <entity id="e11"> <description>Orders</description> <image>images/book.gif</image> <imageOpen>images/bookOpen.gif</imageOpen> <onClick></onClick> <contents/> </entity> </contents> </entity> </contents> </entity> <entity id="e12"> <description>Reports</description> <oncontextmenu></oncontextmenu> <image>images/book.gif</image> <imageOpen>images/bookOpen.gif</imageOpen> <contents> <entity id="e13"> <description>Income</description> <oncontextmenu></oncontextmenu> <image>images/paper.gif</image> <imageOpen>images/paper.gif</imageOpen> <contents> </contents> </entity> <entity id="e14"> <description>Expenses</description> <oncontextmenu></oncontextmenu> <image>images/paper.gif</image> <imageOpen>images/paper.gif</imageOpen> <contents> </contents> </entity> </contents> </entity> </tree> このXMLファイルの名前は「tree.xml」です。このファイルはダウンロードサンプルに含まれています。 XSLスタイルシート図1と図2は、どちらも、XMLドキュメントにXSLスタイルシートを適用して得られた結果でした。XMLドキュメントに適用される標準のXSLスタイルシートは次のとおりです。 <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl" language="JavaScript"> <xsl:template match="tree"> <xsl:apply-templates select="entity"/> </xsl:template> <xsl:template match="entity"> <div onclick="window.event.cancelBubble = true;clickOnEntity(this);" onselectstart="return false" ondragstart="return false"> <xsl:attribute name="image"><xsl:value-of select="image"/> </xsl:attribute> <xsl:attribute name="imageOpen"><xsl:value-of select="imageOpen"/> </xsl:attribute> <xsl:attribute name="open">false</xsl:attribute> <xsl:attribute name="id">f<xsl:value-of select="@id"/> </xsl:attribute> <xsl:attribute name="open">false</xsl:attribute> <xsl:attribute name="STYLE"> padding-left: 20px; cursor: hand; <xsl:if expr="depth(this) > 2"> display: none; </xsl:if> </xsl:attribute> <table border="0" cellspacing="0" cellpadding="0"> <tr> <td valign="middle"> <img border="0" id="image"> <xsl:attribute name="SRC"> <xsl:value-of select="image"/> </xsl:attribute> </img> </td> <td valign="middle" nowrap="true"> <xsl:attribute name="STYLE"> padding-left: 7px; font-family: Verdana; font-size: 11px; font-color: black; </xsl:attribute> <xsl:value-of select="description"/></td> </tr> </table> <xsl:apply-templates select="contents/entity"/> </div> </xsl:template> </xsl:stylesheet> このXSLスタイルシートを使って作成したフォルダツリーを図3に示します。 クライアント側操作このフォルダツリーをそれらしく動作させるには、クライアント側で次の操作が必要です。
この5つの操作を実行するコードを次に示しておきます。このコードは、ダウンロードサンプルの「tree.js」ファイルに含まれています。 function initialize() { var xmlDoc var xslDoc xmlDoc = new ActiveXObject(’Microsoft.XMLDOM’) xmlDoc.async = false; xslDoc = new ActiveXObject(’Microsoft.XMLDOM’) xslDoc.async = false; xmlDoc.load("tree/tree.xml") xslDoc.load("tree/tree.xsl") folderTree.innerHTML = xmlDoc.documentElement.transformNode(xslDoc) } function clickOnEntity(entity) { if(entity.open == "false") { expand(entity, true) } else { collapse(entity) } window.event.cancelBubble = true } function expand(entity) { var oImage oImage = entity.childNodes(0).all["image"] oImage.src = entity.imageOpen for(i=0; i < entity.childNodes.length; i++) { if(entity.childNodes(i).tagName == "DIV") { entity.childNodes(i).style.display = "block" } } entity.open = "true" } function collapse(entity) { var oImage var i oImage = entity.childNodes(0).all["image"] oImage.src = entity.image // collapse and hide children for(i=0; i < entity.childNodes.length; i++) { if(entity.childNodes(i).tagName == "DIV") { if(entity.id != "folderTree") Webベースのフォルダツリーの今後の展開Web技術の進歩にともない、Webアプリケーション内部にステート情報を維持できるようになって、しだいに多くの機能がサーバ側からクライアント側に移され、インタフェースは複雑になる一方です。しかし、その結果、サーバの負担が軽くなり、インタフェースの使い勝手とアプリケーションのパフォーマンスが向上するわけですから、喜ぶべきことでもあります。 いずれ、本稿で作成したツリーをさらに発展させ、ツリー内部にあるオブジェクトの挿入・削除・改名・再表示を動的に行うAPIを作成して、紹介したいと考えています。 終わりに本稿の内容が、Webアプリケーションインタフェースの質的向上に役立てば幸いです。質問・コメント・提案があれば、筆者紹介にあるアドレスまで遠慮なくメールをお送りください。 この原稿に目を通し、表現と内容の両方をチェックしてくれたLee McGrawに感謝します。 次回は、カスタムコンテキストメニューの作成を取り上げます。 本連載のその他の記事著者紹介Joe Slovinski(Joe Slovinski)
1993年以来、Webアプリケーションの開発に継続的に携わる。本稿で紹介したコードについてのお問い合わせはJoe Slovinskiまで。
![]()
|
japan.internet.com 10周年記念
インターネットコムマーケティングセミナー ROI を最適化するパフォーマンスマーケティングの最前線 【12/16(水)13時〜 東京・赤坂】 申込はコチラ>>
|