IBM®
本文へジャンプ
    Japan [変更]    ご利用条件
 
 
検索範囲検索:    
    ホーム    製品    サービス & ソリューション    サポート & ダウンロード    マイアカウント    
skip to main content

developerWorks Japan  >  XML | Information Management  >

病院における XForms と Ruby on Rails: 第 4 回 医師用の XForms と患者検索用の XForms を実装する

developerWorks
ページオプション

JavaScript を要するドキュメントオプションは表示されません

サンプルコード

原文はこちら

原文はこちら


レベル: 中級

Tyler Anderson (tyleranderson5@yahoo.com), Freelance writer

2008年 6月 10日

この記事は、XForms と IBM® DB2® pureXML™、そして Ruby を一緒に使うことで容易に Web アプリケーションを作成する 4 回シリーズの第 4 回です。このシリーズでは、病院で患者の情報を管理するための、仮定のアプリケーションを作成し、XForms、DB2 pureXML、そして Ruby on Rails それぞれの技術が個々に持つ強みの一端を知ると共に、これらの技術を併せて使用する方法も学びます。シリーズ第 4 回の今回は病院用の XForms の作成を続け、苗字によって患者を検索する、まったく新しいフォームを作成します。

はじめに

このシリーズの前回の記事までに、患者や看護師が患者データを扱う上での補助となる DB2 データベースと 3 つの XForms を作成しました。また、患者が新しい患者レコードをデータベースに追加することができ、追加した後で患者が自分の情報に戻って更新できる処理インターフェースとして、Ruby on Rails を使用しました。その結果、看護師は患者が医師の診察を受けるための準備として、そうした患者の情報を開いて、適切な編集を行い、入力された情報を承認することができるようになりました。

このシリーズの他の記事

シリーズ最終回であるこの第 4 回では、医師用の新しいビューとコントローラーを作成し、このビューのための新しい XForms も 2 つ作成します。最初のフォームでは、医師は患者が入力して看護師が承認したものと同じ患者レコードを見ることができるのに加え、その患者を診察したことによる追加情報を入力することができます。次に、医師と看護師が苗字で患者情報を検索できるフォームを作成します。




上に戻る


前提条件

この記事では XML と Web アプリケーションに関して全般的に慣れていることを前提としています。これまでに 3 つのコア技術 (XForms とDB2 pureXML、そして Ruby on Rails) を経験したことがあれば役立ちますが、決してそれが必須なわけではありません。この記事を執筆するにあたり、Mozilla XForms プラグインのバージョン 0.8.0.3 を使用しました。このプラグインによって、Firefox を始めとするすべての Mozilla ブラウザーで XForms ランタイムをサポートすることができます。もう 1 つ、Mozilla 用の非常に便利なプラグインが XForms 用のデバッガーである XForms Buddy です。この記事では XForms Buddy のバージョン 0.5.6 を使用しました。また IBM の DB2 データベース・サーバーも必要です。この記事では Windows® システムと Linux® システム、そして UNIX® システムで使用できる DB2 Express-C バージョン 9.5 を使用しています。最後に、Ruby on Rails が必要です。この記事では Ruby 1.8.6 と Rails 1.2.5 を使用しています。また Rails と合わせて Mongrel Web サーバーも使っています。Mongrel は Ruby Gems から入手することができます (コマンドラインから gem install mongrel と入力すればよいだけです)。ダウンロード用のリンクは「参考文献」を参照してください。




上に戻る


医師の診察のための XForms

頻繁に使用する頭字語
  • XML: Extensible Markup Language

医師用の XForms (doctorPatient.xhtml) の目的は、患者がキオスクで入力し、また看護師が承認したものとまったく同じ情報を医師が見られるようにすることです。医師用の XForms ではさらに、その患者を診察したことによる追加の情報を、その医師が入力できる必要があります。こうしたことを念頭に置くと、doctorPatient フォームは triagePatient フォームと似ていますが、いくつかの違いがあります (リスト 1)。このファイルに doctorPatient.xhtml という名前を付け、このファイルを公開フォルダーに保存します。


リスト 1. doctorPatient フォーム
                
...
      <xf:instance xmlns="" id="patient" >
        <p:Info>
          <FirstName></FirstName>
          <MiddleName></MiddleName>
          <LastName></LastName>
          <Age></Age>
          <Insurer></Insurer>
          <Id></Id>
          <PolicyHolder></PolicyHolder>
          <Copay></Copay>
          <Symptoms></Symptoms>
          <BPressure></BPressure>
          <Notes></Notes>
        </p:Info>
      </xf:instance>

      <xf:submission action="http://localhost:3000/doctor/update/0"
                     method="post"
                     id="submit-info"/>

      <xf:submission id="load_data"
                     action="http://localhost:3000/doctor/grab/0"
                     method="post"
                     replace="instance"
                     />
      
      <xf:action ev:event="xforms-ready">
        <xf:dispatch name="xforms-submit" target="load_data"/>
      </xf:action>   
...
          <xf:label>Please describe your symptoms:<br/></xf:label>
        </xf:textarea>    
      </div>  
      <div id="bloodpressure">
        <xf:input ref="BPressure">
          <xf:label>Blood Pressure: </xf:label>
        </xf:input>
      </div>
      <div id="notes">
        <xf:textarea ref="Notes">
          <xf:label>Notes regarding<br/>visit 
		  with patient:<br/></xf:label>
        </xf:textarea>    
      </div>  
      <div id="submit">
        <xf:submit submission="submit-info">
          <xf:label>Submit Information</xf:label>
        </xf:submit>
      </div>
    </p>

    <a href="doctor/list">Back to List</a>
  </body>
</html>

まず、インスタンス・データの中に、BPressure と Notes という 2 つの要素が追加されていることに注目してください。この 2 つのフィールドには、それぞれ医師が測定した患者の血圧と、医師がテキスト・フィールドに入力できるコメントが含まれています。ここでは submit-info という submission 要素の action 属性と load_data という submission 要素の action 属性は doctor コントローラーを指しています。最後に、この XForms の body の中で 2 つの新しい XForms 要素が宣言されていることがわかります。

次に、doctor のビューとコントローラーに対する scaffold を生成します。




上に戻る


doctor のビューとコントローラー

Rails の scaffold は Ruby アプリケーションを開発する際の素晴らしい出発点となります。まず、doctor のビューとコントローラー用に scaffold を生成します (リスト 2)。


リスト 2. doctor のビューとコントローラー用に scaffold を生成する
                
ruby script/generate scaffold patient doctor
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/doctor
      exists  app/views/layouts/
      exists  test/functional/
  dependency  model
      exists    app/models/
      exists    test/unit/
      exists    test/fixtures/
        skip    app/models/patient.rb
   identical    test/unit/patient_test.rb
   identical    test/fixtures/patients.yml
      create  app/views/doctor/_form.rhtml
      create  app/views/doctor/list.rhtml
      create  app/views/doctor/show.rhtml
      create  app/views/doctor/new.rhtml
      create  app/views/doctor/edit.rhtml
      create  app/controllers/doctor_controller.rb
      create  test/functional/doctor_controller_test.rb
      create  app/helpers/doctor_helper.rb
      create  app/views/layouts/doctor.rhtml
   identical  public/stylesheets/scaffold.css

多くのものが既に作成されており、まだ存在していないファイルのみが Rails によって作成されることに注意してください。次に、doctor コントローラーの中で grab メソッドと update メソッドを定義します (リスト 3)。


リスト 3. doctor コントローラーの中で grab メソッドと update メソッドを定義する
                
  def grab
    id = @request.env["HTTP_REFERER"].split('=')[1]
    @patient = Patient.find(id)
    doc = REXML::Document.new(@patient.information)
    if doc.root.elements["Notes"] == nil then
      el = REXML::Element.new("Notes")
      doc.root.add el
    end
    if doc.root.elements["BPressure"] == nil then
      el = REXML::Element.new("BPressure")
      doc.root.add el
    end
    @patient.information = doc
  end

  def update
    doc = REXML::Document.new("<Info></Info>")
    params[:Info].each_pair do |key,value|
      if (key.index(':') == nil) #removes 
        el = REXML::Element.new key
        el.add_text value
        doc.root.add el
      else
        doc.root.add_attribute key,value
      end
    end

    id = @request.env["HTTP_REFERER"].split('=')[1]
    @patient = Patient.find(id)
    @patient.information = doc
    @patient.update_attributes(params[:patient])
    redirect_to :action => 'list'
  end

最初に気付くことは、grab メソッドは他の 2 つのコントローラー (kiosk と triage) と大きく異なることです。これは、2 つの新しい要素 (BPressure と Notes) が、新たに作成され承認された (データベースの中の) レコードには、まだ存在していないためです。従ってレコードが要求されると、この 2 つの新しい XML 要素がそれぞれ検索され、もしその要素が存在していない場合には、その要素を XML に追加してから grab ビューをとおして XForms に送り返す必要があります。BPressure 要素と Notes 要素が共にその XML 文書の中に存在することが確認されると、患者情報 (patient.information) フィールドは doc 変数の中に含まれる新しい XML として設定されます。

update メソッドに移る前に、grab.rhtml を triage ビュー (app/views/triage/grab.rhtml) から doctor ビュー (app/views/doctor) にコピーします。これで grab ビューは完成です。

この場合の update メソッドには何も新しい機能はありませんが、新しい XML データを DB2 に保管するためにはこのメソッドが絶対に必要です。

では次に進み、医師用の list ビューを変更します。




上に戻る


医師用の list ビュー

医師はこのビューによって、看護師が既に情報を承認したすべての患者の苗字 (Last Name) と名前 (First Name) を見ることができます。この list ビュー (app/views/doctors/list.rhtml) をリスト 4 のように変更します。


リスト 4. 医師用の list ビューを変更する
                
<h1>Listing patients</h1>

<table>
  <tr>
    <th><%= "First Name" %></th>
    <th><%= "Last Name" %></th>
  </tr>
  
<% for patient in @patients %>
<%   if patient.approved=="true" then %>
  <tr>
    <td><% doc = REXML::Document.new(patient.information) %>
      <%= doc.root.elements["FirstName"] %>
    </td>
    <td>
      <%= doc.root.elements["LastName"] %>
    </td>
    <td><%= "<a href=\"../doctorPatient.xhtml?id=" +
             patient[:id].to_s + "\">View/Add Notes</a>" %></td>
    <td><%= link_to 'Delete', { :action => 'destroy', :id => patient },
                                 :confirm => 'Are you sure?',
                                 :method => :post %></td>
  </tr>
<%   end %>
<% end %>
</table>
...

ここでは医師が見るための First name と Last name を出力しています。またリスト 4 で、doctorPatient フォームを指す View/Add Notes リンクに注目してください。ユーザーがこのリンクをクリックすると、これまでのフォームでは入力できなかった情報 (血圧とコメント) を医師が入力できる XForms が開きます (図 1)。


図 1. 医師用の XForms の表示

医師は患者の苗字と名前を見ることができ、また View/Add Notes リンクをクリックすると、その患者が XForms の中に表示されます (図 2)。


図 2. doctorPatient XForms の実際

このフォームでは、医師が Please describe your symptoms (症状を記入してください) というテキスト・ボックスに記述を追加したり、患者の血圧を入力したり、Notes regarding visit with patient (患者の診察に関するコメント) というボックスにこの診察に関する任意のコメントを入力したりすることができます。この情報を送信すると、ユーザーには図 1 の Web ページが返されます。

これで医師用のフォームは完成です。では次に、患者を検索するためのフォームを作成しましょう。




上に戻る


患者検索用のフォーム

さて、スクロールが必要なほど沢山の患者がいるとしたらどうでしょう。そうした場合には、多忙な病院での患者情報の検索作業が時間のかかるものになってしまいます。これから作成する、医師と看護師が患者を苗字で検索できるフォームによって、手動で検索していた検索時間を短縮することができます。この新しいフォームには、すべての患者情報を 1 つの XML 文書の中に配置し、その XML 文書を XForms に返す、新しい graball ビューが必要です。最初にこの新しいビューを作成し、その次に、新しい XForms そのものを作成します。




上に戻る


graball コントロールを作成する

graball コントロールはその名前のとおり、データベースの中にあるすべての患者を 1 つの XML ファイルに入れて返す新しいビューです。doctor ビューのディレクトリー (app/views/doctor/graball.rhtml) に新しいファイルを作成し、それをリスト 5 のように定義します。


リスト 5. graball ビューを作成する
                
<% @headers["Content-Type"] = "text/xml; charset=utf-8" %><%= 
"<Patients xmlns:xf=\"http://www.w3.org/2002/xforms\"
           xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" 
           xmlns:p=\"http://developerworks.ibm.com/patient\" 
           xmlns:ev=\"http://www.w3.org/2001/xml-events\">" %>
<% for pat in @patient %>
<%=  "<Info DbId=\"" + pat.id.to_s +
     "\" ViewEditLinkDoc=\"\" ViewEditLinkTri=\"\">" %>
<%   doc = REXML::Document.new(pat.information) %>
<%=  doc.root.elements["LastName"].to_s %>
<%=  "</Info>" %>
<% end %>
<%= "</Patients>" %>

このビューは grab ビューと同様、まず Content-Type ヘッダーを「text/xml」に設定します。こうすることで Mongrel と Firefox はこのビューの処理方法を認識することができます。次に Patients という開始タグがあり、名前空間が設定されています。興味深い部分が for ループです。このループではデータベースの中にある各患者データに対してループにより独自の <Info>...</Info> タグ・セットが XML 文書の中で与えられます。そして Info タグは次の 3 つの属性を持ちます。

  • DbId —その患者に対応する、データベースの中の ID
  • ViewEditLinkDoc —これは doctorPatient フォームの中に患者の情報を表示するためのリンクを含むローカル変数です。
  • ViewEditLinkTri —ViewEditLinkDoc と同様、これもローカル変数ですが、こちらは患者の情報を triagePatient フォームに表示します。

Info タグの開始タグを並べた後、患者の XML レコードからその患者の苗字 (LastName) を取得します。これは list ビューで苗字 (LastName) を取得する場合とまったく同じです (リスト 4)。</Info> 終了タグによって、その患者の情報を XML の中に入れる作業が完了します。他に患者がいなくなると、for ループの実行が終了し、</Patients> 終了タグが書き込まれて XML が完成します。

doctor コントローラーには、これに対応する graball メソッドがないことに注意してください。これをリスト 6 のように定義します。


リスト 6. doctor コントローラーの graball メソッド
                
  def graball
    @patient = Patient.find_by_sql("select * from patients");
  end

ID のような固有識別子によって患者を発見する代わりに、SQL 文によって、すべての患者を返すように要求します。この方法で、リスト 5 で定義した graball ビューの中にデータベースの中のすべての患者を入れます。

次に、患者検索用のフォームそのもののコードを作成します。




上に戻る


患者検索用の XForms

いよいよ、このシリーズで最後の XForms にやって来ました。この便利なフォームを利用すると、医師や看護師が患者を苗字 (Last Name) で容易に見つけることができます。新しい XForms (lookupPatient.xhtml) を作成して公開ディレクトリーに保存し、それをリスト 7 のように定義します。


リスト 7. lookupPatient フォームを作成する
                
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      xmlns:xf="http://www.w3.org/2002/xforms"
      xmlns:ev="http://www.w3.org/2001/xml-events">
  <head>
    <meta http-equiv="Content-Type"
          content="text/html; charset=ISO-8859-1" />
    <title>Patient Lookup</title>
    <xf:model id="patientModel">

      <xf:instance xmlns="" id="searchLastName">
        <search>
          <LastName/>
        </search>
      </xf:instance>

      <xf:instance xmlns="" id="patients">
        <Patients>
<!--
          <Info DbId="" ViewEditLinkDoc="" ViewEditLinkTri="">
            <LastName/>
          </Info>
          ...
-->
        </Patients>
      </xf:instance>

      <xf:submission id="load_data"
                     action="http://localhost:3000/doctor/graball/0"
                     method="post"
                     replace="instance"
                     instance="patients"/>
      
      <xf:action ev:event="xforms-ready">
        <xf:dispatch name="xforms-submit" target="load_data"/>
      </xf:action>

    </xf:model>
  </head>
  <body>
    <p>
      <div id="searchLastName">
        <xf:input ref="instance('searchLastName')//LastName"
                  incremental="true">
          <xf:label>Search Last Name:</xf:label>
        </xf:input>
      </div>
      <table>
        <th>
          <td width="200px">Last Name</td>
          <td width="100px">View/Edit Doctor</td>
          <td width="100px">View/Edit Triage</td>
        </th>
      </table>

      <xf:repeat id="patientRepeat"
                 nodeset="instance('patients')//Info
                          [LastName=instance('searchLastName')//LastName]">
        <table>
          <tr>
            <td width="200px">
              <div id="LastName">
                <xf:output ref="LastName"/>
              </div>
            </td>
            <td width="100px">
              <div id="viewDoctor">
                <xf:trigger>
                  <xf:label>View/Edit Doc</xf:label>
                  <xf:action ev:event="DOMActivate">
                    <xf:setvalue ref="@ViewEditLinkDoc"
                        value="concat('doctorPatient.xhtml?id=',../@DbId)"/>
                    <xf:load ref="@ViewEditLinkDoc" show="new"/>
                  </xf:action>
                </xf:trigger>
              </div>
            </td>
            <td width="100px">
              <div id="viewTriage">
                <xf:trigger>
                  <xf:label>View/Edit Tri</xf:label>
                  <xf:action ev:event="DOMActivate">
                    <xf:setvalue ref="@ViewEditLinkTri"
                        value="concat('triagePatient.xhtml?id=',../@DbId)"/>
                    <xf:load ref="@ViewEditLinkTri" show="new"/>
                  </xf:action>
                </xf:trigger>
              </div>
            </td>
          </tr>
        </table>
      </xf:repeat>
    </p>

    <a href="doctor/list">Back to Doctor</a><br/>
    <a href="triage/list">Back to Triage</a>
  </body>
</html>

このフォームには、今までこのシリーズに登場したことのない要素がいくつかあります。さらにこのフォームには、別々に管理が必要な 2 つのインスタンス文書があります。searchLastName という ID を持つ最初のインスタンス文書は検索される患者の苗字 (LastName) を含んでいます。patients という ID のインスタンス文書は、load_data という submission 要素によってロードされる XML を含んでいます (この XML は XForms がロードされる際に doctor の graball ビューを呼び出すことによってロードされます)。いったんインスタンス・データがロードされると、患者の XML インスタンス・データの中にある苗字 (LastName) の 1 つに一致する苗字 (Last Name) を入力しない限り、XForms には何も特別なデータが表示されません (図 3)。


図 3. lookupPatient フォーム
The lookupPatient form

リスト 7 の XForms の body の中を見ると、医師と看護師が苗字 (Last Name) を入力して一致検索を行うためのテキスト・ボックスがあります。次に見出し行が設定されていることがわかります。一致した苗字 (Last Name) 用の見出しが 1 つ、そして見つかった各患者の情報を医師または看護師が別々のフォーム (doctorPatient と triagePatient) で開くためのボタン用の見出しが 2 つです。結果が見つかると、そこに repeat 要素が登場します。repeat 要素の nodeset 属性の中の XPath 式は、repeat 文の中でどちらの Info 要素を表示するかを定義します。XML による patients インスタンス・データの中にある苗字 (LastName) とテキスト・ボックスに入力された苗字 (Last Name) が一致する場合には、この XPath によって一致が見つかります。この XPath は、苗字 (LastName) を最初の列に、doctorPatient フォームに患者情報を表示するボタンを 2 番目の列に、そして triagePatient フォームに患者情報を表示するボタンを 3 番目の列に表示します (図 4)。


図 4. lookupPatient フォームの実際

するとこのように、一致した患者データがテーブルの行として表示されます。この、Ajax のような即時処理は「Search Last Name (苗字を検索)」テキスト・ボックスの incremental="true" 属性によって実現されています (リスト 7)。患者データを doctorPatient フォームまたは triagePatient フォームの中に表示するためには、図 4 の中にある 2 つのボタンのいずれかをクリックすればよいだけです。

非常に便利だと思いませんか。これで、Ruby と DB2 pureXML を使って XForms を作成するシリーズが完結しました。




上に戻る


まとめ

何という素晴らしい成果でしょう。この 4 回シリーズの記事の最終回でアプリケーションを完成するに当たり、医師用の XForms を作成し、そして何千件も潜在している可能性がある患者レコードの中から検索するという気の遠くなるような作業を容易にする、患者検索用の最終的な XForms を作成できたのです。

XForms と Ruby on Rails、そして DB2 pureXML の 3 つの技術をマスターしたことによって、これらを組み合わせることの強力さを理解できたはずです。まだ皆さんはこれらの技術を完全にマスターできていないかもしれませんが、その場合は「参考文献」が役立ちます。この 3 つの技術それぞれの知識やスキルを向上させるために役立つ数々の素晴らしいリンクを参考にしてください。では、幸運をお祈りします。





上に戻る


ダウンロード

内容ファイル名サイズダウンロード形式
Part 4 sample codepart4_doctorsOffice.zip15KBHTTP
ダウンロード形式について


参考文献

学ぶために

製品や技術を入手するために
  • Mozilla や Firefox、あるいは Seamonkey 用の XForms 拡張機能を入手してください。

  • XForms Buddy は Mozilla/Firefox の拡張機能であり、XForms のインスタンス・データを表示することができます。またインスタンス・データが変更されると自動的に更新を行います。

  • IBM から DB2 Express-C version 9.5 を入手してください。

  • Ruby 1.8.6 with Rails 1.2.5 を入手してください。

  • 皆さんの次期開発プロジェクトを IBM trial software で構築してください。developerWorks から直接ダウンロードすることができます。この中には DB2® や Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品が含まれています。


議論するために


著者について

Tyler Anderson は、2004年に Brigham Young University でコンピューター・サイエンスの学位を取得し、2005年12月に同大学のコンピューター・エンジニアリングの理学修士を取得して、同大学を卒業しました。Tyler はフリーランス・ライターであり、Backstop Media のライターでもあります。




記事の評価


サイト改善のため、ご意見をお寄せください。こちらのフォームからお願いいたします。



 


 


不充分・不完全である大変素晴らしい
 


この記事を共有する

del.icio.us del.icio.us newsing newsing FC2ブックマーク FC2ブックマーク
Choix! Choix! ニフティクリップ ニフティクリップ Yahoo!ブックマーク Yahoo!ブックマーク
MM/memo MM/memo CZブックマーク CZブックマーク livedoorクリップ livedoorクリップ
はてなブックマーク はてなブックマーク Buzzurl(バザール) Buzzurl(バザール)




上に戻る


Adobe、Adobe ロゴ、PostScript、および PostScript ロゴは Adobe Systems Incorporated の米国およびその他の国における登録商標または商標です。 IBM、IBM ロゴ、ibm.com、DB2、developerWorks、Lotus、Rational、Tivoli、WebSphere、および pureXML は、International Business Machines Corporation の米国およびその他の国における商標です。 Java およびすべての Java 関連の商標およびロゴは、Sun Microsystems, Inc. の米国およびその他の国における商標です。 Microsoft、Windows、および Windows ロゴは、Microsoft Corporation の米国およびその他の国における商標です。 Linux は、Linus Torvalds の米国およびその他の国における商標です。UNIX は The Open Group の米国およびその他の国における登録商標です。 他の会社名、製品名およびサービス名等はそれぞれ各社の商標です。

    日本IBMについて プライバシー お問い合わせ