Google 따라잡기(4)



2.4.XSLT


XML은 몇 년 전부터 아주 다양한 형태로 사용되고 있다. XML의 편의성은 사용자가 XML로 구성되어있는 데이터를 다시 가공하여 사용하기가 쉽기 때문이다. XML데이터를 쉽게 사용할 수 있도록 도와주는 파서들이 언어별로 잘 만들어져 있다. 그래서 XML로 작성된 데이터 덩어리에서 검색, 수정, 추가, 삭제 등의 작업을 간편하게 수행 할 수 있다.
XML을 설명하는 책의 대부분에서 XML과 Database에 관련된 내용들이 있다. 프로젝트에서 사용되는 XML데이터는 데이터 덩어리이다. XSLT는 데이터 덩어리에서 필요로 하는 데이터만을 뽑아내고 재구성하여 새로운 문서를 만들 수 있다. Michael Kay는 XSLT Programmer's Reference에서 다음과 같이 서문을 시작하고 있다.


XSLT를 처음 대했을 때 단지 데이터의 저장과 전송을 위한 포맷이었던 XML을 융통성 있고 선언적인 방법을 통해서 쿼리를 주어 다룰 수 있는, 살아있는 정보의 원천으로 바꾸어 줄 고수준의 데이터 입출력 언어로서 웹을 위한 SQL이 될 것이라는 것을 느꼈다.


Ajax모델에서 XSLT는 웹서버로부터 받은 XML데이터를 이용하여 HTML문서를 만들 수 있다. 책에서도 설명하듯이 XSLT를 이용해서 만들어 낼 수 있는 결과물은 HTML문서에만 국한되는 것이 아니라. 다양한 형태의 결과물을 작성할 수 있다. 이번 장에서는 이런 XSLT에 관한 간략한 설명을 하도록 하겠다.


(1) MSXML 4.0 SDK 다운로드


Microsoft XML Core Services (MSXML) 4.0을 설치하면 Parser와 XML에 관한 도움말이 설치된다. XSLT에 관련된 사항은 . MSXML 4.0 SDK -> XSLT Developer's Guide -> Concepts -> Understanding the XSLT Process에서 확인할 수 있다.


(2) XSLT 처리과정


Understanding the XSLT Process를 보면 XML파일을 XSLT파일로 처리과정을 거치면 텍스트의 결과물이 생성된다. 가공하려는 원본 XML파일은 XSLT파일에 작성되어있는 처리규칙에 따라서 새로운 결과물을 생성한다. XSLT를 사용하면 원본 데이터에 추가, 삭제, 수정이 가능하면 데이터의 순서를 변경할 수 도 있다. XSLT의 기본 처리방식은 template형식을 정의하게 된다. Template에는 원본파일의 어느 부분을 정의한 템플릿으로 처리할지를 결정하는 조건이 있으며, 조건을 만족한 템플릿의 내용을 정의하는 부분으로 구성된다. XSLT파일에 정의된 템플릿은 소스파일에서 템플릿 조건을 만족하는 엘리먼트를 이용해서 템플릿 결과물을 만든다. 템플릿 정의의 조건을 만족하는 모든 엘리먼트에 템플릿을 적용하고 텍스트 스트림의 결과물을 만든다.


(3) XSLT파일


XSLT파일은 하나의 XML문서이다. MSXML 4.0 도움말에서 XSLT Document Map를 찾으면 XSLT문서의 구성을 확인 할 수 있다. 문서는 XML정의에서부터 xsl:엘리먼트의 정보를 하이퍼텍스트 형태로 확인해 볼 수 있다. 연결된 정보가 있는 엘리먼트에 마우스커서를 가져가면 마우스 커서가 손가락 모양으로 바뀌면서 링크된 정보가 있다는 것을 알려준다.


(4) Sample Files for the XSLT Document Map



MSXML 4.0에서 XSLT를 이용해서 HTML결과물을 만들어 내는 예제를 확인 할 수 있다. 간단한 예제는 아니지만 많이 사용하는 XSLT 기술을 사용하고 있어서 XSLT를 이해하는데 많은 도움을 준다.
문서는 세 개로 구성되어있다. 원본 XML데이터인 books.xml파일, 보조 XML데이터인 Ancillary.xml파일 그리고 변환을 정의하고 있는 books.xsl파일이다.


원본 XML파일은 책의 카탈로그 정보(저자, 제목, 종류, 가격, 출판일, 설명)를 가지고있다. 각 책의 정보를 가지는 <book>에는 책을 구별해 주는 id속성값을 가지고 있다. <book>엘리먼트가 모여서 <catalog>를 구성하고 있다. <?xml-stylesheet type="text/xsl" href="books.xsl"?> 처리명령어는 XML문서를 읽어들인 브라우저에게 변환정보를 가지고 있는 books.xsl파일을 처리하도록 지시한다.


보조 XML파일인 ancillary.xml파일은 저작권에 관한 정보를 가지고 있다. <watermark>,<coryright>엘리먼트를 가진다.


변환정보를 가지고 있는 books.xsl파일은 root엘리먼트로 <xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">을 가진다. XSLT의 네임스페이스를 xsl로 설정한다. <xsl:variable> 를 사용해서 상수변수를 정의한다. <xsl:variable name="ancillary" select="document('ancillary.xml')"/>는 ancillary.xml 문서의 내용을 변수 ancillary에 넣는다. <xsl:template>엘리먼트를 이용해서 세 개의 템플릿을 정의했다. XSLT변환에서 템플릿의 적용은 원본 XML문서의 각 엘리먼트가 <xsl:template>의 select 속성을 만족할 때 템플릿을 수행하게 된다. 또한 <xsl:apply-templates>엘리먼트를 만날 경우 템플릿을 수행하게 된다. <xsl:template> 템플리트 엘리먼트는 변환처리의 흐름을 관리하는 XSLT의 뼈대를 이루고 있다. 템플리트 엘리먼트의 내부에 있는 노드들중 xsl:네임스페이스를 가지고 있는 않은 엘리먼트들은 템플리트 처리결과에 text 스트림으로 그대로 포함되게 된다. 예제에서 결과물을 HTML문서를 만들고 있기 때문에 HTML문서의 스타일시트 및 페이지 구성을 위한 테이블 등의 테그들을 템플릿에 포함하고 있다. xsl:네임스페이스에 정의되어 있는 <xsl:for-each>, <xsl:value-of>, <xsl:if>, <xsl:sort>명령어들로 흐름을 조정하여 사용자가 원하는 문서를 만들어 내게 된다. 뿐만 아니라 텍스트 문자열을 처리하는 함수들도 제공해주고 있다.


XSLT를 이용해서 HTML 문서를 생성할 경우 root템플릿에서 HTML문서의 구조를 생성하고 <xsl:apply-templates>를 이용해서 HTML결과물을 만들어 간다.



<xsl:template match="/">
<html>
<head></head>
<body>
<xsl:apply-templates select=" "/>
</body>
</html>
</xsl:template>

<xsl:apply-templates select=" "/>, <xsl:value-of select=""> 등 XSL 명령어에 select속성을 사용해서 원본 XML문서에서 원하는 데이터를 읽어온다. 여기서 select에 사용되는 형식으로 XPATH를 사용한다.


(5) XPATH


Operators and Special Characters, XPath Examples 단원을 확인하면 XPATH 사용에 대한 간단한 정보를 얻을 수 있다.






books.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="books.xsl"?>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
<book id="bk102">
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-12-16</publish_date>
<description>A former architect battles corporate zombies,
an evil sorceress, and her own childhood to become queen
of the world.</description>
</book>
<book id="bk103">
<author>Corets, Eva</author>
<title>Maeve Ascendant</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-11-17</publish_date>
<description>After the collapse of a nanotechnology
society in England, the young survivors lay the
foundation for a new society.</description>
</book>
<book id="bk104">
<author>Corets, Eva</author>
<title>Oberon's Legacy</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2001-03-10</publish_date>
<description>In post-apocalypse England, the mysterious
agent known only as Oberon helps to create a new life
for the inhabitants of London. Sequel to Maeve
Ascendant.</description>
</book>
<book id="bk105">
<author>Corets, Eva</author>
<title>The Sundered Grail</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2001-09-10</publish_date>
<description>The two daughters of Maeve, half-sisters,
battle one another for control of England. Sequel to
Oberon's Legacy.</description>
</book>
<book id="bk106">
<author>Randall, Cynthia</author>
<title>Lover Birds</title>
<genre>Romance</genre>
<price>4.95</price>
<publish_date>2000-09-02</publish_date>
<description>When Carla meets Paul at an ornithology
conference, tempers fly as feathers get ruffled.</description>
</book>
<book id="bk107">
<author>Thurman, Paula</author>
<title>Splish Splash</title>
<genre>Romance</genre>
<price>4.95</price>
<publish_date>2000-11-02</publish_date>
<description>A deep sea diver finds true love twenty
thousand leagues beneath the sea.</description>
</book>
<book id="bk108">
<author>Knorr, Stefan</author>
<title>Creepy Crawlies</title>
<genre>Horror</genre>
<price>4.95</price>
<publish_date>2000-12-06</publish_date>
<description>An anthology of horror stories about roaches,
centipedes, scorpions and other insects.</description>
</book>
<book id="bk109">
<author>Kress, Peter</author>
<title>Paradox Lost</title>
<genre>Science Fiction</genre>
<price>6.95</price>
<publish_date>2000-11-02</publish_date>
<description>After an inadvertant trip through a Heisenberg
Uncertainty Device, James Salway discovers the problems
of being quantum.</description>
</book>
<book id="bk110">
<author>O'Brien, Tim</author>
<title>Microsoft .NET: The Programming Bible</title>
<genre>Computer</genre>
<price>36.95</price>
<publish_date>2000-12-09</publish_date>
<description>Microsoft's .NET initiative is explored in
detail in this deep programmer's reference.</description>
</book>
<book id="bk111">
<author>O'Brien, Tim</author>
<title>MSXML3: A Comprehensive Guide</title>
<genre>Computer</genre>
<price>36.95</price>
<publish_date>2000-12-01</publish_date>
<description>The Microsoft MSXML3 parser is covered in
detail, with attention to XML DOM interfaces, XSLT processing,
SAX and more.</description>
</book>
<book id="bk112">
<author>Galos, Mike</author>
<title>Visual Studio 7: A Comprehensive Guide</title>
<genre>Computer</genre>
<price>49.95</price>
<publish_date>2001-04-16</publish_date>
<description>Microsoft Visual Studio 7 is explored in depth,
looking at how Visual Basic, Visual C++, C#, and ASP+ are
integrated into a comprehensive development
environment.</description>
</book>
</catalog>


ancillary.xml
<?xml version='1.0'?>
<document>
<watermark>Scootney Publishing</watermark>
<copyright>Copyright 2000, Scootney Publishing. All Rights Reserved.</copyright>
</document>


books.xsl
<?xml version='1.0'?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:variable name="recentdate">2001-01-01</xsl:variable>
<xsl:variable name="ancillary" select="document('ancillary.xml')"/>
<xsl:key name="categ_key" match="book" use="genre"/>
<xsl:key name="author_key" match="book" use="author"/>

<xsl:template match="/">
<html>
<head>
<title>Scootney Publishing: Special Exhibit</title>
<style>
h1 {font-family: Arial,Helvetica,Univers,sans-serif;
font-size: 18pt; background-color: #00CCCC; width: 90%}
h2 {font-family: Arial,Helvetica,Univers,sans-serif;
font-size: 14pt; width: 90%}
h3 {font-family: Arial,Helvetica,Univers,sans-serif;
font-size: 12pt; background-color: gold;
width: 90%; border-width: 1; border-style: solid}
h4 {font-family: Arial,Helvetica,Univers,sans-serif;
font-size: 11pt; background-color: gold;
width: 33%; border-width: 1; border-style: solid}
</style>
</head>
<body>
<div style="position:absolute;font-size:96;
font-family:Times New Roman;color:#F0F0F0;z-index:-1">
<xsl:value-of select="$ancillary//watermark"/>
</div>
<h1> Scootney Publishing: Special Exhibit Catalog</h1>
<!-- Group by catalog in first pass, then by author. -->
<xsl:apply-templates select="catalog" mode="grp_categ"/>
<xsl:apply-templates select="catalog" mode="grp_author"/>
<p/>
<div style="font-size:9">
<xsl:value-of select="$ancillary//copyright"/>
</div>
</body>
</html>
</xsl:template>

<xsl:template match="catalog" mode="grp_categ">
<h2>Titles Grouped by Genre</h2>
<xsl:for-each select="book[count(. | key('categ_key', genre)[1])=1]">
<h3> <xsl:value-of select="genre"/></h3>
<xsl:for-each select="key('categ_key', genre)">
<xsl:sort select="title"/>
<table border="0" width="75%">
<tr>
<th width="10%" align="right">Title</th>
<td width="90%" align="left"><xsl:value-of select="title"/></td>
</tr>
<tr>
<th width="10%" align="right">Author</th>
<td width="90%" align="left"><xsl:value-of select="author"/></td>
</tr>
<tr>
<th width="10%" align="right">Copyright</th>
<td width="90%" align="left">
<xsl:value-of select="publish_date"/>
<xsl:if test="substring(publish_date,1,4) >= substring($recentdate,1,4)">
  <b>new</b>
</xsl:if>
</td>
</tr>
<tr>
<th width="10%" align="right">Price</th>
<td width="90%" align="left"><xsl:value-of select="price"/></td>
</tr>
<tr>
<th width="10%" align="right" valign="top">Summary</th>
<td width="90%" align="left"><xsl:value-of select="description"/></td>
</tr>
</table>
<hr width="75%" align="left"/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>

<xsl:template match="catalog" mode="grp_author">
<h2>Titles Grouped by Author</h2>
<xsl:for-each select="book[generate-id() = generate-id(key('author_key', author)[1])]">
<xsl:sort select="author"/>
<h4> <xsl:value-of select="author"/></h4>
<xsl:for-each select="key('author_key', author)">
<xsl:sort select="title"/>
 <xsl:value-of select="title"/><br/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>

</xsl:stylesheet>

트랙백

이 글과 관련된 글 쓰기 (트랙백 보내기)
TrackbackURL : http://getorey.egloos.com/tb/1085494 [도움말]

덧글

덧글 입력 영역


메모장

자신과의 약속을 지키자.