XSLT를 공부하며 참고한 책인데 상당히 좋다. 예제로배우는 XSLT.
실전에서 바로 사용할만한 좋은 예제들이 가득하다. 이책을 보면서, 내용을 텍스트파일로 정리해서 XSL작업이 필요할때 바로바로 검색해서 적용하니 XSL 작성 효율이 좋아졌다. 게다가 많은 좋은 팁들이 같이 들어 있다.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
...내용...
</xsl:stylesheet>
<wine price="1" year="1997">Carneros</wine>
↓
<wine vintage="1997">Carneros</wine>
<xsl:template match="wine">
<wine vintage="{@year}">
<xsl:apply-template/>
</wine>
</xsl:template>
속성이나 요소를 삭제할때는 그냥 언급을 회피하면 될뿐... @문자는 지정한 이름을 가지는 속성의 값을 의미한다.
{} 중괄호는 XSLT가 그 안의 내용을 글자 그대로 가져오지 않고 수식으로서 연산 한 뒤에 가져오도록 지정하는 것이다. {2 + 2}라고 하면 4가 들어가게 된다.
<wine grape="Chardonnay">
<product>Carneros</product>
<year>1997</year>
<price>10.99</price>
</wine>
↓
<wine vintage="1997">
<product>Carneros</product>
<category>Chardonnay</category>
<price>10.99</price>
</wine>
<xsl:template match="wine">
<wine vintage="{year}">
<product><xsl:apply-templates select="product"/></product>
<category><xsl:value-of select="@grape"/></category>
<price><xsl:apply-templates select="price"/></price>
</wine>
</xsl:template>
어떤 요소가 특정 속성을 가질때만 선택하기
<xsl:template match="wine[@grape='Cabernet']">
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>
child::wine[last()]
축 ::노드테스트[프레디케이트]
Axis ::NodeTest[Predicate]
필수 로케이션 스텝은 노드뿐이다.
축은 보통 생략되는 child로 간주되고 프레디케이트는 조건을 줘서 조건에 맞는 노드만을 취사
선택하는데에 사용한다.
프레디케이트는 문서의 맨위부터 따지는 것이 아니라 현재 컨텍스트 노드 자신과 가까운쪽이 1
가장 먼쪽이 last()가 된다.
현재 처리중인 노드를 의미한다.
축 한정자는 선택될 노드와 컨텍스트 노드 사이의 위치 관계를 지정한다.
종류 :
child, descendant, parent, ancester, following-sibling, preceding-sibling,
following, preceding, attribute, name-space, self, descendant-or-self, ancestor-or-self
<wine grape="Cabernet">
<year>1998</year>
<prices>
<list>13.99</list>
<discounted>11.99</discounted>
</prices>
</wine>
현재 컨텍스트 노드가 prices 일때, 여기에 부모노드(<wine>)의 속성을 표시하려면,
<xsl:template match="prices">
parent element's grape:
<xsl:value-of select="parent::wine/attribute::grape"/>
</xsl:template>
parent와 attribute는 각각 .. 와 @ 로 축약해서 표현할 수 있다.
<xsl:template match="prices">
parent element's grape:
<xsl:value-of select="../@grape"/>
</xsl:template>
XPath에서 축이 생략되면 무조건 child 축의 생략으로 간주한다. <wine>을 처리하는 도중 그의 자식노드인 year의 값을 가져오려면,
<xsl:template match="wine">
<wine vintage="{child::year}">
</xsl:template>
혹은, 축 한정자가 생략되면 무조건 child로 간주하므로,
<xsl:template match="wine">
<wine vintage="{year}">
</xsl:template>
{year}부분을 <xsl:value-of select="year"/>로 대신할 수 는 없다.
수식을 계산하거나 어떤 노드의 값을 <xsl:value-of/>가 아닌 방법으로 얻으려면 {}사이에 넣으면 된다. {}내부에 있는 값을 계산된뒤에 입력된다.
<A>
<B>
<C/>
</B>
</A>
가 있을때 <C>의 ancestor는 <A>, <B>를 의미한다. ancester:A 와 같은 형식으로 지정하면 된다.
<A>
<B>
<C/>
</B>
</A>
가 있을때 <C>의 ancestor-or-self는 <A>,<B>,<C>이다.
<xsl:template matching="waring">
<xsl:if test="ancester-or-self::*[@xml:lang][1]/@xml:lang='en'">
<p>Warning!</b><xsl:apply-templates/></p>
</xsl:if>
</xsl:template>
이 경우, 아래부터 위로 검색해나간다. <C>의 위치에서 먼저 <B>를 검사하고 그 다음에 <A>를 검사하므로 만약 xml:lang 속성이 B 와 A에 있을 경우 xml:lang[1]은 B위치의 속성이 검사되게 된다. xml:lang[last]는 A위치의 속성이된다.
자기와 동일한 부모 밑에 있는 노드들 중, preceding-sibling은자기보다 위에 속한 것들이고 following-sibling은 자기보다 아래에 속한 것들이다.
<story>
<chapter>
<title>A</title>Contents A</chapter>
<chapter>
<title>B</title>Contents B</chapter>
<chapter>
<title>C</title>Contents C</chapter>
</story>
↓
chapter
Prev:
Next: B
chapter
Prev: A
Next: C
chapter
Prev: B
Next:
위와 같이 하려면...
<xsl:template match="chapter">
<h3>chapter</h3>Prev: <xsl:value-of select="preceding-sibling::chapter[1]/title"/><br/>
Next: <xsl:value-of select="following-sibling::chapter/title"/>
<xsl:value-of select="./text()"/><br/>
</xsl:template>
preceding-sibling이 프레디케이트를 계산할 때는 자기와 가까운 쪽, 즉 자기 바로 위를 1로 하고, 자기와 가장 먼 맨 위의 것을 last()로 한다.
preceding 축은 문서의 처음부터 컨텍스트 노드 바로 이전까지, following은 컨텍스트 노드 바로 다음부터 문서의 끝까지의 모든 노드를 의미한다. 형제, 부모 할것 없이 다 포함한다. 프레디케이트는 자신과 가까운쪽이 1이다.
<A>
<B>
<C><TITLE>1</TITLE><T/></C>
<C><TITLE>2</TITLE><D><T/></D></C>
<C><TITLE>3</TITLE><C>
<B>
<A>
첫번째 <T>는 <C>의 자식이고 두번째 <T>는 <D>의 자식이다. 여기서 1과 3을 얻으려면,
<xsl:template match="test">
<xsl:value-of select="preceding::C[1]/TITLE"/>
<xsl:value-of select="following::C/TITLE"/>
</xsl:template>
descendant는 컨텍스트 노드의 자식들과 그 자식들의 자식들 등, 컨텍스트 노드의 모든 자식들을 의미한다. descendant-or-self는 말 그대로 자신을 포함한 자손들.
<xsl:for-each select="descendant::figure">
<xsl:value-of select="title"/>
</xsl:for-each>
이것은 자기 아래에 있는 모든 figure 노드에서 title 요소의 값을 가져온다.
<xsl:for-each select="descendant-or-self::*/@author">
<xsl:value-of select="."/>
</xsl:for-each>
자기 자신을 포함하여 그 자식 모두를 검사하여 author 속성의 값을 출력한다.
self 는 컨텍스트 노드 그 자신이다. 이것의 축약은 . 으로 self:node()를 의미한다.
이것은 기본 xml 네임스페이스와 컨텍스트 노드의 범위 안에 있는 모든 네임스페이스로 구성된다. (표준은 xml 네임스페이스를 포함해야 하지만 그렇지 않은 것도 있다.)
<xsl:template match="test">
<xsl:for-each select="namespace::*">
<xsl:value-of select="name()"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
* 은 모든 요소(Element) 노드를 의미한다. node() 는 종류에 상관없는 모든 노드를 의미한다. 이것은 주석이나 PI등도 포함한다.
<xsl:for-each selec="node()">
<xsl:value-of select="." />
</xsl:for-each>
프레디케이트는 참/거짓의 값만 가진다.
<xsl:template match="winelist">
Wines:needing their "discount" value set;
<xsl:for-each select="wine/prices/discounted[not(text())]">
<xsl:value-of select="../../year"/><xsl:text> </xsl:text>
<xsl:value-of select="../../winery"/><xsl:text </xsl:text>
</xsl:for-each>
</xsl:template>
<xsl:element name="ode">내용</xsl:element>
이것은 <ode>내용</ode>를 생성한다.
이것을 이용해 정해지지 않은 동적 태그 생성이 가능해진다. 다음은 poem의 type 속성에 따라 동적으로 태그를 생성한다.
<xsl:template match="poem">
<xsl:element name="{@type}">
<author>John Milton</author>
<year><xsl:value-of select="@year"/></year>
</xsl:element>
</xsl:template>
이것은 자식 노드들이 <xsl:template>을 갖고 있지 않을 경우 그 노드의 값을 취해서 추가해준다. 이것을 내장 템플릿 룰이라고 한다.
<xsl:template match="list">
~~~~~ Start of list element's template ~~~~~
1. List price (current node) : {<xsl:apply-templates/>}
2. Parent element (price) : {<xsl:value-of select=".."/>
3. Grandparent element contents : {<xsl:value-of select="../.."/>}
4. Attribute of grandparent : {<xsl:value-of select="../../@grape"/>}
5. Sibling node {<xsl:value-of select="../discounted"/>}
6. "Uncle" node {<xsl:value-of select="../../product"/>}
7. Parent node's name: {<xsl:value-of select="name(..)"/>}
8. Grandparent node's name: {<xsl:value-of select="name(../..)"/>}
~~~~~ End of list element's template ~~~~~
</xsl:template>
<xsl:template match="item[3]">
~~~ Start of item element's template ~~~
1. This node : {<xsl:apply-templates/>}
2. First node : {<xsl:value-of select="../item[1]/>}
3. Last node : {<xsl:value-of select="../item[last()]"/>}
4. Preceding node : {<xsl:value-of select="preceding-sibling::item[1]"/>
5. Next node : {<xsl:value-of select="following-sibling::item[1]"/>}
6. flavor attriute value of first node : {<xsl:value-of select="../item[1]/@flavor"/>}
~~~ End of item element's template ~~~
xsl:value-of는 기본적으로 선택된 노드들 중 첫번째 것만 반환한다.
" " 내에 <xsl:value-of>를 쓸 수 없다. 그 대신 다음과 같이 사용한다.
<xsl:template match="wine">
<wine variental="{@grape}" brand="{winery}" year="{../year}"/>
</xsl:template>
<xsl:copy>가 단독으로 쓰이면 컨텍스트 노드의 요소 이름만 복사될 뿐이다. 즉, 태그만 복사되고 태그의 내용은 복사되지 않는다.
다음은, <xsl:copy>와 다른 명령으로 속성과 내용을 복사하는 것이다.
<xsl:copy>
<xsl:attribute name="date"> <!-- 이것이 속성을 추가해 주는 것이다. -->
<xsl:value-of select="@date"/>
</xsl:attribute>
<xsl:apply-templates/> <!-- 내용복사 -->
</xsl:copy>
자식과 요소는 물론 PI와 주석, 네임스페이스 등까지 복사한다.
<xsl:template match="wine">
<xsl:copy-of select="."/>
</xsl:template>
count() 함수를 이용한다.
<xsl:template match="employees">
A. Number of employees:
<xsl:value-of select="count(employee)"/>
B. Number of officers:
<xsl:value-of select="count(employee[@officer='yes'])"/> <!-- 'yes' 작은 따옴표! -->
C. Number of employees without 'officer' attribute set:
<xsl:value-of select="count(employee[not(@officer)])"/>
D. Number of comments in 'employees' element:
<xsl:value-of select="count(//comment())"/> <!-- 모든 주석의 개수 -->
</xsl:template>
<xsl:template match="customer">
<client>
<xsl:apply-templates select="lastName"/>
<xsl:apply-templates select="phone"/>
</client>
</xsl:template>
만약 여기서 그냥 <xsl:apply-templates/>를 한다면 모든 customer의 자식 노드들의 내용이 여기에 삽입될 것이다. 여기서는 lastName과 phone에만 템플릿을 적용하여 두 자식 노드들의 값만 가져오도록 한다.
<sample>
<line lid="u1">hello</line>
<line color="red" lid="u2">hello</line>
<line color="blue" lid="u3">hello</line>
<line lid="u4">hello there</line>
<line color="blue" lid="u5">hello there</line>
<line color="blue" lid="u6">hello</line>
</sample>
↓
<sample>
<line lid="u1">hello</line>
<line lid="u4">hello there</line>
</sample>
속성은 아무 관계 없이 노드의 내용이 동일한 것을 제거하려면
<xsl:template match="line">
<xsl:if test="not(. = preceding::line)">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/> <!-- 속성과 노드의 내용 복사 -->
</xsl:copy>
</xsl:if>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="line">
<xsl:if test="not(@color = preceding::line/@color)">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
not(@color = preceding::line/@color) 는 컨텍스트 노드의 color 속성의 값과 현재 노드 위쪽에 존재하는 line 요소의 color 속성을 비교하여 다르면 참을 리턴한다.
<xsl:template match="line">
<xsl:variable name="contents" select="."/>
<xsl:variable name="colorVal" select="@color"/>
<xsl:if test = "not(preceding::line[(. = $contents) and (@color = $colorVal)])">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
not(preceding::line(. = $contents) and (@color = $colorVal)]) 에서 .은 preceding::line 노드를 의미하고, @color 는 preceding::line의 color 속성을 의미한다.
<xsl:template match="sample">
<xsl:choose>
<xsl:when test="normalize-space(.)">
Sample element <xsl:value-of select="@eid"/> isn't empty.
</xsl:when>
<xsl:otherwise>
Sample element <xsl:value-of select="@eid"/> is empty.
</xsl:otherwise>
</xsl:choose>
</xsl:template>
normalize-space(node)는 노드 집합을 문자열로 전환한 후 여러 공백을 하나로 바꾸고, 문자열 앞뒤의 공백을 잘라낸 뒤 문자가 남아 있으면 true 그렇지 않으면 false 이다.
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="setc2[figure]"> <!-- figure라는 자식 노드가 있는가? -->
<xsl:value-of select="title"/>
[<xsl:apply-templates/>]
</xsl:template>
<xsl:template match="para[contains(.,'the')]"> <!-- contains()의 . 을 주의하라. -->
** This para has "the" in it: ***
<xsl:apply-templates/>
</xsl:template>
문자열이 자식 노드에 포함되어 있어도 마찬가지 이다.
<xsl:template match="verse">
<xsl:element name="line"> <!-- <line> 태그가 생성된다. -->
<xsl:attribute name="status">done</xsl:attribute> <!-- <line status="done">
<xsl:attribute name="hue">
<xsl:value-of select="@color"/>
</xsl:attribute> <!-- <line status="done" hue="@color의 값">
<xsl:attribute name="number">
<xsl:value-of select="amount"/>
</xsl:attribute>
<xsl:attribute name="sourceElement">
<xsl:text>src</xsl:text><xsl:value-of select="generate-id()"/>
</xsl:attribute>
</xsl:element>
</xsl:template>
최종 생성 태그는 <line status="done" hue="@color" number="5" sourceElement="srcb2a"/>
<para color="blue" flavor="mint" author="bd">Here is a paragraph.</para>
↓
Color : blue
attribute name: color
attribute value: blue
attribute name: flavor
attribute value: mint
attribute name: author
attribute value: bd
위와 같이 속성의 이름과 값을 얻으려면,
<xsl:template match="para">
Color : <xsl:value-of select="@color"/>
<!-- list the attribute names and values. -->
<xsl:for-each select="@*">
attribute name: <xsl:value-of select="name()"/>
attribute value: <xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
<para color="blue" flavor="mint" author="jm">Here is a paragraph.</para>
↓
There is a flavor attribute
Athor equals "jm"
<xsl:template match="para">
<xsl:if test="@flavor">There is a flavor attribute</xsl:if>
<xsl:if test="@font">There is a font attribute</xsl:if>
<xsl:if test="@author = 'jm'">Author equals "jm"</xsl:if>
</xsl:template>
속성 그룹을 만들고 어떤 요소에 한꺼번에 추가시켜 줄 수 있다.
<xsl:attribute-set name="lineAttrs">
<xsl:attribute name="status">done</xsl:attribute>
<xsl:attribute name="hue">
<xsl:value-of select="@color"/> <!-- 디폴트값. 디폴트 값은 무시될 수 있다. -->
</xsl:attribute>
<xsl:attribute name="number">
<xsl:value-of select="amount"/>
</xsl:attribute>
<xsl:attribute name="sourceElement">
<xsl:text>src</xsl:text><xsl:value-of select="generate-id()"/>
</xsl:attribute>
</xsl:attribute-set>
<xsl:template match="verse">
<xsl:element name="line" use-attribute-sets="lineAttrs">
<xsl:attribute name="author">BD</xsl:attribute> <!-- 디폴트 값을 무시함 -->
<xsl:attribute name="hue">NO COLOR</xsl:attribute> <!-- 디폴트 값을 무시함 -->
</xsl:apply-templates>
</xsl:element>
</xsl:template>
<xsl:template match="poem">
<html>
<xsl:comment>Created By FabAutoDocGen release 3</xsl:comment>
<xsl:apply-template>
</html> </xsl:template>
<xsl:template match="documentation">
<xsl:comment><xsl:apply-templates/></xsl:comment>
</xsl:template>
<xsl:template match="comment()">
<xsl:comment><xsl:value-of select="."/></xsl:comment>
</xsl:template>
<!DOCTYPE stylesheet [
ENTITY ntilde "n"
]>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="test">
<testOut>
The Spanish word for "Spain" is "Espana".
<xsl:apply-templates/>
</testOut>
</xsl:template> </xsl:stylesheet>
스타일시트에 기본적으로 미리 선언된 다섯개의 엔티티(lt, gt, apos, quot, amp)외의 다른 엔티티를 참조하고자 한다면, 그것들을 DOCTYPE 선언부에 직접 선언해 주어야 한다.
<!DOCTYPE stylesheet [
ENTITY ntilde
"<xsl:text disable-output-escaping='yes'>n</xsl:text>"
]>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output doctype-system="testOut.dtd"/>
<xsl:template match="test">
<testOut>
The Spanishword for "Spain" is "Espana"
<xsl:apply-templates/>
</testOut>
</xsl:template>
</xsl:stylesheet>
Espana 가 이 모양 그대로 출력된다.
"xsl"을 XSLT 요소임을 나타내는 접두사로 사용하는 것은 단지 관례일 뿐이다. 다른 것을 지정해도 된다.
<harpo:stylesheet
xmlns:harpo="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<harpo:output method="xml" omit-xml-declaration="yes"/>
<harpo:template match="xdata">
<heading>xdata</heading><harpo:text>
</harpo:text>
<text><harpo:apply-templates/></text>
</harpo:template> </harpo:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xslAlt="http://www.snee.com/xml/dummy"
version="1.0">
<!-- xslAlt를 xsl로 바꿔 출력하라 -->
<xsl:namespace-alias stylesheet-prefix="xslAlt" result-prefix="xsl"/>
<xsl:template match="elementHandler">
<!-- 아래는 <xsl:template match="@element값"> 으로 출력된다. -->
<xslAlt:template match="{@element}">
<xsl:apply-templates/>
</xslAlt::template>
</xsl:template>
<xsl:template match="elementContents">
<xslAlt:apply-templates/>
</xsl:template>
<xsl:template match="ssheet">
<xslAlt:stylesheet version="1.0">
<xsl:apply-templates/>
</xslAlt:stylesheet>
</xsl:template>
<!-- Just copy any other elements, attributes, etc. -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template> </xsl:stylesheet>
<xsl:template match="picture">
<img src=http://img.yahoo.co.kr/blank.gif>
</xsl:template>
picfile 이 XML파일에 다음과 같이 지정되어 있다면
ENTITY ceres SYSTEM "../pics/cerespic.jpg" NDATA JPEG
생략..
<picture picfile="ceres"/>
<xsl:template match="article">
<xsl:processing-instruction name="xml-stylesheet">
<xsl:text>href="headlines.css" type="text/css"</xsl:text>
</xsl:processing-instruction>
<html>
<xsl:apply-templates/>
</html>
</xsl:template>
위의 결과는
<?xml-stylesheet href="headlines.css" type="text/css"?>
xsl:processing-instruction이 트리의 최상위에 위치해서는 안된다. 만약 그것이 xsl:stylesheet 요소의 자식이라면, XSLT 프로세서는 그것을 무시한다.
<xsl:template match="processing-instruction()">
<xsl:copy/>
<xsl:template>
좀더 세밀하게 이용하기
<?xml-stylesheet href="headlines.css" type="text/css"?>
<?smellPlugIn scent="newCar" duration="12secs"?>
와 같은 PI가 있을 때..
<xsl:template match="processing-instruction('xml-stylesheet')">
<stylesheet><xsl:value-of select="."/></stylesheet>
</xsl:template>
<xsl:template match="processing-instruction('smellPlugIn')">
<smellData><xsl:value-of select="."/></smellData>
</xsl:template>
<xsl:template match="poem">
--- Start of "if" tests. ---
<xsl:if test="@author='jm'"> <!-- author 속성이 'jm'인가? -->
1. The poem's author is jm.
</xsl:if>
<xsl:if test="@author"> <!-- author 속성이 존재하는가? -->
2. The poem has an author attribute
</xsl:if>
<xsl:if test="verse"> <!-- verse 자식 요소를 가지고 있는가? -->
4. The poem has at least one verse child element.
</xsl:if>
<xsl:if test="count(verse) > 3"> <!-- 크다. 궂이 > 를 사용안해도 됨 -->
6. The poem has more than 3 verse child elements.
</xsl:if>
<xsl:if test="count(verse) < 3"> <!-- 작다. <를 사용하면 안되! -->
6. The poem has less than 3 verse child elements.
</xsl:if>
<!-- or 조건주기 -->
<xsl:if test="(@author = 'bd') or (@year='1667')>
8. Either the author is "bd" or the year is "1667".
</xsl:if>
<!-- 중첩 if -->
<xsl:if test="@year < '1850'">
9a. The poem is old.
<xsl:if test="@year < '1700'">
9b. The poem is very old.
</xsl:if>
<xsl:if test="@year < '1500'">
9c. The poem is very, very old.
</xsl:if>
</xsl:if> </xsl:template>
<xsl:template match="poem">
<xsl:choose>
<xsl:when test="@year < 1638">
The poem is one of Milton's earlier works.
</xsl:when>
<xsl:when test="@year < 1650">
The poem is from Milton's middle period.
</xsl:when>
<xsl:when test="@year < 1668">
The poem is one of Milton's later works.
</xsl:when>
<xsl:when test="@year < 1675">
The poem is one of Milton's last works.
</xsl:when>
<xsl:otherwise>
The poem was written after Milton's death
</xsl:otherwise>
</xsl:choose> </xsl:template>
xsl:choose 는 최초로 조건을 만족시킨 부분만 실행하고 끝난다.
<xsl:template match="/">
<test>
<xsl:variable name="myVar">10</xsl:variable>
A. <atvtest at1="hello world"/>
B. <atvtest at1="3 + 2 + $myVar"/> <!-- 문자열로 취급됨 -->
C. <atvtest at1="{3 + 2 + $myVar"/> <!-- 식으로 취급됨 -->
D. <atvtest at1="u{3+2}"/> <!-- "u5" 출력 -->
E. <atvtest at1="yo, substring('hello world',7)"/> <!-- 문자열로 취급됨 -->
F. <atvtest at1="yo, {substring('hello world',7)"/> <!-- "yo, world" 출력 -->
</test> </xsl:template>
<xsl:variable name="myVar">10</xsl:variable>
A. <xsl:value-of select="3+2+$myVar"/> <!-- select 안의 내용은 수식으로 취급. {}불가 -->
B. <xsl:value-of select="substring('hello world', 7)"/>
xsl:for-each 명령은 주어진 노드들의 집합에 대하여 같은 명령을 반복적으로 실행시킨다. 이들 노드들을 명시할 때에는 XPath의 축 한정자, 노드 테스트, 프레디케이트 구문들을 그대로 사용할 수 있다.
<xsl:template match="chapter">
Pictures:
<xsl:for-each select="descendant::figure">
<xsl:value-of select="title"/><xsl:test>
</xsl:test> </xsl:for-each> Chapter:<xsl:apply-templates/> </xsl:template>
이것은 figure 요소의 title 자식요소들을 모두 가져다가 화면에 표시해준다.
xsl:tmeplate 요소의 match 속성에 XPath 표현을 사용할 수 있지만, 사실 그 XPath는 패턴이라고 알려진 XPath의 부분집합이라는 제한을 가지고 있는 반면에, xsl:for-each 요소의 select 속성에는 완벽한 XPath 표현이 가능하다.
<xsl:template match="title">
<xsl:text>title ancestors:</xsl:text>
<xsl:for-each select="ancestor::*">
<xsl:value-of select="name()"/>
<xsl:if test="position() != last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="para"/>
xsl:value-of 에게 어떤 노드들의 집합을 가져오게 하면 그것은 단지 그 무리에 있는 첫 번째 노드의 문자열 형식만을 던져준다는 점이다. 이에 반해 xsl:for-each는 마찬가지로 어떤 노드들의 집합을 가져오게 하면 그 집합 전체를 가져다 준다.
<xsl:template name="hyphens">
<xsl:param name="howMany">1</xsl:param>
<xsl:if test="$howMany > 0">
<xsl:text>-</xsl:text>
<xsl:call-template name="hyphens">
<xsl:with-param name="howMany" select="$howMany - 1"/>
</xsl:call-tempalte>
</xsl:if>
</xsl:template>
<xsl:template match="sample">
Print 1 hyphen:
<xsl:call-template name="hyphens"/>
<xsl:with-param name="howMany" select="3"/>
</xsl:call-template>
Print 20 hyphens:
<xsl:call-template name="hyphens">
<xsl:with-param name="howMany" select="20"/>
</xsl:call-template>
Print 0 hyphens:
<xsl:call-template name="hyphens">
<xsl:with-param name="howMany" select="0"/>
</xsl:call-tempalte>
</xsl:template>
재귀 호출에서 중요한 것은 재귀 호출을 멈출 조건이 언젠가는 반드시 참이 되어야 한다는 것이다.
<xsl:include: href="inlines.xsl"/>
<xsl:template match="chapter">
.... 생략
inlines.xsl이 통째로 들어간 것은 아니고, 그 내용만 들어갔다. 다시 말해 그 스타일 시트의 xsl:stylesheet 태그들 사이의 모든 것들이 이 XSL내용에 끼어들어간다.
xsl:import는 임포트 시키는 스타일시트에서 임포트된 스타일시트의 명령어들을 재정의할 수 있다. 그 외엔 xsl:include와 동일하다.
<xsl:import href="inlines.xsl"/>
xsl:import 요소는 스타일시트의 XSLT 네임스페이스에 속하는 다른 어떤 요소보다도 앞에 와야 한다.
템플릿에 이름을 주고 마치 함수처럼 호출 할 수 있다.
<xsl:template name="boldIt"> <!-- 템플릿에 이름을 주었다. -->
<b><xsl:apply-templates/></b>
</xsl:template>
<xsl:template match="winery">
<p><xsl:call-template name="boldIt"/></p> <!-- 템플릿 호출!! -->
</xsl:template>
<xsl:template match="product">
<p><xsl:call-template name="boldIt"/></p>
</xsl:template>
<xsl:template match="year | price">
<p><xsl:apply-templates/></p>
</xsl:template>
<xsl:param name="bodyTextSize">10pt</xsl:param>
<xsl:template match="/">
<xsl:if test="$bodyTextSize != '10pt'">
<xsl:message>bodyTextSize default value overridden with value of
<xsl:value-of select="$bodyTextSize"/>.
</xsl:message>
</xsl:if>
</xsl:appl-templates>
</xsl:template>
xsl:message 의 출력 내용은 XSLT변환의 출력으로 가지 않고 화면에 나온 다든지의 XSLT 프로세서에 따라 다르다.
<xsl:template match="/">
<xsl:if test="not(contains($bodyTextSize, 'pt'))">
<xsl:message terminate="yes">bodyTextSize must be specified in points
(pt).</xsl:message>
</xsl:if>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="*">
<h1><xsl:value-of select="name()"/> ELEMENT UNACCOUNTED
FOR BY STYLESHEET: <xsl:apply-templates/></h1>
</xsl:template>
다른 템플릿에 의해 처리되지 않은 모든 요소들이 <xsl:template match="*">에 의해 처리된다.
XSLT 프로세서가 특정 확장 요소를 구현하지 않았다면, 프로세서는 xsl:fallback 요소의 자식 요소를 찾아 결과 트리에 붙인다.
<saxon:assing name="color">blue<xsl:fallback>
<xsl:message>This XSLT processor doesn't support saxon:assign.
</xsl:message></xsl:fallback>
</saxon:assing>
다른 방법으로 element-available()을 사용한다.
<xsl:choose>
<xsl:when test="element-available('saxon:assign')">
<saxon:assign name="color">blue</saxon:assign>
</xsl:when>
<xsl:otherwise>
<xsl:message>This XSLT processor doesn't support saxon:assign.
</xsl:message>
</xsl:otherwise>
</xsl:choose>
확장함수가 지원되는지 확인 한 뒤에 사용하기
<xsl:choose>
<xsl:when test="function-available('xalan:tokenize')">
<xsl:for-each select="xalan:tokenize(.,',')">
<entry><xsl:value-of select="."/></entry>
</xsl:for-each>
</xsl:when>
</xsl:choose>
<numbers>
<x>4</x>
<y>3.2</y>>
<z>11</z>
</numbers>
↓
A. 4 + 3.2 = 7.2
B. 3.2 - 4 = -0.8
C. 4 * 3.2 = 12.8
D. 11/3.2 = 3.4375
E. 4+3.2*11 = 39.2
F. (4+3.2)*11 = 79.2
G. 11 mod 4 = 3
H. 4 + 3.2 + 11 = 18.2
I. floor(3.2) = 3
J. ceiling(3.2) = 4
K. round(3.2) = 3
L. 11 + count(*) = 14
M. 3.2 + string-length("3.2") = 6.2
N. 11 + "hello" = NaN
<xsl:template match="numbers">
A. 4 + 3.2 = <xsl:value-of select="x + y"/>
B. 3.2 - 4 = <xsl:value-of select="y - x"/>
C. 4 * 3.2 = <xsl:value-of select="x * y"/>
D. 11/3.2 = <xsl:value-of select="z div y"/>
E. 4+3.2*11 = <xsl:value-of select="x+y*z"/>
F. (4+3.2)*11 = <xsl:value-of select="(x+y)*z"/>
G. 11 mod 4 = <xsl:value-of select="z mod x"/>
H. 4 + 3.2 + 11 = <xsl:value-of select="sum(*)"/>
I. floor(3.2) = <xsl:value-of select="floor(y)"/>
J. ceiling(3.2) = <xsl:value-of select="ceiling(y)"/>
K. round(3.2) = <xsl:value-of select="round(y)"/>
L. 11 + count(*) = <xsl:value-of select="11+count(*)"/>
M. 3.2 + string-length("3.2") = <xsl:value-of select="y + string-length(y)"/>
N. 11 + "hello" = <xsl:value-of select="z + 'hello'"/>
</xsl:template>
<xsl:template match="verse">
1. By itself: {<xsl:value-of select="."/>}
2. {<xsl:value-of select="substring(.,7,6)"/>} <!-- 7번째 문자부터 6문자 -->
3. {<xsl:value-of select="substring(.,12)"/>}
4. {<xsl:value-of select="substring-before(.,'dreary')"/>}
5. {<xsl:value-of select="substring-after(.,'desolation')"/>}
</xsl:template>
<xsl:template match="verse">
1. {<xsl:value-of select="concat('length: ', string-length(.))"/>}
2. {<xsl:if test="contains(.,'light')"><xsl:text>light: yes!</xsl:text></xsl:if>}
3. {<xsl:if test="starts-with(.,'Seest')">
<xsl:text>Yes, starts with "Seest"</xsl:text>
</xsl:if>}
4. {<xsl:value-of select="normalize-space(.)"/>}
5. {<xsl:value-of select="translate(.,'abcde','ABCDE')"/>}
</xsl:template>
normalize-space()는 주어진 문자열의 앞과 뒷부분에 있는 공백을 없애준다.
<xsl:template match="binCode">
<productLocation>
<row><xsl:value-of select="substring(text(), 1, 2)"/>
</row>
<shelf><xsl:value-of select="substring(.,3,1)"/>
</shelf>
<prodNum><xsl:value-of select="substring-after(text(), '-')'/>
</prodNum>
</productLocation>
</xsl:template>
여기서 text()와 .은 동일한 역할을 한다. text()는 주어진 컨텍스트 노드의 자식 노드인 텍스트 노드를 가리키고, "."은 substring()의 첫번째 인자로 사용되었을 때 노드의 내용을 문자열로 표현한 것을 가리킨다.
<xsl:if test=". = 'full of Pomp and Gold'">
a = "full of Pomp and Gold"
</xsl:if>
<xsl:if test=". != ../c">
a != ../c
</xsl:if>
두 문자열의 같은지 다른지 여부는 = 와 != 를 이용한다.
<xsl:template name="globalReplace">
<xsl:param name="outputString"/>
<xsl:param name="target"/>
<xsl:param name="replacement"/>
<xsl:choose>
<xsl:when test="contains($outputString, $target)">
<xsl:value-of select="concat(substring-before($outputString, $target), $replacement)"/>
<xsl:call-template name="globalReplace">
<xsl:with-param name="outputString" select="substring-after($outputString, $target)"/>
<xsl:with-param name="target" select="$target"/>
<xsl:with-param name="replacement" select="$replacement"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$outputString"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="text()">
<xsl:call-template name="globalReplace">
<xsl:with-param name="outputString" select="."/>
<xsl:with-param name="target" select="'finish'"/>
<xsl:with-param name="replacement" select="'FINISH'"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="@*|*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:variable name="bodyTextSize">10pt</xsl:variable>
<xsl:template match="winery">
<b><font size="{$bodyTextSize}"><xsl:apply-template/>
<xsl:text> </xsl:text>
<xsl:value-of select="../@grape"/></font><b><br/>
</xsl:template>
<xsl:template match="product">
<i><font size="{$bodyTextSize}">
<xsl:apply-templates/></font></i><br/>
</xsl:template>
<xsl:template match="year | price">
<font size="{$bodyTextSize}"><xsl:apply-templates/></font><br/>
</xsl:template>
결과 트리에 반영되는 요소의 속성값이 변수나 매개변수가 가리키는 값을 넣으려고 할 때, 달러
기호가 붙은 변수가 그대로 찍히지 않게 하기 위해 위 예처럼 중괄호를 사용해야 한다. 속성이
아니라 요소의 내용에서 변수를 참조하기 위해서는 xsl:value-of 구문을 사용해야한다.
* 변수 선언시 select 를 이용하여 동적인 값을 줄 수 있다.
<xsl:variable name="baseFontSize" select="8"/>
<xsl:variable name="bodyTextSize" select="concat($baseFontSize+2, 'pt')" />
여기서 $bodyTextSize는 '10pt' 가 된다.
변수는 지역성을 갖는다. 동일한 이름을 갖더라도 선언 지역이 다르면 다른 변수이다.
<xsl:output omit-xml-declaration="yes"/>
<xsl:variable name="fieldWidth">12</xsl:variable> <!-- 12칸에 맞춰 오른쪽 정렬 -->
<xsl:template match="color">
<xsl:variable name="valueLength" select="string-length(.)"/>
<xsl:variable name="padding" select="$fieldWidth - $valueLength"/>
<xsl:value-of select="substring(' ',1,$padding)"/>
<xsl:value-of select="."/>
</xsl:template>
xsl:param 구문은 xsl:variable과 거의 같지만 한가지 차이점이 있다. 그 값은 단지 디폴트 값으로만 다루어지고, 런타임에서 재정의 될 수 있다.
<xsl:param name="bodyTextSize">10pt</xsl:param> <!-- 10pt는 런타임시 재 지정 될수 있다. -->
<xsl:template match="winery">
<b><font size="{$bodyTextSize}"><xsl:apply-templates/>
<xsl:text> </xsl:text>
<xsl:value-of select="../@grape"/></font></b><br/>
</xsl:template>
지역 매개변수는 p.228 문자열 치환 템플릿 참조
(키,값)의 쌍으로 정보를 구성하여 키에 의해 값을 검색하는 구조
<shirts>
<colors>
<color cid="c1">yellow</color>
<color cid="c2">black</color>
<color cid="c3">red</color>
<color cid="c4">blue</color>
<color cid="c5">purple</color>
<color cid="c6">white</color>
<color cid="c7">orange</color>
<color cid="c7">green</color> <!-- 일부러 위와 동일하게 했슴 -->
</colors>
<shirt colorCode="c4">oxford button-down</shirt>
<shirt colorCode="c1">poly blend, straight collar</shirt>
<shirt colorCode="c6">monogrammed, tab collar</shirt>
</shirts>
↓
blue oxford button-down
yellow poly blend, straight collar
white monogrammed, tab collar
<color>의 @cid를 키로 이용해서 검색하면 <color>노드 자체가 리턴된다. key 검색은 검색된 노드를 반환하는 것이지 문자열(text())을 반환하는 것이 아니다.
<xsl:key name="colorNumKey" match="color" use="@cid"/> <!-- 키 생성 -->
<xsl:template match="colors"/>
<xsl:template match="shirt">
<xsl:value-of select="key('colorNumKey', @colorCode)"/> <!-- key(키이름,키) -->
<xsl:text> </xsl:text><xsl:apply-templates/>
</xsl:template>
또 다른 방식으로 <color>의 text()를 키로 이용하여 <color>노드 얻기
Looking up the color name with the color ID:
c3's color: red
c4's color: blue
c8's color:
c7's color:
orange green
Looking up the color ID with the color name:
black's cid: c2
gray's cid:
위와 같은 결과를 얻으려면,
<xsl:output method="text"/>
<xsl:key name="colorNumKey" match="color" use="@cid"/>
<xsl:key name="colorKey" match="color" use="."/> <!-- color/text()를 키로 이용 -->
<xsl:variable name="testVar">c4</xsl:variable>
<xsl:variable name="keyName">colorKey</xsl:variable>
<xsl:template match="colors">
Looking up the color name with the color ID:
c3's color: <xsl:value-of select="key('colorNumKey', 'c3')"/>
c4's color: <xsl:value-of select="key('colorNumKey', $testVar)"/>
c8's color: <xsl:value-of select="key('colorNumKey', 'c8')"/> <!-- 존재하지 않는 키 -->
c7's color:
<xsl:for-each select="key('colorNumKey', 'c7')">
<xsl:value-of select="."/><xsl:text> </xsl:text>
</xsl:for-each>
Looking up the color ID with the color name:
black's cid: <xsl:value-of select="key($keyName, 'black')/@cid"/>
gray's cid: <xsl:value-of select="key('colorKey', 'gray')/@cid"/>
</xsl:template>
<xsl:template match="shirt"/>
<xsl:value-of select="descendant:figure/title[last()]"/>로는 원하는 결과를 얻을 수 없다.
이 문장은 각 figure 자식노드의 마지막 title 노드를 가져온다.
원하는 결과를 얻으려면,
<xsl:template match="chapter">
<xsl:for-each select="descendant::figure/title">
<xsl:if test="position() = 1"> <!-- 맨처음 figure/title만 가져옴 -->
First figure title in chapter: <xsl:value-of select="."/>
</xsl:if>
<xsl:if test="position() = last()"> <!-- 맨 마지막 figure/title만 가져옴 -->
Last figure title in chapter: <xsl:value-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="chapter">
<xsl:for-each select="descendant::figure/title">
<xsl:sort/>
<xsl:if test="position() = 1"> <!-- 맨처음 figure/title만 가져옴 -->
First figure title in chapter: <xsl:value-of select="."/>
</xsl:if>
<xsl:if test="position() = last()"> <!-- 맨 마지막 figure/title만 가져옴 -->
Last figure title in chapter: <xsl:value-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="employees">
<xsl:for-each select="employee">
<xsl:sort select="salary" data-type="number"/> <!-- 숫자로 간주하고 정렬하라. -->
<xsl:if test="position() = 1">
Lowest salary: <xsl:apply-templates/>
</xsl:if>
<xsl:if test="position() = last()">
Highest salary: <xsl:apply-templates/>
</xsl:if>
</xsl:for-each>
</xsl:template>
XSTL 형식으로 출력되는 결과물은 Text를 제외하고 well-formed 형식을 따라야 한다. 하지만 HTML은 well-formed 태그를 제대로 인식하지 못한다. 그의 해결책으로 XSLT의 xsl:output 요가 있다. 이 요소의 method 속성에 "html" 이라고 쓰면 XSLT 프로세서는 결과물을 만들때 XHTML형식으로 만들지 않고 HTML로 만든다. 그러마 XSLT 문서 작성시에는 well-formed로 만들어야 한다.
<xsl:output method="html"/>
<?xml version="1.0"?>
<?xml-stylesheet href="haha.xsl" "type="text/xsl"?>
<root>
등등...
모질라 1.4, IE 6.0 에서 모두 잘 보였슴.
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="shirts">
<shirts>
<!-- 여기서 xq1.xml 을 읽어서 XSLT적용 -->
<xsl:apply-templates select="document('xq1.xml')"/>
<xsl:apply-templates/>
</shirts>
</xsl:template>
<xsl:tempalte match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="shirts">
<shirts>
<!-- 속성 cid가 'c7'인것만 가저오라. -->
<xsl:apply-templates select="document('xq1.xml')//*[@cid='c7']"/>
<xsl:apply-templates/>
</shirts>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- 다른 문서 삽입. 이 문서에 <color>노드가 있다. -->
<xsl:variable name="colorLookupDoc" select="document('xq1.xsl')"/>
<xsl:key name="colorNumKey" match="color" use="@cid"/>
<xsl:template match="shirts">
<xsl:apply-templates select="$colorLookupDoc"/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="colors"/>
<xsl:template match="shirts">
<xsl:variable name="shirtColor" select="@colorCode"/>
<xsl:for-each select="$colorLookupdoc">
<xsl:value-of select="key('colorNumKey', $shirtColor)"/>
</xsl:for-each>
<xsl:text> </xsl:text><xsl:apply-templates/><xsl:txt>
</xsl:text>
</xsl:template>
<xsl:template match="story">
<html>
<body>
<h1>Table of Conetnts</h1>
<xsl:apply-templates select="chapter/title" mode="toc"/>
<xsl:apply-templates/></body></html>
</xsl:template>
<xsl:template match="chapter/title">
<h2><a name="{generate-id()}"/><xsl:apply-templates/></h2>
</xsl:template>
<xsl:template match="chapter/title" mode="toc">
<p><a href="#{generate-id()}"><xsl:apply-templates/></a></p>
</xsl:template>
<xsl:template match="para">
<p><xsl:apply-templates/></p>
</xsl:template>
<xsl:template match="story/title">
<h1><xsl:apply-templates/></h1>
</xsl:template>
<!-- 일반적인 방법. 항목 앞에 숫자와 점 공백 넣기 -->
<xsl:template match="color">
<xsl:number/>. <xsl:apply-templates/>
</xsl:template>
<!-- 숫자 형식 포맷팅 -->
<xsl:template match="colors">
<xsl:for-each select="color">
<xsl:number format="I. "/><xsl:value-of select="."/> <!-- I. II. III. 형식 -->
</xsl:for-each>
<xsl:for-each select="color">
<xsl:number format="i. "/><xsl:value-of selet="."/> <!-- i. ii. iii. 형식 -->
</xsl:for-each>
<xsl:for-each select="color">
<xsl:number format="A. "/><xsl:value-of select="."/> <!-- A. B. C. 형식 -->
</xsl:for-each>
<xsl:for-each select="color">
<xsl:number format="a. "/><xsl:value-of select="."/> <!-- a. b. c. 형식 -->
</xsl:for-each>
</xsl:template>
<xsl:template match="color">
<xsl:number format="001. "/><xsl:templates/> <!-- 001. 002. 003. 형식 -->
</xsl:template>
xsl:number에 grouping-separator 요소의 값으로 ","를 주고 grouping-size 요소에 3을 할당하면 999를 넘는 숫자에 대해서 세 자리마다 콤마를 찍어준다.
<xsl:template match="color">
<xsl:number level="multiple" format="1. "/>
<xsl:apply-templates/>
</xsl:template>
다음과 같은 형식의 결과를 얻게된다.
1. red
2. green
3. blue
3.1 robin's egg
3.2 haha
4. yellow
<xsl:template match="chapter">
<xsl:number format="1. "/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="sect1">
<xsl:number format="1. " level="multiple" count="chapter|sect1"/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="sect2">
<xsl:number format="1. " level="multiple" count="chapter|set1|sect2"/>
<xsl:apply-templates/>
</xsl:template>
다음과 같은 형식의 결과를 얻게된다.
1.
1.1
1.2
2.
2.1
2.1.1
2.1.2
2.2
<xsl:template match="figure">
<xsl:number format="1. " level="any"/><xsl:apply-templates/>
</xsl:template>
figure가 어느 노드의 자식이든지 간에 번호가 순서대로 먹여 진다.
<xsl:template match="figure">
<xsl:number format="1. " level="any" from="chapter"/>
<xsl:apply-templates/>
</xsl:template>
xsl:number 요소를 자주 사용하면 XSLT 프로세서의 속도가 떨어진다. 되도록 position()을 사용하라.
<xsl:template match="colors">
<xsl:for-each select="color">
<xsl:value-of select="position()"/>. <xsl:value-of select="."/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
여기서 꼭 xsl:for-each를 써야한다. 그냥 xsl:template 을 사용하면 안된다. XSLT 프로세서는 colors 요소들의 자식 요소들 중에 각 color 요소들 사이의 개행문자를 포함하고 있는 텍스트 노드까지 포함하여 각 color 요소의 위치를 계산한다.
<xsl:template match="employees">
<xsl:apply-templates>
<xsl:sort select="salary" data-type="number" order="descending"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="employees">
<xsl:apply-templates>
<xsl:sort select="last"/> <!-- last/first는 요소의 이름임 -->
<xsl:sort select="first"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="employees">
<xsl:apply-templates>
<!-- hireDate는 04/23/1999 형심임 -->
<xsl:sort select="substring(@hireDate, 7, 4)"/> <!-- year -->
<xsl:sort select="substring(@hireDate, 1, 2)"/> <!-- month -->
<xsl:sort select="substring(@hireDate, 3, 2)"/> <!-- day -->
</xsl:apply-templates>
</xsl:template>
<xsl:template match="winelist">
<xsl:copy>
<xsl:apply-templates>
<xsl:sort data-type="number" select="prices/discounted"/> <!-- 손자 요소를
조거으로 -->
</xsl:templates>
</xsl:copy>
</xsl:template>
<xsl:template match="*"
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
xsl:sort는 xsl:for-each와 함께 쓸때 강력해진다.
<xsl:output method="xml" doctype-system="../dtds/docbookx.dtd"
doctype-public="-//OASIS//DTD DocBook XML//EN"/>
<xsl:template match="@*|node()">
어쩌구...
아래 문구가 삽입된다. 아래에서 chapter는 생성될 xml 문서의 root 요소이다.
<!DOCTYPE chapter
PUBLIC "-//OASIS//DTD DocBook XML/EN" "../dtds/docbookx.dtd">
[ ] 안에 DTD 선언을 넣을 수는 없다. System 속성에 있는 외부 DTD에 모든 선언을 넣어야 한다.
<xsl:output method="xml" version="1.0" encoding="utf-8"/>
위 선언에 의해 생성된 xml 파일은 다음으로 시작된다.
<?xml version="1.0" encoding="utf-8"?>
자동으로 들어가는 선언을 빼려면..
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:strip-space elements="color"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
위의 스타일 시트는 원본 XML에서 color 요소의 공백을 제거하고 모든 내용을 그대로 복사한다.
<xsl:strip-space elements="*"/> <!-- 모든 요소의 공백을 제거하라 -->
<!-- codeListing과 sampleOutput만 빼고 -->
<xsl:preserve-space elements="codeListing sampleOutput"/>
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
indent="yes"에 의해 들여쓰기가 된다.
공백과 개행문자를 엔티티로 선언하면 사용하기 쉽다.
<!DOCTYPE stylesheet [
ENTITY space "<xsl:text> </xsl:text>"
ENTITY cr "<xsl:text>
</xsl:text>"
ENTITY tab "<xsl:text> </xsl:text>"
]>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="employee">
<xsl:apply-templates select="@hireDate"/>&cr;
<xsl:apply-templates select="first"/>&space;&tab; <!-- 공백과 탭 삽입 -->
<xsl:apply-templates select="last"/>
</xsl:template>
</xsl:stylesheet>
XML 프로세서는 요소 안에 다른 문자 데이터와 함께 개행 문자가 들어가 있으면 이를 제거하지 않는다. 일반 문자열에서 개행 문자가 작동하지 않게 하려면 <xsl:text>를 이용한다.
<xsl:text>Date</xsl:text>
<xsl:template match="chapter | sect1 | sect2">
<xsl:copy>
<xsl:attribute name="uid">
<xsl:value-of select="generate-id(.)"/> <!-- ID 생성 -->
</xsl:attribute>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:output method="html"/>
<xsl:template match="chapter">
<html> <body >
<!-- Generate a list of picture titles, with each title linking to the picture in the
poem below -->
<b>Pictures:</b><br/>
<xsl:for-each select="descendant::figure">
<a href="#{generate-id(graphic)}">
<xsl:value-of select="title"/></a><br/>
</xsl:for-each>
<xsl:apply-templates/>
</body></html>
</xsl:template>
<xsl:template match="para">
<p><xsl:apply-templates/></p>
</xsl:template>
<xsl:template match="graphic">
<!-- 위에 각 graphic 요소마다 생성된 id와 동일한 id가 생성된다. -->
<center><a name="{generate-id(.)}"><img src=http://img.yahoo.co.kr/blank.gif></a>
<b><xsl:value-of select="../title"/></b></center>
</xsl:template>
<xsl:template match="figure/title"/>
</xsl:stylesheet>
<!-- 아래는 문서 전체를 그대로 복사한다 -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- 아래에 의해 불필요한 노드가 삭제된다. -->
<xsl:template match="불필요한 노드"/>