IT_Programming/XML

[XSLT] for-each를 사용한 loop법

JJun ™ 2007. 9. 30. 13:15

우선 XSLT엔 loop를 쓰기위해 사용할 수 있는 두 가지 방법이 있다.

 

<xsl:for-each>
.........
</xsl:for-each>

<xsl:choose>
----------------------------------------

<xsl:when>
............
</xsl:when>
<xsl:otherwise>
............
</xsl:otherwise>
</xsl:choose>


[특징]

- <xsl:for-each> 는 반드시 노드집합에서만 사용할 수 있다.
- <xsl:choose><xsl:when>은 함께 다니는 태그이며 적어도 노드집합에서는 잘 안쓴다.
  위 둘은 서로 포함시킬 수 있다.
- <xsl:for-each>의 조건문은 select="" 안에서 이뤄진다.
- <xsl:choose><xsl:when>의 조건문은 test="" 안에서 이뤄진다.
- <xsl:choose><xsl:when>의 조건에 예외적인 것은 <xsl:otherwise>로 해결한다.

*** 여기서도 물론 XPath는 중요한 역할을 한다.


먼저 XML문서의 element node를 이용한 loop를 써보자.

다음과 같은 1.xml 문서가 있다.

 

<?xml version="1.0" encoding="euc-kr"?>
<?xml-stylesheet type="text/xsl" href="1.xslt"?>
<list>
 <person num="1">
  <name sex="여자">구영숙</name>
 </person>
 <person num="2">
  <name sex="여자">권경화</name>
 </person>
 <person num="3">
  <name sex="여자">김민영</name>
 </person>
 <person num="4">
  <name sex="남자">김상범</name>
 </person>
 <person num="5">
  <name sex="남자">김상호</name>
 </person>
</list>

 

자.. 이를 모두다 뿌리는 1.xslt 파일은 다음과 같다.

 

<?xml version="1.0" encoding="euc-kr"?>
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
 
<!-- root element  -->
<xsl:template match="/list">
<xsl:for-each select="person">
 <xsl:value-of select="name"/><br/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

 

순서를 바꿔서 뿌리고 싶다면...


<xsl:sort order="desending"/> 을 loop밖에다 뿌려준다.

 

자... 그럼 5명중에 가운데 두 명만 뿌리고 싶다면?
여기서 XPath의 position() 이 역할을 한다.
postion() 은 처리직전에 들어온 xml문서를 위에서 부터 node 번호를 준다. 정렬없이 1.xml 문서를 읽게 된다면 posion()은

 

1:구영숙 , 2:권경화 , 3:김민영 , 4:김상범 , 5:김상호

 

의 번호를 주게 된다.

 

그렇다면 이 position() 과 연산자를 통해서 특정 범위만큼 돌릴 수 있겠다.

 

<xsl:for-each select="person[position() >= 2 and position() < 4]">

 

이렇게 하면 권경화와 김민영만 나온다.

 

XPath에 대해서 잠깐 설명하자면 먼저 template에서 root밑의 list를 찾고 (/list) 그 밑의 자식 노드들 중에서 for-each에서 A[B] 연산자에 의해서 person 노드의 position()를 선택한다.
그리고 이는 XPath의 기준에 의해서 연산자를 통해서 연산이 가능하다. 그래서, 2<= 노드 포지션값<4 의 연산을 한 결과 이다.

이런 식으로 XML문서에 있는 모든 노드들을 컨드롤 할 수 있다.

 

게시물이라면 번호를 줄 수 있지 않을까?

position()을 쓰면 노드값으로 번호를 줄 수 있다.

 

<?xml version="1.0" encoding="euc-kr"?>
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
 
<!-- root element  -->
<xsl:template match="/list">
<xsl:for-each select="person[position() >= 2 and position() < 4]">
 <xsl:value-of select="position()"/> : <xsl:value-of select="name"/><br/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

 

그렇다면 중간에서 뽑게되면 중간에 있는 번호가 나오지 않는가.. -_-;

그렇다면 번호를 거꾸로 뽑고 싶다면?
정렬을 거꾸로 해도 position() 은 연산직전에서 순서를 주기때문에 번호는 그대로 1,2 순차적으로 나온다.

last() 를 쓴다면 해결된다.
last() 는 불려진 노드의 마지막 번호를 결과값으로 준다.
따라서...

 

<?xml version="1.0" encoding="euc-kr"?>
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
 
<!-- root element  -->
<xsl:template match="/list">
<xsl:for-each select="person[position() >= 2 and position() < 4]">
 <xsl:value-of select="last()+1 - position()"/> : <xsl:value-of select="name"/><br/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

 

제법 게시판을 어떠케 구현해야 할지 알 수 있듯 싶지 않은지... (나만그런가.. -_-a ..)
변수를 한 번 써보자...

 

<?xml version="1.0" encoding="euc-kr"?>
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
 
<!-- root element  -->
<xsl:template match="/list">
<xsl:variable name="시작번호" select="2"/>
<xsl:variable name="끝번호" select="4"/>
<xsl:for-each select="person[position() >= $시작번호 and position() < $끝번호]">

 <xsl:value-of select="last()+1 - position()"/> : <xsl:value-of select="name"/><br/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

 

주의점이 있다면 변수를 쓸경우 변수명 앞뒤로 반드시 1개 이상의 공백을 두라는 것이다.
실제 해보면 에러가 나는걸 확인 할 수 있다.

 

ps.

for-each는 XPath의 검색값에 의해서 원하는 정보만 뽑아낸다. 뭐 mysql의 Limit와 같은 역할을 해낸다고 보면된다. 그런점에서 XML파일을 전체 다 불러다가 뽑아내줄 필요가 없어서 하나의 게시판을 단일 XML파일에 다 밀어 넣어도 문제가 없을 것 같다.