홈페이지 꼭대기로

XSLT Quickly 책 정리

XSLT Quickly?

XSLT를 공부하며 참고한 책인데 상당히 좋다. 예제로배우는 XSLT.
책 표지

실전에서 바로 사용할만한 좋은 예제들이 가득하다. 이책을 보면서, 내용을 텍스트파일로 정리해서 XSL작업이 필요할때 바로바로 검색해서 적용하니 XSL 작성 효율이 좋아졌다. 게다가 많은 좋은 팁들이 같이 들어 있다.

XSLT Quickly 요약

★ XSL 기본 헤더와 푸터

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
...내용...
</xsl:stylesheet>

★ p.40 속성 바꾸기

<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가 들어가게 된다.

★ p.41 속성과 요소간의 변환

<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>

★ p.42 속성값에 따라 요소 선택하기

어떤 요소가 특정 속성을 가질때만 선택하기

<xsl:template match="wine[@grape='Cabernet']">
  <xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>

★ p.50 XPath의 로케이션 스텝

child::wine[last()]
축 ::노드테스트[프레디케이트]

Axis ::NodeTest[Predicate]
필수 로케이션 스텝은 노드뿐이다. 축은 보통 생략되는 child로 간주되고 프레디케이트는 조건을 줘서 조건에 맞는 노드만을 취사 선택하는데에 사용한다. 프레디케이트는 문서의 맨위부터 따지는 것이 아니라 현재 컨텍스트 노드 자신과 가까운쪽이 1 가장 먼쪽이 last()가 된다.

★ p.50 컨텍스트(Context) 노드란?

현재 처리중인 노드를 의미한다.

★ p.51 축(Axis)?

축 한정자는 선택될 노드와 컨텍스트 노드 사이의 위치 관계를 지정한다.
종류 :

child, descendant, parent, ancester, following-sibling, preceding-sibling,
following, preceding, attribute, name-space, self, descendant-or-self, ancestor-or-self

★ p.52 부모 노드의 속성을 표시하기

<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>

★ p.53 child 축의 축약형

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"/>로 대신할 수 는 없다.

★ p.53 수식의 처리

수식을 계산하거나 어떤 노드의 값을 <xsl:value-of/>가 아닌 방법으로 얻으려면 {}사이에 넣으면 된다. {}내부에 있는 값을 계산된뒤에 입력된다.

★ p.55 ancestor 축

<A>
  <B>
    <C/>
  </B>
</A>

가 있을때 <C>의 ancestor는 <A>, <B>를 의미한다. ancester:A 와 같은 형식으로 지정하면 된다.

★ p.56 ancestor-or-self 축

<A>
  <B>
    <C/>
  </B>
</A>

가 있을때 <C>의 ancestor-or-self는 <A>,<B>,<C>이다.

★ p.56 자기 자신 혹은 자기의 부모가 가진 특정 속성의 값을 조건으로 줄때,

<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위치의 속성이된다.

★ p.58 preceding-sibling / following-sibling

자기와 동일한 부모 밑에 있는 노드들 중, 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()로 한다.

★ p.61 preceding과 following

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>

★ p.65 descendant와 descendant-or-self

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 속성의 값을 출력한다.

★ p.69 descendent-or-self 의 축약

★ p.70 self

self 는 컨텍스트 노드 그 자신이다. 이것의 축약은 . 으로 self:node()를 의미한다.

★ p.70 namespace

이것은 기본 xml 네임스페이스와 컨텍스트 노드의 범위 안에 있는 모든 네임스페이스로 구성된다. (표준은 xml 네임스페이스를 포함해야 하지만 그렇지 않은 것도 있다.)

<xsl:template match="test">
  <xsl:for-each select="namespace::*">
    <xsl:value-of select="name()"/>
    <xsl:text>
    </xsl:text>
  </xsl:for-each>

★ p.72 노드 테스트(Node test)

* 은 모든 요소(Element) 노드를 의미한다. node() 는 종류에 상관없는 모든 노드를 의미한다. 이것은 주석이나 PI등도 포함한다.

<xsl:for-each selec="node()">
  <xsl:value-of select="." />
</xsl:for-each>

★ 프레디케이트(Predicate)

프레디케이트는 참/거짓의 값만 가진다.

★ p.77 손자 노드의 조건에 따라 자식 노드의 값출력

<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>

★ p.83 동적으로 태그 생성

<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>

★ p.84 <xsl:apply-templates>는 현재 노드의 자식 노드만을 다룬다.

이것은 자식 노드들이 <xsl:template>을 갖고 있지 않을 경우 그 노드의 값을 취해서 추가해준다. 이것을 내장 템플릿 룰이라고 한다.

★ p.86 부모, 자식, 형제의 값 얻기, 노드의 이름얻기

<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>

★ p.89 정해지지 않은 자기 형제 참조

<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는 기본적으로 선택된 노드들 중 첫번째 것만 반환한다.

★ p.92 요소를 속성으로 변환하기

" " 내에 <xsl:value-of>를 쓸 수 없다. 그 대신 다음과 같이 사용한다.

<xsl:template match="wine">
  <wine variental="{@grape}" brand="{winery}" year="{../year}"/>
</xsl:template>

★ p.96 요소를 복사하며 속성 추가

<xsl:copy>가 단독으로 쓰이면 컨텍스트 노드의 요소 이름만 복사될 뿐이다. 즉, 태그만 복사되고 태그의 내용은 복사되지 않는다.
다음은, <xsl:copy>와 다른 명령으로 속성과 내용을 복사하는 것이다.

<xsl:copy>
  <xsl:attribute name="date"> <!-- 이것이 속성을 추가해 주는 것이다. -->
    <xsl:value-of select="@date"/>
  </xsl:attribute>
  <xsl:apply-templates/> <!-- 내용복사 -->
</xsl:copy>

★ p.96 컨텍스트 노드를 자식과 속성까지 완전하게 그대로 복사하기

자식과 요소는 물론 PI와 주석, 네임스페이스 등까지 복사한다.

<xsl:template match="wine">
  <xsl:copy-of select="."/>
</xsl:template>

★ p.100 노드의 개수 세기

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>

★ p.103 apply-templates 에서 처리할 노드를 직접 지정하기

<xsl:template match="customer">
  <client>
    <xsl:apply-templates select="lastName"/>
    <xsl:apply-templates select="phone"/>
  </client>
</xsl:template>

만약 여기서 그냥 <xsl:apply-templates/>를 한다면 모든 customer의 자식 노드들의 내용이 여기에 삽입될 것이다. 여기서는 lastName과 phone에만 템플릿을 적용하여 두 자식 노드들의 값만 가져오도록 한다.

★ p.104 동일한 내용(text())를 가진 요소 제거

<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>

★ p.105 동일한 속성을 가진 요소 제거

<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 속성을 비교하여 다르면 참을 리턴한다.

★ p.106 요소와 속성을 동시에 비교하기

<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 속성을 의미한다.

★ p.109 이 노드는 비어 있는가? (text()가 없는가?)

<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 이다.

★ p.116 특정 자식을 갖고 있는 요소의 템플릿

<xsl:output method="text"/>
<xsl:strip-space elements="*"/>

<xsl:template match="setc2[figure]"> <!-- figure라는 자식 노드가 있는가? -->
  <xsl:value-of select="title"/>
  [<xsl:apply-templates/>]
</xsl:template>

★ p.117 노드 내용에 특정한 문자열을 포함한 요소는?

<xsl:template match="para[contains(.,'the')]"> <!-- contains()의 . 을 주의하라. -->
  ** This para has "the" in it: ***
  <xsl:apply-templates/>
</xsl:template>

문자열이 자식 노드에 포함되어 있어도 마찬가지 이다.

★ p.121 새로운 요소와 그 요소의 속성 추가하기

<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"/>

★ p.124 속성의 이름과 값 얻기

<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>

★ p.126 속성의 존재 여부. 속성이 특정한 값을 가지고 있는가?

<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>

★ p.127 속성 그룹(Attribute set) 사용하기

속성 그룹을 만들고 어떤 요소에 한꺼번에 추가시켜 줄 수 있다.

<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>

★ p.129 HTML 주석 출력하기

<xsl:template match="poem">
<html>
  <xsl:comment>Created By FabAutoDocGen release 3</xsl:comment>
  <xsl:apply-template>
</html> </xsl:template>

★ p.131 HTML 주석 사이에 노드의 값 출력하기

<xsl:template match="documentation">
  <xsl:comment><xsl:apply-templates/></xsl:comment>
</xsl:template>

★ p.131 XML파일 자체의 주석 이용하기

<xsl:template match="comment()">
  <xsl:comment><xsl:value-of select="."/></xsl:comment>
</xsl:template>

★ p.136 결과 트리에 엔티티 레퍼런스 삽입

<!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 선언부에 직접 선언해 주어야 한다.

★ p.138 엔티티 레퍼런스 자체를 삽입히기

<!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 가 이 모양 그대로 출력된다.

★ p.142 Namespace 지정

"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>

★ p.147 XML문서를 XSLT로 변환하려면

<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>

★ p.156 해석 불가능한 엔티티(JPG 파일등)의 URI추가

<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"/>

★ p.159 PI 출력

<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 프로세서는 그것을 무시한다.

★ p.161 원본 트리에서 PI 읽고 이용하기

<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>

★ p.164 <xsl:if> 총정리

<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>

★ p.169 <xsl:choose> 총정리

<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 는 최초로 조건을 만족시킨 부분만 실행하고 끝난다.

★ p.170 언제 중괄호{}를 사용하는가?

<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>

★ p. 171 언제 중괄호{}를 사용하면 안되는가?

<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)"/>

★ p.176 <for-each>를 이용한 목차 만들기

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 자식요소들을 모두 가져다가 화면에 표시해준다.

★ p.177 for-each 와 XPath

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는 마찬가지로 어떤 노드들의 집합을 가져오게 하면 그 집합 전체를 가져다 준다.

★ p.180 재귀 호출을 통한 템플릿 반복 수행

<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>

재귀 호출에서 중요한 것은 재귀 호출을 멈출 조건이 언젠가는 반드시 참이 되어야 한다는 것이다.

★ p.184 <xsl:include> 다른 XSL 문서 포함하기

<xsl:include: href="inlines.xsl"/>

<xsl:template match="chapter">
.... 생략

inlines.xsl이 통째로 들어간 것은 아니고, 그 내용만 들어갔다. 다시 말해 그 스타일 시트의 xsl:stylesheet 태그들 사이의 모든 것들이 이 XSL내용에 끼어들어간다.

★ p.186 <xsl:import> 다른 XSL 문서 포함하기

xsl:import는 임포트 시키는 스타일시트에서 임포트된 스타일시트의 명령어들을 재정의할 수 있다. 그 외엔 xsl:include와 동일하다.

<xsl:import href="inlines.xsl"/>

xsl:import 요소는 스타일시트의 XSLT 네임스페이스에 속하는 다른 어떤 요소보다도 앞에 와야 한다.

★ p.192 이름을 가진 템플릿

템플릿에 이름을 주고 마치 함수처럼 호출 할 수 있다.

<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>

★ p.194 <xsl:message>를 이용한 디버깅, Debugging, 디버그

<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 프로세서에 따라 다르다.

★ p.196 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>

★ p.199 템플릿으로 처리하지 않고 지나쳐 버린 요소 확인하기

<xsl:template match="*">
  <h1><xsl:value-of select="name()"/> ELEMENT UNACCOUNTED
  FOR BY STYLESHEET: <xsl:apply-templates/></h1>
</xsl:template>

다른 템플릿에 의해 처리되지 않은 모든 요소들이 <xsl:template match="*">에 의해 처리된다.

★ p.209 확장 요소가 지원되는지 확인하기

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>

★ p.211 내장 확장 함수 사용

확장함수가 지원되는지 확인 한 뒤에 사용하기

<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>

★ p.213 산술 연산 예제(숫자 계산)

<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>

★ p.219 문자열 뽑아내기 함수들

<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>

★ p.220 그외 문자열 함수들

<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()는 주어진 문자열의 앞과 뒷부분에 있는 공백을 없애준다.

★ p.223 text() 사용하기

<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()의 첫번째 인자로 사용되었을 때 노드의 내용을 문자열로 표현한 것을 가리킨다.

★ p.225 두 문자열의 비교

<xsl:if test=". = 'full of Pomp and Gold'">
  a = "full of Pomp and Gold"
</xsl:if>
<xsl:if test=". != ../c">
  a != ../c
</xsl:if>

두 문자열의 같은지 다른지 여부는 = 와 != 를 이용한다.

★ p.228 문자열 치환 템플릿

<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>

★ p.234 변수의 선언과 사용

<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' 가 된다.
변수는 지역성을 갖는다. 동일한 이름을 갖더라도 선언 지역이 다르면 다른 변수이다.

★ p.237 변수를 사용하여 문자열을 오른쪽으로 정렬하기

<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>

★ p.238 매개변수(parameter)

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 문자열 치환 템플릿 참조

★ p.248 Key(키)에 의한 검색

(키,값)의 쌍으로 정보를 구성하여 키에 의해 값을 검색하는 구조

<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"/>

★ p.253 마지막 figure 자식 노드의 마지막 title 요소의 값 얻기

<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>

★ p.254 알파벳 순으로 처음과 마지막 노드 얻기

<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>

★ p.255 자식 요소의 값에 따라 정렬한 뒤 맨 처음과 마지막 노드 얻기

<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>

★ p.267 HTML 형식으로 출력

XSTL 형식으로 출력되는 결과물은 Text를 제외하고 well-formed 형식을 따라야 한다. 하지만 HTML은 well-formed 태그를 제대로 인식하지 못한다. 그의 해결책으로 XSLT의 xsl:output 요가 있다. 이 요소의 method 속성에 "html" 이라고 쓰면 XSLT 프로세서는 결과물을 만들때 XHTML형식으로 만들지 않고 HTML로 만든다. 그러마 XSLT 문서 작성시에는 well-formed로 만들어야 한다.

<xsl:output method="html"/>

★ p.270 XML 파일에 자신을 처리할 XSL 지정하기

<?xml version="1.0"?>
<?xml-stylesheet href="haha.xsl" "type="text/xsl"?>
<root>
등등...

모질라 1.4, IE 6.0 에서 모두 잘 보였슴.

★ p.274 한 XSLT문서로 여러 XML 문서 처리

<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>

★ p.275 다른 XML문서의 일부 노드만 가져오기

<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>

★ p.276 다른 XML문서를 가져와 Key로 이용하기

<!-- 다른 문서 삽입. 이 문서에 <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>

★ p.279 mode를 이용해 한 노드집합에 두 개 이상의 템플릿 정의 - 차례와 목록 만들기

<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>

★ 일반 Text 결과물 만들기

★ p.286 번호 붙이기(Numbering)

<!-- 일반적인 방법. 항목 앞에 숫자와 점 공백 넣기 -->
<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를 넘는 숫자에 대해서 세 자리마다 콤마를 찍어준다.

★ p.290 multiple 넘버링

<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

★ p.293 여러 단계의 노드에 대해 multiple 넘버링

<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

★ p.294 노드의 깊이에 관계 없이 문서 전체에 걸쳐 순차적인 넘버링

<xsl:template match="figure">
  <xsl:number format="1. " level="any"/><xsl:apply-templates/>
</xsl:template>

figure가 어느 노드의 자식이든지 간에 번호가 순서대로 먹여 진다.

★ p.295 노드의 깊이에 관계 없고, 특정 조상 태그마다 번호를 다시 시작하는 넘버링

<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 요소의 위치를 계산한다.

★ p.301 숫자에 의한 정렬 / 역순 정렬

<xsl:template match="employees">
  <xsl:apply-templates>
    <xsl:sort select="salary" data-type="number" order="descending"/>
  </xsl:apply-templates>
</xsl:template>

★ p.301 다중 정렬

<xsl:template match="employees">
  <xsl:apply-templates>
    <xsl:sort select="last"/> <!-- last/first는 요소의 이름임 -->
    <xsl:sort select="first"/>
  </xsl:apply-templates>
</xsl:template>

★ p.303 속성에 의한 정렬(날짜 순)

<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>

★ p.305 손자 요소에 의한 정렬

<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와 함께 쓸때 강력해진다.

★ p.313 XML문서 생성하며 Doctype 삽입

<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에 모든 선언을 넣어야 한다.

★ p.315 XML 선언 넣기

<xsl:output method="xml" version="1.0" encoding="utf-8"/>

위 선언에 의해 생성된 xml 파일은 다음으로 시작된다.

<?xml version="1.0" encoding="utf-8"?>

★ p.316 XML 선언 빼기

자동으로 들어가는 선언을 빼려면..

<xsl:output method="xml" omit-xml-declaration="yes"/>

★ p.318 특정 요소가 갖고 있는 불필요한 공백을 문서 전체에 걸쳐 제거

<xsl:strip-space elements="color"/>

<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>

위의 스타일 시트는 원본 XML에서 color 요소의 공백을 제거하고 모든 내용을 그대로 복사한다.

★ p.320 공백 그냥 놔두기

<xsl:strip-space elements="*"/> <!-- 모든 요소의 공백을 제거하라 -->
<!-- codeListing과 sampleOutput만 빼고 -->
<xsl:preserve-space elements="codeListing sampleOutput"/>

★ p.321 들여쓰기(indentation) : xml 문서를 적당히 들여쓰기 한다.

<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>

indent="yes"에 의해 들여쓰기가 된다.

★ p.326 공백과 개행문자, Tab문자 처리

공백과 개행문자를 엔티티로 선언하면 사용하기 쉽다.

<!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>

★ p.334 유일한 ID 생성

<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>

★ p.336 generate-id()를 이용한 문서내 자동 링크 생성

<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="불필요한 노드"/>