 |  |
|
난이도 : 중급 John Chun, DB2 Advanced Support Specialist, IBM Christine Law, DB2 Advanced Support Specialist, IBM Salvador Ledezma, Staff Software Engineer, IBM Alex Pitigoi, Advisory Software Engineer, IBM
2007 년 7 월 31 일 XML은 웹 상에서 가장 일반적인 데이터 교환 포맷 중 하나입니다. DB2®의 pureXML™ 지원과 Ruby on Rails에서 사용할 수 있는 XML API(REXML)의 파싱과 생성과 결합하여 웹 애플리케이션 개발의 강력한 콤비를 구성합니다. DB2 데이터 서버의 네이티브 XML 지원은, SQL과 XQuery용 하이브리드 데이터베이스 엔진 컴파일러와 파서를 통해, 반 구조화 된, 계층적 XML 문서를 저장하는 유연성을 관계형 데이터에 가져왔습니다. Ruby on Rails 시리즈 두 번째 글에서는 Team Room 예제에 pureXML을 활용하는 방법을 설명합니다.
머리말
Ruby on Rails 시리즈의 Part 1에서, Ruby on Rails와 DB2를 사용하여 등록된 멤버들이 다양한 텍스트 문서, 이미지 파일, XML 문서들을 공유할 수 있도록 하는 Team Room을 구현했다. 점점 늘어나는 공유 문서들을 관리하려면, 문서들을 카테고리 별로 그룹핑 하는 방법을 배워야 한다. 섭스크립션 기능을 추가하여 새로운 문서가 문서 카테고리에 추가될 때 이메일로 사용자에게 공지를 보낼 수 있다. 멤버들은 다양한 유형의 파일들을 Team Room에 업로드 할 수 있고, 파일들은 백엔드 DB2 데이터 서버에 저장된다. 이제, 고급의 사용자 기능을 제공하고 리소스에 더욱 잘 접근할 수 있도록 Team Room을 향상시켜 보자.
Part 1의 Team Room 애플리케이션 업데이트
Step 1. 사용자 관리 기능 추가하기
먼저, 사용자 모델과 기반 테이블에 기능을 추가하여 인증을 실행한다. 고유 userid 스트링과 pseudo-random seed (salt)와 SHA 알고리즘을 사용하는 해시(hash) 패스워드가 있다 사용자 애트리뷰트를 추가하여 사용자 모델을 향상시킬 수 있고(예를 들어, 액티브, 랭크), 컨트롤러와 뷰 변경이 추가되어 새로운 사용자의 등록과 보안 로그인에 적용된다. Rails 프로젝트가 D:\rails\teamroom에 있기 때문에 참조되는 모든 경로들은 D:\rails\teamroom 디렉토리 내의 상대 경로이다.
a) ruby script/generate migration add_user_credentials_columns를 실행하여 마이그레이션 프로세스를 시작하고, 필수 컬럼을 USERS 테이블에 추가한다.
b) db/migrate/008_add_user_credentials_columns.rb 파일을 편집하여 필수 컬럼을 추가한다. (Listing 1):
Listing 1. 008_add_user_credentials_columns.rb 편집
class AddUserCredentialsColumns < ActiveRecord::Migration
def self.up
add_column :users, :userid, :string, :limit => 8
add_column :users, :hash_passwd, :string
add_column :users, :salt, :string
end
def self.down
remove_column :users, :userid
remove_column :users, :hash_passwd
remove_column :users, :salt
end
end
|
c) rake db:migrate를 실행하여 새로운 컬럼들을 USERS 테이블에 추가한다.
Step 2. 여러 사용자 섭스크립션에 사용할 수 있는 주제 만들기
첫 번째 글에서 설명한 Team Room에서, 각 주제는 한 개의 섭스크립션에만 속할 수 있다고 했다. 각 섭스크립션은 사용자가 제출했던 주제들의 컬렉션이다. 이는 우리의 Team Room을 다소 비현실적으로 만든다. 사용자가 특정 주제를 선택하면, 선택된 주제는 Team Room의 다른 사용자들이 더 이상 사용할 수 없기 때문이다.
Team Room의 대중성 덕택에, 많은 멤버들이 여러 주제들을 신청할 수 있다. 따라서, 멤버들의 요청을 존중할 수 있고, 같은 주제에 대한 다중 섭스크립션을 허용할 할 수 있다. 업데이트 된 Team Room에서, 사용자는 단일 섭스크립션을 통해 많은 주제들을 신청할 수 있다. 이러한 변화를 실행하려면 다음 단계들을 따른다.
- 이전에는 SUBSCRIPTIONS와 SUBJECTS 사이에 일대다 관계가 있었다. 각 주제는 하나의 섭스크립션에만 속할 수 있다. 이러한 제한을 없애려면, SUBSCRIPTIONS와 SUBJECTS 간 다대다 관계를 허용해야 한다.
- 데이터베이스가 정상화 되었는지를 확인하려면(주 1 참조), 새로운 테이블 SUBJECTS_SUBSCRIPTIONS가 생성되어 SUBJECTS와 SUBSCRIPTIONS 테이블을 결합해야 한다. 중간 조인(join) 테이블의 이름을 선택할 때, 우리가 Rails 규약을 사용했음을 알 수 있다. Active Record는 이 조인 테이블의 이름이 두 개의 목표 테이블 이름들을 알파벳 순서로 자른 것이고, 두 개의 목표 테이블들을 연결하는 외래 키 쌍들을 포함하고 있다는 것으로 간주한다.
- 기존 제휴들이 수정되고, 새로운 제휴가 SUBJECTS_SUBSCRIPTIONS 테이블, 주제와 섭스크립션 모델에 추가되어 변경 사항을 반영한다.
 | |
주 1: IBM DB2 Database for Linux, UNIX, and Windows Information Center의 "Normalization" 섹션을 참조하라. |
|
SUBJECTS_SUBSCRIPTIONS 테이블에는 다음과 같은 컬럼들이 포함되어 있다.
표 1. SUBJECTS_SUBSCRIPTIONS 테이블 컬럼과 디스크립션
| 컬럼 이름 | 데이터 유형 | 설명 |
|---|
| SUBSCRIPTION_ID | Integer | SUBSCRIPTIONS 테이블에 대한 외래 ID |
|---|
| SUBJECT_ID | Integer | SUBJECTS 테이블에 대한 외래 ID |
|---|
마이그레이션 방법은 다음과 같다.
a) Issue ruby script/generate migration create_subjects_subscriptions_table을 실행한다.
b) db/migrate/009_create_subjects_subscriptions_table.rb 파일을 편집한다.
Listing 2. 009_create_subjects_subscriptions_table.rb 편집
class CreateSubjectsSubscriptions < ActiveRecord::Migration
def self.up
create_table :subjects_subscriptions, :id => false do |t|
t.column :subscription_id, :integer, :null => false
t.column :subject_id, :integer, :null => false
end
remove_column :subjects, :subscription_id
add_index :subjects_subscriptions, :subject_id
end
def self.down
drop_table :subjects_subscriptions
add_column :subjects, :subscription_id, :integer
end
end
|
c) rake db:migrate를 실행하여 SUBJECTS_SUBSCRIPTIONS 테이블을 생성한다.
e) 기존 /app/models/subject.rb 파일에 있는 belongs_to :subscription을 새로운 제휴 has_and_belongs_to_many :subscriptions로 대체한다.
f) /app/models/subscription.rb 파일에 있는 기존 제휴 has_many: subject를 has_and_belongs_to_many :subjects로 대체한다.
 | |
주 2: 마이그레이션 할 때, 각 모델의 데이터베이스 객체와의 제휴도 이에 따라 변경된다. |
|
Step 3. XML 데이터: 고객 정보
마케팅 부서는 XML 포맷으로 수많은 고객 정보를 수집하여 고객의 쇼핑 습관을 분석한다. 다음은 시장 연구를 위해 수집된 데이터 예제이다.
Listing 3. 샘플 XML 문서
<marketinfo xmlns="http://www.ibm.com/developerworks">
<sales>
<customer>
<address>
<city>Nashville</city>
<state>TN</state>
<zip>46808</zip>
</address>
<categories>
<category type='Toys'>
<item>
<SKU>2434901</SKU>
</item>
<item>
<SKU>9043272</SKU>
</item>
</category>
<category type='Video Games'>
<item>
<SKU>1915216</SKU>
</item>
</category>
</categories>
<last_purchase>2007-05-12</last_purchase>
</customer>
</sales>
</marketinfo>
|
각각의 고객 구매에는 미국 또는 캐나다 내의 주소, 아이템 SKU 넘버를 포함한 제품 카테고리 상세, 마지막 구매 날짜가 포함되어 있다.
- Apparel
- Automotive
- Baby
- Books
- Computers
- Cosmetics
- Electronics
- Garden & Patio
- Home
- Jewelry
- Movies
- Music
- Pets
- Pharmacy
- Sports
- Toys
- Video Games
다음 섹션에서는 Team Room 애플리케이션을 사용하여 이러한 XML 데이터에 쿼리 연산을 수행하는 방법을 설명한다.
텍스트 문서 포맷으로 된 마케팅 리포트를 위 XML 고객 데이터로 연결할 수 있다. 마케팅 리포트에는 시장 분석 또는 컬렉션이 발생하는 방법에 대한 상세가 포함된다.
Part 1에서는 XML 유형의 컬럼을 만들어서 수집된 마케팅 데이터를 저장했다. 전통적인 SQL 데이터 유형 같은 XML 데이터를 효율적으로 관리하기 위해 DB2는 XML 데이터 모델을 내부적으로 사용한다. 논리적 데이터 모델로서, 그리고 물리적 스토리지의 기본 단위로서 사용한다. 더욱이, 이러한 데이터 모델은 XML 데이터 유형이 지정될 때 데이터베이스 사용자들에게 노출된다. 이것은 XML 데이터를 관리하는데 많은 힘과 유연성을 제공하고, 특히 XML 중심의 개발자들에게는 XML 컬럼에 대해 수행될 수 있는 전통적인 데이터베이스 관리 액티비티의 유형에 제한이 있다. 예를 들어, XML 컬럼이 있는 테이블은 DB2에 의해 재구성 될 수 없다. XML의 계층적 스토리지 구조 때문이다. ALTER 연산으로 XML 컬럼을 포함하고 있는 테이블에서 컬럼을 제거할 수 없다는 의미이다. 이러한 한계는 향후 릴리스에서는 사라지겠지만, Ruby on Rails 마이그레이션에 대한 연산 수행 시 이를 염두 해 두어야 한다.
XML의 힘을 포기하지 않고, Ruby on Rails 마이그레이션의 유연성을 활용하기 위해, 개별 테이블을 만들어서 XML 데이터를 저장해 보자. 이를 XML_CONTENTS라고 해보자. 이것은 XML 문서들을 저장하고, DOCUMENTS 테이블은 계속해서 다른 모든 관련 정보들을 저장할 것이다. DOCUMENTS 테이블에서 컬럼의 추가 또는 삭제가 향후에도 발생할 수 있고, 이는 XML 데이터에 의해서 영향을 받지 않으며, XML_CONTENTS 테이블에 있는 XML 데이터에 영향을 주지도 않는다.
XML 데이터 유형을 사용에 대한 제한 사항들은 IBM DB2 Database for Linux, UNIX, and Windows Information Center의 "Restrictions on native XML data store" 섹션을 참조하라.
이 태스크를 수행하려면, 다음 마이그레이션을 생성 및 실행해야 한다.
a) ruby script/generate migration create_xml_contents를 실행하면, db/migrate/010_create_xml_contents.rb 파일이 만들어진다.
b) db/migrate/010_create_xml_contents.rb.rb 파일을 편집한다.
Listing 4. 010_create_xml_contents.rb 편집하기
class CreateXmlContents < ActiveRecord::Migration
def self.up
drop_table :documents
create_table :documents do |t|
t.column :name, :string, :null => false
t.column :size, :integer, :null => false
t.column :data, :binary, :limit => 2.megabytes
t.column :content_type, :string, :null => false
t.column :created_at, :timestamp
t.column :updated_at, :timestamp
t.column :platform, :string, :limit =>10
t.column :subject_id, :integer
t.column :user_id, :integer
end
create_table :xml_contents do |t|
t.column :name, :string
t.column :data, :xml, :null => false
t.column :document_id, :integer
end
end
def self.down
drop_table :documents
drop_table :xml_contents
create_table :documents do |t|
t.column :name, :string, :null => false
t.column :size, :integer, :null => false
t.column :data, :binary, :limit => 2.megabytes
t.column :content_type, :string, :null => false
t.column :created_at, :timestamp
t.column :updated_at, :timestamp
t.column :platform, :string, :limit =>10
t.column :subject_id, :integer
t.column :user_id, :integer
t.column :xmldata, :xml, :null => false
end
end
end
|
c) rake db:migrate를 실행하여 기존 DOCUMENTS 테이블을 제거하고, XML_CONTENTS라고 하는 새로운 XML 데이터 전용 테이블과 새로운 DOCUMENTS 테이블(XML 컬럼 없음)을 만든다.
d) 새로운 DOCUMENTS 테이블과 XML_CONTENTS 테이블간 관계를 재정립 한다.
먼저, belongs_to :document 제휴를 Step d에서 생성된 /app/models/xml_content.rb 파일에 추가한다.
두번째는, has_one :xml_content 제휴를 /app/models/document.rb 파일에 추가한다.
e) 업로드 기능은 이제 부모 모델이 되고 자식 모델(xml_content)의 생성에 대한 핸들링을 추가한 이전 문서 모델(document.rb)에 구현되었던 것과 비슷하다.
NAME 컬럼에 원래의 파일 이름이 채워진다.
Listing 5. 파일 애트리뷰트에 DOCUMENTS 레코드 할당하기
self.name = File.basename(doc_field.original_filename).gsub(/[^\w._-]/, '')
self.content_type = doc_field.content_type.chomp
self.size = doc_field.size
self.created_at = Time.now
|
XML_CONTENTS.DATA 컬럼에 지정된 파일이 채워진다.
Listing 6. XML 파일 콘텐트에 XML_CONTENTS.DATA 지정하기
unless self.content_type.include?('text/xml')
self.data = doc_field.read
else
content = XmlContent.new
content.name = self.name
content.data = doc_field.read
self.xml_content = content
end
|
마지막 /app/models/document.rb이 Listing 7과 같이 나타난다.
Listing 7. document.rb
class Document < ActiveRecord::Base
belongs_to :user
belongs_to :subject
has_one :xml_content
# values displayed | stored
PLATFORM_TYPES = [ ['Neutral', 'Any'],
['Windows', 'WinXP'],
['Mac OS X', 'MacOS'],
['Linux', 'Linux']]
def uploaded_doc=(doc_field)
self.name = File.basename(doc_field.original_filename).gsub(/[^\w._-]/, '')
self.content_type = doc_field.content_type.chomp
self.size = doc_field.size
self.created_at = Time.now
unless self.content_type.include?('text/xml')
self.data = doc_field.read
else
content = XmlContent.new
content.name = self.name
content.data = doc_field.read
self.xml_content = content
end
end
end
|
XML_CONTENTS와 DOCUMENTS 테이블의 모델이 정의되었으므로, 뷰를 수정하여 업로드와 디스플레이 기능을 핸들해야 한다. 업로드 기능과 문서를 리스팅 하는 뷰가 업데이트 되어 디스플레이 될 모델 애트리뷰트(컬럼)를 선택할 수 있도록 했다.
/app/views/documents/list.rhtml은 이러한 컬럼 선택을 다음과 같이 구현한다.
Listing 8. /app/views/documents/list.rhtml
<table cellpadding="0" cellspacing="0">
<tr>
<th>ID</th>
<th>Document name</th>
<th>Subject</th>
<th>Shared by</th>
<th>Size</th>
<th>Update at</th>
<th>Platform</th>
<th></th>
<th></th>
<th></th>
</tr>
<% @documents.each_with_index do |document,i| %>
<% row_class = i%2 ==0 ? "even" : "odd" %>
<tr class="<%=row_class%>">
<td><%= document.id %></td>
<td><%= document.name %></td>
<% if document.subject %>
<td><%= link_to "#{document.subject.name}",
:controller => 'subjects', :action => 'list' %></td>
<% else %>
<td></td>
<% end %>
<% if document.user %>
<td><%= link_to "#{document.user.userid}",
:controller => 'users', :action => 'list' %></td>
<% else %>
<td></td>
<% end %>
<td><%= number_to_human_size( document.size ) %></td>
<td><%= document.updated_at.strftime("%d/%m/%Y %I:%M%p") %></td>
<td><%= document.platform %></td>
<td><%= link_to 'Show', :action => 'show', :id => document %></td>
<td><%= link_to 'Edit', :action => 'edit', :id => document %></td>
<td><%= link_to 'Remove', { :action => 'destroy', :id => document },
:confirm => 'Are you sure?', :method => :post %></td>
</tr>
<% end %>
</table>
|
후속 업데이트는 XML 데이터의 문서 보기 기능을 핸들링 하는 컨트롤러에 이루어졌다. 이 엔트리들이 /app/controllers/documents_controller.rb에 추가되었다.
Listing 9. documents_controller.rb
def show
@document = Document.find(params[:id])
doc_type = @document.content_type
unless doc_type.include?('text/xml')
doc_content = @document.data
else
doc_content = @document.xml_content.data
end
send_data(doc_content,
:filename => @document.name,
:type => doc_type,
:disposition => "inline")
end
|
다음 업데이트는 XML 문서 업로드에 대한 지원 부분에 이루어졌다. 주제와 사용자 관계 핸들링에 대한 문서 구현을 볼 수 있다.
Listing 10. documents_controller.rb
def upload
if params[:document][:uploaded_doc].to_s.empty?
flash[:notice] = "Please provide a file for upload"
redirect_to(:action => "new" )
else
@document = Document.new(params[:document])
@subject = params[:subject_name] && params[:subject_name].empty? ?
Subject.new :
Subject.find_by_name(params[:subject_name])
Document.transaction do
User.find(session[:user_id]).documents << @document
@subject.documents << @document
@subject.size = @subject.documents.size
if @subject.new_record?
@subject.name = params[:subject][:name]
@subject.tag = params[:subject][:tag]
@subject.description = params[:subject][:description]
@subject.save
end
if @document.save
flash[:notice] = "Document #{@document.name} successfully created."
if @document.subject.subscriptions
SubscriptionMailer.deliver_notify(@document)
end
redirect_to :action => 'list'
else
render :action => 'new'
end
end
end
|
아래 그림 1은 위 마이그레이션 단계를 수행한 후에 Team Room의 다른 모델들 간 제휴 관계를 묘사한다.
그림 1. 변경 후 다른 모델들 간 새로운 제휴 관계
XML 마케팅 데이터를 Team Room에 업로드 하기
 | |
주 3: 잘 형성된 XML 문서만이 IMPORT 명령어를 사용하여 반입될 수 있다.
주 4: 다음 명령어를 사용하여 XML 스키마를 제거한다:
drop xsrobject teamroom.marketinfo
|
|
마이그레이션을 통해 모든 필요한 스키마 변화가 구현되었으니, XML 데이터를 XML_CONTENTS 테이블에 업로드 할 수 있다. 여러 XML 문서들을 하나의 테이블에 삽입하는 가장 쉬운 방법은 DB2 9 데이터 서버의 IMPORT 유틸리티를 사용하는 것이다. IMPORT 유틸리티는 XML 스키마 밸리데이션을 통해 또는 밸리데이션 없이 잘 형성된 XML 문서들을 반입한다. 현재로서는, XML_CONTENTS 테이블, DOCUMENTS 테이블, SUBJECTS 테이블의 관련 엔트리들이 잘 업데이트 되었는지를 확인해야 한다. 따라서, 생성된 스카폴드는 한번에 하나의 파일을 업로드 하는데 사용되어서, 모든 외래 키 제휴들을 관리해야 한다.
그림 2에서, 새로운 Document 뷰 /app/views/documents/new.rhtml이 XML 콘텐트와 관련한 문서 생성과, 새로운 문서와 제휴된 새로운 주제의 생성을 보여주고 있다.
그림 2. XML 문서를 Team Room 저장소에 업로드 하기
XQuery와 XPath 검색을 연습할 때 사용될 수 있는 캐나다와 미국의 일부 지역을 시뮬레이트 한 마케팅 데이터가 포함된 XML 문서들을 업로드 할 시간이다. XML 파일들은 /test/fixtures 밑에 marketinfo.xsd XML 스키마와 함께 배치되어 밸리데이션에 사용된다. 다운로드 섹션에서 업데이트 된 Team Room 애플리케이션을 제공한다.
XML 데이터 유형을 사용한 기본적인 CRUD 연산
기본적인 XML Create, Retrieve, Update, Delete (CRUD) 연산을 수행하여 XML 데이터를 관리하는 방법에 대한 감을 익혀보자.
Marketing 부서는 고객들이 살고 있는 도시를 서베이 해야 한다. 아마도, 고객의 인지도와 고객의 상점 재방문을 높이기 위해 그 도시에 마케팅 캠페인이 있을 것이다. 이를 위해, XML_CONTENTS 테이블에 저장된 Marketing Info XML 문서에서 데이터를 가져올 수 있다. 더욱이, 점점 증가하는 도시들의 저장소를 (지속적으로) 트래킹하기 위해 서베이를 저장하기로 결정했다. 이러한 도시들의 데이터베이스를 XML로 생성하기로 결정했다면, 데이터를 트래킹 하기 위해 또 다른 테이블을 만들 걱정을 할 필요가 없다. 이것을 XML 문서로 구성하고, 같은 컬럼에 XML로 다시 삽입할 수 있다. 향후에도 DBA는 애플리케이션 데이터를 분리하기 위해 새로운 테이블을 만들어야 하지만, 이는 엄밀히 논리적이며 의미론적인 요구 사항이고, 데이터베이스에는 이것이 필요하지 않다.
DB2에서, XML 데이터는 많은 방식들로 쿼리될 수 있다. SQL, XQuery, 또는 이 두 가지를 결합하여 사용한다. 이 예제는 XQuery를 사용한다. XQuery는 XML 문서들을 구축하기 위한 값으로 사용될 쿼리 결과를 리턴한다. Listing 11은 XQuery 실행 모습이다.
Listing 11. 도시 서베이 XQuery
XQUERY
<cities>
declare default element namespace "http://www.ibm.com/developerworks";
{ for $c in fn:distinct-values(
db2-fn:xmlcolumn(
'XML_CONTENTS.DATA')/marketinfo/sales/customer/address/city)
order by $c
return <city>{$c}</city>
}
</cities>
|
db2-fn:xmlcolumn() 함수로 시작해서 이 XQuery가 어떤 일을 하는지 알아보자. db2-fn:xmlcolumn()은 현재 연결되어 있는 DB2 데이터베이스에 있는 XML 컬럼에서 시퀀스를 가져오는 함수이다. 여기에서, 우리는 XML_CONTENTS에서 데이터를 가져온다. 정확히 말하면 DATA 컬럼이다. 하지만, 모든 데이터가 필요한 것은 아니고, XPath 식으로 구분된 하위 세트만 필요하다. /marketinfo/sales/customer/address/city.
다시 말해서, 테이블에 있는 모든 행의 모든 XML 문서를 보고, XPath에 나타난 모든 도시 엘리먼트들을 선택해야 한다. 한 명 이상의 고객이 같은 도시에 살 수 있기 때문에 잠재적인 문제가 있다. 이러한 문제에 우리는 XQuery 함수 fn:distinct-values()를 사용한다. 이름에서 함축하듯, 뚜렷하게 구분된 도시 엘리먼트만 리턴한다. 도시 이름들은 반복되지 않는다. 이 시퀀스는 변수 $c에 할당된다.
마지막 단계 전에, $c에 있는 도시들의 순서가 정해진다. 그리고 나서 결과가 리턴된다. XQuery를 강력하게 만드는 특징들 중 하나는 리턴된 데이터 포맷을 커스터마이징 할 수 있다는 점이다. 우리는 현재 도시 이름을 갖고 있기 때문에 각 도시를 <cities> 엘리먼트에 래핑한다. 이는 루트 엘리먼트를 갖고 있지 않으므로 유효 XML 문서가 아닌 엘리먼트의 시퀀스이다. 유효 XML 문서가 리턴되었는지 확인하려면, 전체 결과가 <cities> 엘리먼트 내에 배치되어, 데이터가 Listing 12처럼 오름차순으로 나타나야 한다.
Listing 12. 전형적인 XML 데이터 리턴
<cities>
<city>Atlanta</city>
<city>Augusta</city>
<city>Austin</city>
<city>Baton Rouge</city>
<city> ... </city>
</cities>
|
DB2 9의 XQuery에 대해 자세히 배우고 싶다면 DB2 XML Guide (참고자료)를 참조하라.
XML 문서로 된 도시 리스팅이 생겼으니, 이 문서를 다시 데이터베이스에 삽입해 보자. 이러한 유형의 데이터가 데이터베이스에 삽입되는 방식과 똑같이 XML 문서를 삽입할 수 있다.
Listing 13. XML 문서 삽입하기
class DocumentsController < ApplicationController
[...]
def upload
[...]
@document = Document.new(params[:document])
@subject = params[:subject_name] && params[:subject_name].empty? ?
Subject.new :
Subject.find_by_name(params[:subject_name])
Document.transaction do
User.find(session[:user_id]).documents << @document
@subject.documents << @document
@subject.size = @subject.documents.size
if @subject.new_record?
@subject.name = params[:subject][:name]
@subject.tag = params[:subject][:tag]
@subject.description = params[:subject][:description]
@subject.save
end
if @document.save
flash[:notice] = "Document #{@document.name} successfully created."
[...]
end
|
어떤 경우에는 고객의 수가 정적인 것이 아니기 때문에, 도시 리스트를 주기적으로(주간 또는 월간) 업데이트 해서, 최신의 리스트를 유지한다. 이를 수행하려면, 같은 XQuery 문을 실행한다. 현재 데이터베이스에 있는 문서는 id에 기반한 XML 파일의 최신 버전으로 대체된다. 기존 문서가 숨겨진 :id 매개변수를 통해 검색되는 방법을 주목하라. 이것은 편집 뷰 폼(/app/views/documents/_form.rhtml)으로 전달되어 DocumentsController에서 사용된다.
Listing 14. XML 문서 업데이트 하기
class DocumentsController < ApplicationController
[...]
def update
@document = Document.find(params[:document][:id])
if @document.update_attributes(params[:document])
flash[:notice] = 'Document was successfully updated.'
redirect_to :action => 'show', :id => @document
else
render :action => 'edit'
end
end
[...]
end
|
내부적으로, DB2는 기존 XML 데이터 페이지를 할당 해제하고, 새로운 값이 다시 삽입된다. 따라서, 전체 XML 문서는 새롭고 업데이트 된 문서로 대체된다.
데이터가 더 이상 필요 없거나 다른 메커니즘에 의해 처리되어야 할 때도 있다. 예를 들어, DBA는 다른 테이블에 다른 XML 컬럼을 사용하는 것 같이, 영역의 분리를 주장한다. 문서를 제거하려면, DELETE 문과 WHERE 술어를 실행해야 한다. Ruby에서, 이는 다음과 같이 수행된다.
Listing 15. XML 문서 삭제하기
class DocumentsController < ApplicationController
[...]
def destroy
Document.find(params[:id]).destroy
redirect_to :action => 'list'
end
end
|
XML 데이터 쿼리하기
CRUD 연산 외에도, XQuery 언어의 힘은 쿼리하는 방식과 데이터가 리턴되는 방식을 매우 정확하게 수행하는데 있다. 예를 들어, 고객이 살고 있는 도시의 리스트를 갖추는 것도 도움이 되지만, 마케팅 부서는 제품 카테고리에 더 관심이 있을 수 있다. 이는 마케팅 캠페인에서 마케팅 이니셔티브의 초점을 좁힐 수 있다. 잘 팔리는 제품이 특정 제품 카테고리에서 최근에 구매된 것인지, 더욱 구체적으로 이러한 카테고리들이 특정 시간에도 활발히 거래되는 것인지를 나타내는 한 가지 평가 방법이 있다.
다음과 같이 질문으로 데이터 마이닝을 시작할 것이다: 2007년 4월 15일과 2007년 4월 30일 사이에 구매되었던 제품 카테고리는 무엇인가?
Listing 16은 Marketing 팀이 제기한 질문에 대한 답을 제공하는데 사용된다.
Listing 16. 4월 15일과 4월 30 사이에 구매된 제품 카테고리를 파악하기 위한 XQuery
XQUERY
declare default element namespace "http://www.ibm.com/developerworks";
<categories>
{ let $categories := fn:distinct-values(
for $c in db2-fn:xmlcolumn( "XML_CONTENTS.DATA")/marketinfo/sales/customer
where xs:date($c/last_purchase) > xs:date("2007-04-15")
and xs:date($c/last_purchase) <= xs:date("2007-04-30")
return $c/categories/category/@type)
for $c in $categories
return <category>{$c}</category>
}
</categories>
|
이전 예제와 마찬가지로, 유효 XML 문서를 리턴해야 하기 때문에, XQuery 결과를 <categories> 루트 XML 엘리먼트로 래핑해야 한다. XQuery는 두 부분으로 분리된다. 먼저, "let" 문은 $categories 변수에 대한 식의 바인딩으로서 작용한다. 이 변수는 for 문에 대한 콘텍스트로서 사용된다. 이것을 하나씩 검토해 보자.
"let" 문은 FLWOR (for, let, where, order by, return) XQuery 식으로 구성된다. 여러분도 알다시피, FLWOR 식은 SQL의 SELECT-FROM-WHERE 블록과 종종 비교되곤 한다. 여기에서 우리는 모든 고객들을 반복한다: for $c in db2-fn:xmlcolumn("XML_CONTENTS.DATA")
/marketinfo/sales/customer. 여기에서 구매 날짜는 4월 15일 이후이고 4월 30일 이전이다. 구매가 조건에 맞고, 마케팅은 이것에 대해 알아야 한다: where xs:date($c/last_purchase) > xs:date("2007-04-15")
and xs:date($c/last_purchase) <= xs:date("2007-04-30").
구매한 것 중에서, XML 애트리뷰트로서 저장된 카테고리 유형을 리턴한다: $c/categories/category/@type. 마지막 예제에서, fn:distinct-values() 함수를 사용하여 같은 카테고리에 중복 술어를 피한다. 카테고리의 리스트는 변수 $categories에 속한 것이다.
현재, $categories는 뚜렷하게 구별된 카테고리의 시퀀스를 저장하지만, 시퀀스의 각 값을 <category> XML 엘리먼트로 래핑할 것이다. 마지막 결과는 Listing 17의 결과와 비슷하고, 4월 15일에서 4월 30일까지 구매를 포함하도록 선별했다는 것을 알 수 있다.
Listing 17. 4월 15일과 4월 30일 사이에 구매한 제품 카테고리의 샘플 데이터
<categories>
<category>Home</category>
<category>Electronics</category>
<category>Apparel</category>
<category>Gifts & Flowers</category>
<category>Baby</category>
</categories>
|
이 XQuery는 Marketing이 원하는 날짜 범위에서 쿼리를 실행하도록 매개변수화 될 수 있다. 더욱이, 이 쿼리를 캡슐화 하기 위해, 이 기능을 저장 프로시저로 푸쉬하여, XQuery 상세를 Rails 개발자를 위해 추출한다.
그림 3에서, DOCUMENTS 리스트 뷰인 /app/views/documents/list.rhtml 레이아웃에는 사전 구현된 리포트 폼이 포함되어 있어 XQuery와 XPath 검색을 실행할 수 있다.
그림 3. Team Room Documents 저장소와 사전 구현된 마케팅 리포트
XML 데이터 쿼리하기
지금까지는 발을 적신 정도이다. Marketing은 데이터에 여전히 목마르다. 특정 카테고리 유형의 제품들이 특정 우편 번호에 해당하는 지역에서 얼마나 많이 판매되었는지도 궁금하다. 우편 번호는 많은 구매 내역이 있을 수 있고, 많은 불만 사항이 있을 수 있다. 이는 마케팅 및 제품 매니저들이 어떤 제품이 인기가 있는지를 파악하고, 이들을 해당 우편 번호와 연관시키는데 도움이 된다. 아마도, 마케팅은 어떤 제품을 철회해야 하는지, 어떤 우편 번호가 제품의 인기에 기반하여 마케팅 노력을 기울여야 하는지를 식별할 수 있다.
우리는 이를 결정하기 위해 SQL/XML 함수 XMLQUERY()를 사용한다. SQL/XML을 사용하여 쿼리를 수행하면 두 가지 힘을 모두 활용할 수 있다. 예를 들어, SQL/XML을 사용해서는 다음과 같은 연산을 수행할 수 있다.
- 관계형 데이터와 XML 데이터에 술어를 사용한다.
- XML 데이터의 조각에 액세스 하여 데이터를 추출한다.
- SQL 레벨에서 XML 데이터의 집합과 그룹핑을 사용한다.
- 관계형 데이터와 XML 데이터를 결합한다.
- 매개변수들을 XQuery 식에 전달한다.
우리는 XQuery에서 (1), (2), (5)를 사용할 것이다. 간단히 하기 위해, 예제를 매개변수화 하지 않고, 우편 번호 "79081"에서 "Jewelry" 카테고리 유형에 관심이 있는 것으로 간주한다. 하지만, Marketing 팀의 재미를 위해서, 제공된 애플리케이션 코드(다운로드)에는 카테고리 유형 또는 우편 번호에 매개변수를 허용하는 쿼리를 포함하고 있다.
Listing 18. SQL/XML 쿼리를 사용하여 특정 우편 번호에서 팔린 전체 카테고리 유형 검색하기
select name, xmlquery(
'declare default element namespace "http://www.ibm.com/developerworks";
let $total := sum (
for $i in $t//category
let $sum := count($i/item)
where $i/@type = "Jewelry"
return $sum
)
return <total>{$total}</total>'
passing data as "t"
) as data
from teamroom.documents
where xmlexists(
'declare default element namespace "http://www.ibm.com/developerworks";
$t/marketinfo/sales/customer/address[zip = "79081"]'
passing data as "t"
)
|
SELECT 문은 name 컬럼으로 구분된 지역에 한 개의 행을 리턴한다. 게다가, 각 행의 형우, <total> 루트 엘리먼트만 포함하고 있는 유효 XML 문서를 리턴한다. 우리는 SQL 언어 내에서 XQuery를 호출하기 때문에, SQL/XML 함수 XMLQUERY()를 사용해야 하고, XQuery 엔진이 연산을 실행할 콘텍스트를 알 수 있도록 해야 한다. 이전 예제에서, 이는 db2-fn:xmlcolumn() 함수를 사용하여 수행되었다. 여기에서는, 데이터를 t로 전달하는 문을 사용한다. data를 XML 컬럼으로 구분하여 연산을 수행하고, 여기에 변수 t를 할당한다. 변수 $t가 XQuery에 나타날 때마다, SELECT 문의 현재 행의 data 컬럼에 있는 XML 문서를 대체해야 한다는 것을 알게 된다.
SQL 레벨에서 또 다른 차이는 이 컬럼에서 모든 XML 문서에 대해 XMLQUERY()가 연산을 수행하기를 원치 않는다는 것이다. 이 쿼리를 우편 번호가 "79081"인 고객을 포함하고 있는 행으로 제한하고 싶다. 이러한 행들을 찾으면, 여기에 대해서만 XQuery를 실행할 것이다. 구체적으로, 우편 번호가 "79081"인지 여부에 상관없이 이 행에서의 모든 고객 구매가 쿼리된다.
필터링은 SQL/XML XMLEXISTS() 함수 술어를 사용하여 SQL WHERE 문으로 실행된다. XMLEXISTS 술어는 XQuery 식이 한 개 이상의 엘리먼트를 리턴하는지 여부를 결정한다. 우리 예제에서, XMLEXISTS()로 전달한 XQuery 식은 간단한 XPath 식으로서, 여기에서 $t는 XML 컬럼 data:
$t/marketinfo/sales/customer/address[zip = "79081"]이다.
이 XPath 식은 다음과 같이 해석될 수 있다: 우편 번호가 "79081"인 주소 엘리먼트의 시퀀스를 리턴하라. 지정된 XPath가 빈 시퀀스를 리턴하면 XMLEXISTS는 false를 리턴한다. 그렇지 않으면, true를 리턴한다. SQL이 XML 문서의 하위 세트를 획득하는데 도움이 되었으니, XQuery는 $total 변수에 대해 let 바인딩을 사용한다. $total에는 FLWOR 식의 결과가 할당된다. 유형이 "Jewelry" (where $i/@type = "Jewelry")인 XML 문서의 <category> 엘리먼트(for $i in $t//category)는 판매된 수를 세고 이를 $sum (let $sum := count($i/item))에 할당하여 sum (return $sum)을 리턴한다.
이것은 각 고객의 합계 시퀀스를 리턴한다. 결과는 sum() 함수로 전달되어 특정 카테고리에 대해 모든 고객들을 대상으로 총합을 계산하며 $total이라 한다. XML을 리턴해야 하므로, <total> 엘리먼트 (return <total>{$total}</total>')로 래핑된 총합을 리턴한다. 결과는 return <total>198</total>'와 비슷하다.
DB2 9에서의 XQuery 사용 예제는 DB2 XML Guide (참고자료)를 참조하라.
XML 데이터 나누기(Shredding)
새롭게 구현된 애플리케이션이 네이티브 XML에 대해서는 실행되지 않는 레거시 애플리케이션과 저장소로 통합되어야 한다고 생각해 보자. XML 문서로 저장된 정보는 관계형 테이블 객체에 배치되어야 한다.
시장 분석 결과가 레거시 애플리케이션에 의한 분석을 위해 관계형 스토어에 기여되어야 하는 상황을 생각해 보자. 이 부분에서는 XML 데이터를 나누어서 이것이 관계형 테이블로 삽입될 수 있도록 해야 한다.
pureXML은 XML 데이터로 직접 작업할 수 있는 다양한 장치를 제공한다. pureXML은 또한 Shredding 또는 Decomposition으로 알려진 기능을 제공한다. DB2 9 데이터 서버는 다음과 같은 빌트인 툴을 제공하여 XML Shredding을 사용한다.
1. XDBDECOMPXML 저장 프로시저
DB2 9의 주석이 달린 XML 스키마 Decomposition 기능은 XML 문서들을 관계형 테이블로 분해하는데 사용될 수 있다. 이름에서 시사하듯, 이것은 매핑 언어로서 XML 스키마의 주석을 사용하여 XML 문서의 정보를 관계형 테이블로 매핑한다. 이것은 XML 스키마를 필요로 하기 때문에, XML 스키마 문서는 DB2 XSR로 저장되어야 하고 Decomposition 되어야 한다. XML 문서를 매핑된 관계형 컬럼으로 분해하는 것은 DB2 저장 프로시저(xdbDecompXML) 호출을 통해서 또는 Command Line Processor (CLP) 명령어를 사용하여 수행된다.
Visual Studio Add-in을 통한 XML Shredding 지원은 "DB2 Visual Studio 2005 Add-in을 사용한 주석이 달린 XML 스키마 디컴포지션".
XML 스키마에 주석을 다는 또 다른 방법은 DB2 Developer Workbench (DWB)를 사용하는 것이다. 무료로 다운로드 할 수 있는 DWB는 DB2 데이터베이스 애플리케이션들의 생성, 편집, 디버깅, 전개가 가능한 포괄적인 환경이며, 저장 프로시저와 사용자 정의 함수를 개발할 수도 있다. 다운로드 섹션을 참조하라.
DWB의 컴포넌트들 중 하나는 주석이 달린 XML 스키마 Decomposition Mapping Editor이다. 단순하고 매력적인 그래픽 인터페이스를 사용하면, XML 스키마와 관계형 스키마간 관계를 매핑 할 수 있다. DB2에서 XML 엘리먼트나 애트리뷰트를 관계형 컬럼으로 매핑 하면 XML 스키마 문서에 자동으로 주석이 달린다. XML 스키마가 저장되고 XSR에 등록되면, XML 문서들을 DB2로 분해할 준비가 된 것이다.
XML 스키마 주석과 저장 프로시저의 xdbDecompXML 세트를 이 글에서 다 설명할 수 없다. 주석이 달린 XML 스키마 Decomposition과 콘텐트에 기반한 조건적 Decomposition 또는 삽입 전에 적용되는 콘텐트 변형 지정 같은 고급 기능은 DB2 9 XML Guide(참고자료)를 참조하라. XML Extender와 방법에 익숙한 사람들은 developerWorks 기술자료, ""From DAD to Annotated XML Schema Decomposition"(Mayank Pradhan)을 참조하라.
2. XMLTABLE SQL 테이블 함수
XMLTABLE은 XML 문서에서 XQuery 식의 계산을 통해 테이블을 리턴하는 SQL 테이블 함수이다. 리턴되는 테이블에는 XML을 포함하여 SQL 데이터 유형의 컬럼이 포함된다. XMLTABLE을 사용하여, XML 문서에서 검색된 값들이 INSERT 문과 결합될 때 관계형 테이블로 삽입될 수 있다. 이로써, 주석이 달린 XML 스키마 Decomposition과 같은 기능을 사용할 수 있다. 이를 "Insert-from-XMLTABLE" 문이라고도 한다.
이것은 단순한 형태의 XML Shredding을 제공하고, 관계형 테이블의 다양한 컬럼에 XML 문서 조각들을 저장하는데 이상적이다.
다음 문은 XQuery 식을 실행하고 DATA 컬럼에서 테이블로서 값을 리턴한다. 각 행은, 특정 고객의 도시, 주, 우편 번호, 최근 구매 날짜를 보여준다.
Listing 19. XMLTABLE 함수
SELECT X.CITY, X.STATE, X.ZIP, X.LAST_PURCHASE FROM
TEAMROOM.XML_CONTENTS,
XMLTABLE (XMLNAMESPACES (DEFAULT 'http://www.ibm.com/developerworks'),
'db2-fn:xmlcolumn("XML_CONTENTS.DATA")//customer'
COLUMNS
"CITY" CHAR(16) PATH './address/city',
"STATE" CHAR(16) PATH './address/state',
"ZIP" CHAR(6) PATH './address/zip',
"LAST_PURCHASE" DATE PATH './last_purchase') as X
|
위 XQuery의 결과는 다음과 같다.
Listing 20. XMLTABLE 결과
Baton Rouge LA 77888 03/10/2007
Baton Rouge LA 14257 01/07/2007
Richmond VA 78045 01/26/2007
Oklahoma City OK 71107 04/13/2007
Tallahassee FL 41720 04/25/2007
Richmond VA 39591 03/25/2007
Richmond VA 36522 03/23/2007
Richmond VA 32230 02/12/2007
Charleston WV 33015 02/12/2007
Columbia SC 72647 01/11/2007
Raleigh NC 11238 04/02/2007
Nashville TN 21245 01/06/2007
Fankfort KY 53793 04/18/2007
Austin TX 35462 03/13/2007
Columbia SC 68359 01/01/2007
Jackson MS 25770 01/20/2007
Little Rock AR 46342 03/10/2007
Tallahassee FL 54306 01/20/2007
Charleston WV 44339 02/20/2007
Frankfort KY 92403 02/27/2007
<etc ........>
|
여러분이 적절한 SQL 유형들을 정의하고 CUSTOMER_INFOS 테이블을 정의했다면, XML 마케팅 정보(테이블 식 포맷)에서 추출한 고객 데이터를 관계형 테이블에 삽입할 수 있다. SELECT 문 주위에 INSERT 문을 다음과 같이 래핑한다.
Listing 21. 분해된 XML 데이터를 관계형 테이블로 삽입하기
INSERT INTO TEAMROOM.CUSTOMER_INFOS
SELECT X.CITY, X.STATE, X.ZIP, X.LAST_PURCHASE FROM
TEAMROOM.XML_CONTENTS,
XMLTABLE (XMLNAMESPACES (DEFAULT 'http://www.ibm.com/developerworks'),
'db2-fn:xmlcolumn("XML_CONTENTS.DATA")//customer'
COLUMNS
"CITY" VARCHAR(16) PATH './address/city',
"STATE" CHAR(16) PATH './address/state',
"ZIP" CHAR(6) PATH './address/zip',
"LAST_PURCHASE" DATE PATH './last_purchase') as X
|
Ruby에는 Ruby Electric XML (REXML)이라고 하는 XML 프로세서가 포함되어 있다. 이는 XML 데이터의 트리 파싱과 스트림 파싱에 사용될 수 있다. (참고자료)
꿈의 Web 2.0 시대
본 시리즈의 Part 1에서는 사용자가 특정 관심사의 업데이트를 제공하는 기능을 소개했다. 업데이트가 이루어지면, 사용자는 이메일 공지를 받는다. 너무 구식이다. Web 2.0 시대에는, RSS나 Atom으로 공지를 받는다.
DB2 9 pureXML을 사용하면, 선호하는 피드 리더기를 사용하여 누구나 쉽게 폴링(poll)할 수 있는 피드를 생성할 수 있다. 우리는 SQL/XML XML 퍼블리싱 함수를 사용한다. XML 퍼블리싱 함수는 XML 노드와 문서를 구현하는데 사용된다. 관계형 데이터와 XML 데이터 모두 사용된다.
주: 퍼블리싱 함수를 생성자 함수라고도 한다.
DB2 9에서 사용할 수 있는 XML 퍼블리싱 함수는 다음과 같다:
- XMLNAMESPACES
- XMLELEMENT
- XMLATTRIBUTE
- XMLFOREST
- XMLDOCUMENT
- XMLCONCAT
- XMLCOMMENT
- XMLPI
- XMLTEXT
관심사 등록이 업데이트 될 때 사용자에게 공지를 보내는 Atom 피드를 만들어 보자. Atom 피드를 선택했지만, DB2는 RSS 피드도 생성할 수 있다. 적절한 XML 스키마를 사용하여 피드를 구현하는 것이 관건이다.
Listing 22. Atom 피드 저장 프로시저
CREATE PROCEDURE GET_ATOM_FEED ( )
DYNAMIC RESULT SETS 1
------------------------------------------------------------------------
-- SQL Stored Procedure
------------------------------------------------------------------------
P1: BEGIN
-- Declare cursor
DECLARE cursor1 CURSOR WITH RETURN FOR
SELECT XMLSERIALIZE(
XMLDOCUMENT(
XMLELEMENT (NAME "feed",
XMLNAMESPACES(DEFAULT 'http://www.w3.org/2005/Atom'),
XMLCONCAT (
XMLELEMENT (NAME "id", 'http://localhost:3000/documents'),
XMLELEMENT (NAME "title", 'Teamroom Documents'),
XMLELEMENT (NAME "updated", CURRENT TIMESTAMP),
XMLELEMENT (NAME "link",
XMLATTRIBUTES('http://localhost:3000/documents/atom_feed'
as "href", 'self' as "rel")),
XMLELEMENT (NAME "author",
XMLCONCAT(
XMLELEMENT (NAME "name", 'TeamRoom'),
XMLELEMENT (NAME "email", 'teamroom@developerWorks.ibm.com')
)
),
XMLAGG (
XMLELEMENT (NAME "entry",
XMLCONCAT (
XMLELEMENT (NAME "title", name),
XMLELEMENT (NAME "id", 'http://localhost:3000/documents/show/'
|| CHAR(id)),
XMLELEMENT (NAME "updated", updated_at),
XMLELEMENT (NAME "link", 'http://localhost:3000/documents/show/'
|| CHAR(id)),
XMLELEMENT (NAME "category", category),
XMLELEMENT (NAME "summary", content_type),
XMLELEMENT (NAME "content", XMLATTRIBUTES('text' as "type"), content)
)
)
)
)
)
)
AS CLOB INCLUDING XMLDECLARATION
)
FROM (SELECT d.id as id, d.name as name, d.content_type as content_type,
d.updated_at as updated_at, s.name as category, s.description as content
FROM DOCUMENTS d, SUBJECTS s
WHERE d.subject_id = s.id
ORDER BY d.updated_at DESC
FETCH FIRST 10 ROWS ONLY)
AS doc_list;
-- Cursor left open for client application
OPEN cursor1;
END P1 |
이 기능도 저장 프로시저로서 제공하여 Rails 개발자들이 Atom 피드를 생성 시 상세한 부분까지도 신경 쓰지 않도록 하였다.
Listing 23. Atom 피드 저장 프로시저 호출하기
class Document < ActiveRecord::Base
[...]
def atom_feed
feed = Document.find_by_sql("call teamroom.get_atom_feed()")
content = feed[0].attributes["1"]
send_data(content,
:filename => 'TeamRoomFeed.atom',
:type => 'text/xml',
:disposition => "inline")
end
[...]
end
|
DB2 XML 퍼블리싱 함수와 Atom Syndication Format Protocol에 대해서는 이 글에서는 다루지 않겠다. 참고자료 섹션에서 자세한 내용을 참조하기 바란다. 다운로드 할 수 있는 애플리케이션에는 Atom 피드의 완전한 구현이 포함되어 있고, 여기에는 피드를 생성할 수 있는 저장 프로시저와 애플리케이션 코드가 들어있다.
결론
계층적 포맷에 XML 데이터를 저장하는 DB2의 pureXML 기능으로 애플리케이션들은 XML과 쉽게 통신할 수 있고, DB2 관계형 데이터베이스 관리 시스템의 성능, 확장성, 신뢰성, 가용성 혜택도 누릴 수 있다. Ruby on Rails의 단순함과 유연성을 활용하면, 세계적 수준의 Web 2.0 애플리케이션들을 빠르고 쉽게 구현, 전개, 관리할 수 있다. 개발 옵션은 비즈니스가 원하는 대로 관계형 포맷에서부터 계층적 포맷에 이르기까지 정보를 이동할 수 있을 정도로 유연하다. 하나의 데이터 포맷에서 또 다른 포맷으로 이동하는 동안, 성능은 일관성 있게 유지된다. 같은 최적화 기술을 사용하고, DB2 기술의 백업, 복구, 확장성 같은 신뢰성 및 가용성 특성들이 적용되기 때문이다.
DB2 pureXML은 1세대 네이티브 XML 지원뿐만 아니라, 인덱싱과 DB2 쿼리 엔진에 구현된 XQuery와 XPath 프리머티브를 통한 높은 쿼리 성능을 보장하는 노드 레벨의 세분성으로 나중에 파싱된 데이터를 디스크에 저장한다. 이로써 Ruby on Rails 런타임은 친숙한 XML 라이브러리(REXML, ROXML)를 제공할 수 있고, XML 기반 데이터를 웹 애플리케이션에 빠르게 통합할 수 있다.
다운로드 하십시오 | 설명 | 이름 | 크기 | 다운로드 방식 |
|---|
| Team room sample code | Teamroom2.zip | 10KB | HTTP |
|---|
참고자료 교육
-
"DB2와 Ruby on Rails, Part 1: DB2와 Ruby on Rails 시작하기 (한글)"
(한국 developerWorks, 2007년 7월) DB2 on Rails용 Starter Toolkit를 소개하고, IBM_DB 드라이버를 설치하는 다양한 방법과 DB2로의 Rails 마이그레이션을 설명합니다.
-
"Ruby on Rails and J2EE:Is there room for both?"
(developerWorks, 2005년 7월) 두 개의 웹 애플리케이션 프레임워크 비교: J2EE vs. Ruby on Rails.
-
"Crossing borders: Exploring Active Record"
(developerWorks, 2006년 3월)
-
"Crossing borders: What's the secret sauce in Ruby on Rails?"
(developerWorks, 2006년 5월)
-
"An introduction to Ruby on Rails for DB2 developers"
(developerWorks, 2006년 6월) Ruby on Rails 단계별 소개 기술자료.
-
"Crossing borders: Rails migrations"
(developerWorks, 2006년 8월)
-
"RadRails와 Eclipse로 Ruby on Rails를 쉽게! (한글)" (한국 developerWorks, 2007년 5월) Eclipse 기반 개발 툴인 Ruby on Rails의 소개.
-
ActiveRecord association 문서.
-
"From DAD to annotated XML schema decomposition" - Mayank PradhanPradhan (developerWorks, 2006년 4월)
-
Ruby on Rails and XML - Daniel Wintschel (developerWorks, 2007년 4월)
-
DB2 9 pureXML Guide
-
technology bookstore
-
DB2 for Linux, UNIX, Windows 리소스 페이지(developerWorks)
-
DB2 Express-C, DB2 Express Edition의 무료 버전 커뮤니티.
제품 및 기술 얻기
토론
필자소개  | |  | John Chun은 DB2 Advanced Support 팀의 전문가로서, 애플리케이션 개발과 툴링 분야에서 일하고 있다. IBM DBT Toronto 연구실에서 Java, C, C++, Perl, REXX, C#을 포함한 다양한 언어들로 DB2 애플리케이션 문제를 해결하고 있다. DB2 CLI와 OLEDB 드라이버 및 .NET 프로바이더 관련 수 많은 프로젝트를 수행했다. DB2 Certified Solutions Expert 및 Certified WebSphere Administrator이다. |
 | |  | Christine Law는 IBM Toronto Lab, DB2 UDB Advanced Support 팀의 IBM 인증 솔루션 전문가이다. 2001년 IBM에 입사했으며, 4년 이상을 DB2 고객을 위해 일하고 있다. DB2 애플리케이션 개발 분야가 전문이며, 특히 JDBC, SQLJ, 저장 프로시저, 임베디드 SQL을 전문으로 하고 있다. 현재 Ajax와 Ruby 같은 오픈 소스 기술에 관심을 갖고 있다. |
 | |  | Salvador는 캘리포니아 샌호세에 위치한 Silicon Valley Labs에 2002년 입사했다. 초기에는 DB2 z/OS 데이터베이스 제품용 J2EE 애플리케이션들을 개발했다. 현재, DB2 pureXML을 비롯한 IBM의 데이터 서버 제품용 런타임 및 툴링 기술 분야에서 일하고 있다. |
 | |  | Alex Pitigoi는 IBM Toronto Lab의 소프트웨어 엔지니어이다. 1998년 이후 Information Management 분야에서 다양한 소프트웨어 개발 프로젝트에 참여했으며, 웹 기술과 데이터베이스 관리를 전문으로 했다. 최근에는 SQLModel 개발 프로젝트를 이끌었고, 이것은 현재 Eclipse Data Tools Project로 통합되었고, 많은 IBM 데이터 서버들에서 데이터베이스 관리 웹 툴용 아키텍처로서 사용되고 있다. DB2 Satellite Administration Center에서도 일했으며 DB2용 최초의 웹 툴 개발도 이끌었다. 현재 새로운 오픈 소스 기술(Ruby, Python, PHP)을 위한 IBM의 데이터 서버 인에이블먼트에 집중하고 있다. |
기사에 대한 평가
|  |