본문 바로가기

Develop/XML & XSL

XSL 간단정리

개요

XSL에 대한 간단한 내용 정리이다. 자세한 내용이 없어서 처음 접하시는 분은 어려울 수도 있다.

마지막에 참고에 관련 강좌 링크를 넣어두었으니 더 자세한 내용이나 설명이 필요하신 분은 참고하시기 바랍니다.


XSL은 eXtensible Stylesheet Language의 약자입니다. XML에 대한 스타일쉬트(shtylesheed)라고 합니다.

다시 말하면 XML을 XSL 통해서 다른 XML(혹은 HTML)로 변환하는 역활을 합니다. 다른 예를 들면 Database에 있는 자료를 쿼리로 불러서 원하는 데이터로 가공하는 부분이라고 보면 되죠. Database가 입력 XML문서가 되고 가공되어 나오는 부분이 다른 XML이나 HTML 문서라고 할 수 있겠네요.


더 정확한 XSL에 대한 내용은 아래 참조에서.. (좀 무책임한 듯.. ㅡ.ㅡ;)



기본 구조

XML 은 알고 있다고 간주하고  바로 XSL로 들어갑니다. XSL은 XSLT와 XPath, XSL-FO인 3 부분으로 구성되어 있습니다.  XSLT은 실제 변환하는 부분이고 XPath은 입력 XML에서 원하는 값 위치를 표시하는 형식이다. XSL-FO는 XSL Formatting Objects로 화면이나 다른 출력를 위한 XML 데이터 포멧을 표현한다.


XSLT의 기본 구조를 먼저 살펴보자.

  • XML 형식 선언
  • XSL shtylesheet 선언 (root element)
  • template 선언


크게 위의 3부분이 기본이다. template 선언은 root element인 XSL shtylesheet 밑에 자식 노드로 선언된다.

간단한 예를 보자.


<?xml version="1.0" encoding="ISO-8859-1"?>  <!-- 필수는 아니지만 넣어두는게 좋다. -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- 위의 stylesheet대신에 아래 transform으로 사용할 수도 있다. 그냥 위의 shtylesheet로 쓰자. -->
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 
<xsl:tempalte>
<!-- 기타등등 -->
</xsl:template>
 
</xsl:stylesheet> <!-- transform으로 사용하면 일치시켜줌 -->


XSLT 구성 elements 종류

  • <xsl:template>
    템플릿을 만들기 위한 기본 element. match 속성이 기본으로 사용됨
  • <xsl:variable>
    XSLT에서 사용할 변수를 선언하고 값을 초기화
  • <xsl:value-of>
    입력 XML에서 값을 획득하는데 사용
  • <xsl:for-each>
    반복 순환문으로 XML에 있는 다수의 지정된 elements을 가져와서 처리 가능
  • <xsl:if>
    조건에 따라서 구문 실행 여부 결정
  • <xsl:choose>
    if문과 비슷하지만 조건이 여러 개로 여러 구분 실행 판단
  • <xsl:sort>
    출력 결과를 정렬
  • <xsl:apply-template>
    현재 element와 자신 element에 해당 xml template을 적용?
  • 기타 등등


사용할 입력 XML 데이터

아래는 2개 cd elements만 있다. 모든 내용은 cdcatalog.xml 을 참고하기 바란다.[2] 자료는 w3schools.com에 있는 XML를 사용하였다.

<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
    <cd>
        <title>Empire Burlesque</title>
        <artist>Bob Dylan</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>10.90</price>
        <year>1985</year>
    </cd>
    <cd>
        <title>Hide your heart</title>
        <artist>Bonnie Tyler</artist>
        <country>UK</country>
        <company>CBS Records</company>
        <price>9.90</price>
        <year>1988</year>
    </cd>
</catalog>


아래에는 위의 XML을 이용한 XSL 내용과 그 결과을 표시하겠다. 자세한 설명은 가급적 생략하며, 필요한 내용은 XSLT을 참고하기 바란다.


<xsl:template>

가 장 기본적인 template을 생각하기 위한 element이다. 다르게 표현하면 XSL의 작업장이라고 보면 된다. 기본적인 attribute(이하 속성)로서 match가 있다. XPath표현에 의해서 입력 XML 데이터에서 필요한 기본 작업 element위치를 지정합니다.

<xsl:template match="/catalog">
</xsl:template>


위 의 match에 의해 root element에서 catalog element을 현재 작업 element위치로 지정한다. Child element가 cd element가 된다. 이하 모든 element은 template element에 속한다.

즉, 다음 예제는 기본 구성인 template element를 생략해서 표현한다. 위의 template가 기본적으로 적용되었다는 전제 하에 설명하겠다.


<xsl:variable>

XSL에 사용할 임시 변수를 선언(?)하는 element입니다. 필요한 변수를 선언하고 저장할 값을 지정하면 됩니다.

<xsl:variable name="cdTitle" select="cd/title" />
<someElement title="{$cdTitle}">


값은 하나만 저장된다. 다른 element에서 해당 변수를 참고하고 싶다면 "{ }"을 사용하고 접두어로 "$"를 사용해서 표기한다.


<xsl:value-of>

입 력 XML에서 필요한 element의 값을 획득한다. 앞의 variable element은 값을 저장할 뿐, 출력하지는 않는다. value-of element가 출력하는 역활을 가진다. 앞의 variable element에 저장된 값을 참조하는 부분도 같이 살펴보자.

<xsl:value-of select="$cdTitle"/>
<xsl:value-of select="cd/title"/>


앞의 variable이나 value-of나 다른 element에서 사용할 수 있는 함수(?)를 사용할 수 있다. 예를 들어 count(), contains() 등이 있다.

count()은 해당 elements의 하부 elemenet의 개수를 말하며 contains()은 특정 element에 임의 문자열이 포함되었는지 여부를 알려준다.

<xsl:value-of select="count(cd)" />
<xsl:value-of select="contains(cd/title, 'haven')" />


<xsl:for-each>

앞 의 value-of element은 여러 개의 element가 있어서 첫번째 element만 사용할 수 있다. 여러 element가 있을 경우 사용하는게 for-each element이다. 이는 일판적인 프로그래밍 언어에서 사용하는 for 문과 비슷하다. XPath에 지정된 element에 하부 모든 element 값을 순차적으로 얻어서 처리한다. 모든 element은 아래 모든 경로에 해당하는 것이 아니라 바로 밑에 있는 element만 해당된다.

<xsl:for-each select="cd">
  <xsl:value-of  select="title" />
</xsl:for-each>


때에 따라서 특정 값을 검색해서 해당 값이 있는 목록을 처리할 수도 있다.

<xsl:for-each select="cd[year='1985']">
  <xsl:value-of  select="title" />
</xsl:for-each>


<xsl:if>

조건에 의해 다음 구분 처리 여부를 판단한다.  사용하는 속성으로 test가 있으며, test의 결과가 참인지 거짓인지 따라 처리여부를 결정한다. 당연히 참인 경우에만 다음 하부 element를 처리하게 된다.

<xsl:if test=contains(cd/title, 'heaven') >
  <xsl:value-of select="cd/title" />
</xsl:if>


if에 test의 속성에 있는 XPath의 영향은 하부 element에 미치지 않는다. 그래서 value-of의 select에 주의하라.

다른 비교 조건으로 =, !=, >, <을 사용할 수 있다.


<xsl:choose>

다양한 조건에 따라 처리하는 부분을 달리할 수 있는 element이다. when element에 의해 처리되는 부분이 달라진다.

<code><xsl:choose>
  <xsl:when test="cd/year > 1985">
    After
  </xsl:when>
  <xsl:when  test="cd/year > 1980">
    Before
  </xsl:when>
  <xsl:otherwise>
    Others
  </xsl:otherwise>
</xsl:choose>


when element은 여러 개 올 수 있다.


<xsl:sort>

여 러 element에 대해 정렬을 한다. 속성으로 select, order, case-order 등이 있다. order은 정렬 순서로 ascending(오름차순)과 descending(내림차순)이 있고 case-order은 대소분서 정렬 순서로 upper-first을 대문자를 우선순위로 lower-forst은 소문자가 우선순위를 가진다. select은 정렬할 element 값  XPath을 나타난다.

<xsl:for-each select="cd">
  <xsl:sort select="year" order="descending" />
  <xsl:value-of select="title" />
  <xsl:value-of select="year" />
</xsl:for-each>


year에 의해 역순으로 정렬된 element로 처리된다.


<xsl:apply-template>

template emement은 match에 의해서 해당 입력 XML을 수행된다. 좀더 말하면 match에 의해 입력 element에서 루트인경우 template들 중에서 루트와 일치(match)되는 <xsl:template match="/">에 의해서 처리된다. 실제로는 루트에 해당하는 <xsl:template match="/">은 template에서 처음 시작되는 출발점이다. 여기서 apply-template element의 match 속성에 의해서 다른 template element으로 분기할 수 있다.

다음 예제는 template element 에서 시작한다.

<xsl:template match="/">
  <xsl:apply-templates/> <!-- 여러 template을 match 하기 시작한다 -->
</xsl:template>

<xsl:template match="cd"> <!-- 루트에서 cd element에 대해 처리 -->
<!-- cd element의 하위 element에서 title element에 대한 template을 적용(찾음), 없다면 title element의 값을 그대로 표시 -->
<xsl:apply-templates select="title"/><p>
<!-- cd element의 하위 element에서 artist element에 대한 template을 적용(찾음), 없다면 artist element의 값을 그대로 표시 -->
<xsl:apply-templates select="artist"/><p>
</xsl:template>

<!-- apply-templates에 의해서 title element에 해당하는 값을 처리 -->
<!-- title element에 하부 element가 있다면 해당 element에 대해 apply-templates을 적용하면 다른 template을 찾아서 적용함 -->
<xsl:template match="title">
   Title: <xsl:value-of select="."/><p>
</xsl:template>


위의 예제는 루트("/")에서 template을 시작한다. 만약 "/catalog"라고 되면 시작되는 기준 element가 catalog가 된다. 즉 루트 대신에 다른 값을 입력할 수 있다.

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


앞의 예제에서 잘 보면 apply-templates에 의해 artist에 대한 template을 적용하는데 artist에 일치되는 template가 없다. 그렇게 되면 단순히 artist element에 있는 값을 표시한다.

그 리고 전체 element의 트리 구조가 /catalog/cd/title 순으로 되어 있는데, 앞에서 catalog에 대한 template을 찾을 수 없다. 즉 catalog element을 건너뛰고 아래로 일치되는 element가  있는 template을 계속 찾게 된다. template 찾게 된다면 검색 과정을 중지한다. 다시 하위 template으로 검색을 다시 하고 싶다면 apply-templates을 사용하면 된다.

앞의 예에서 아래 catalog에 대한 template을 추가하면, catalog 아래의 cd element에 대한 template 검색이 중지된다.

<xsl:template match="catalog">
</xsl:template>


잘만 사용하면 특정 element에 대한 혹은 특정 element 하위 모든 element에 대한 처리를 분리하여 처리 가능하게 된다. 응용은 알아서... ^^;



XPath 간단한 사용

XSL하면서 XPath는 입력 XML 데이터에서 필요한 element에  값을 획득하기 위한 경로 표기 방식이다. 말이 조금 어렵다.

다 른 예를 들면 위도우에서 특정 파일을 사용하려면 폴더명을 입력해야 한다. 예를 들어 "c:\Windows\System32\cmd.com" 형태로 표시한다. 즉 XPath가 이런 형태로 특정 element로 접근하기 위한 폴더 경로와 파일명 표시하는 방식이라 보면 된다.


먼저 사용할 XML 데이터를 보겠다. 앞의 예는 단순한 예라서 여기서 사용하기에는 적합하지 않다.

<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
    <cd lang="en">
        <title>Empire Burlesque</title>
        <artist>Bob Dylan</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>10.90</price>
        <year>1985</year>
    </cd>
    <cd lang="kr">
        <title>Empire Burlesque</title>
        <artist>밥 딜런</artist>
        <country>미국</country>
        <company>콜럼비아</company>
        <price>15,000</price>
        <year>1985</year>
    </cd>
</catalog>


XSLT에서 <xsl:template>에서 match 속성을 사용해서 XML에 기본 위치를 지정할 수 있다.

<xsl:template match="/catalog">
</xsl:template>


이후 작업에서는 항상 현재 element위치가 "/catalog"가 된다.


template element에서 catalog가 기본 경로로 설정되어 있다면,

title을 접근하는 정식 표현은 child::을 사용하여 하위 element임을 표시한다. 이 child::을 생략할 수도 있다. 기본이 하위 element라고 간주하기 때문이다.

  1. child::cd/title ==> cd/title


XML에서 element 안에 attribute(속성) 값을 접근할 때에는 attribute::를 사용한다. 이를 @으로도 사용할 수 있다.

  1. cd[attribute::lang="kr"]/title ==> cd[@lang="kr"]/title


현재 노드를 self::node()로 접근 가능하며 "."으로도 표현 가능하다.

  1. self::node()/cd/title ==> ./cd/title


부모 노드를 parent::node()로 접근 가능하며 ".."으로도 표현 가능하다.

  1. parent::node()/cd/title ==> ../catalog/cd/title


하위 모든 자식 노드에 추출하는 /descendant-or-self::node()를 사용할 수 있다. 이를 "//"으로도 표현 가능하다

  1. ./descendant-or-self::node()/cd ==> .//cd

    ./descendant::cd/title ==> .//cd/title


루트 노드는 "/"으로 표현한다.

  1. /


모든 element은 "*"으로 표현한다.

  1. ./*


여러 element가 있을 때 접근 방법으로 "[]"을 사용하고 position()을 사용한다. 때로는 position()을 생략할 수 있다.

  1. ./cd[position()=1] ==> ./cd[1]

    ./cd[position()=last()] ==> ./cd[last()]


검색 기능으로 "[]"을 사용해서 자식 element과 비교 조건을 넣으면 된다. 비교에서 값이 아닌 경우는 "!="를 사용하면 된다.

  1. ./cd[title="Empire Burlesque"]


다음은 간단한 활용 예이다.

  1. 영화 목록에서 감독이 "James"라는 모든 영화명를 찾아라
    //movie[director="James"]/title
    해당 감독 영화 개수
    count(//movie[director="James"])



XSL에서 Namespace 사용

간단하게 집고 넘어가자. 대중 무엇인지 알거라고 생각하겠다. ㅡ.ㅡ; 그래서, 바로 예제로 들어가겠다.

Namespace에 대한 일반적인 표기형식은 다음과 같다. xmlns속성에 의해서 XML에서 사용할 namespace을 정의한다.

<prefix:elementName xmlns:prefix="namespace name">


이 부분은 앞의 기본 구조에서 얼피 보았다. 다음 부분이다.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">


xsl이 prefix이고 stylesheet가 elementName이다. 그리고 namespace name가 "http://www.w3.org/1999/XSL/Transform" 이 된다. 전자 prefix은 현재 테그의 namespace 영역을 표시하고 xmlns에 있는 prefix은 새로운 namespace 영역을 나타난다. 여기서 사용한 prefix가 xsl인데, 단순히 현재 XSL 문서의 xsl 공통 namespace라고 보면 된다. 그래서 XSL의 모든 element는 xsl이라는 namespace로 표기된다.


Namespace을 사용하는 이유는 같은 element 명이지만 다른 namespace에서는 다른 의미나 역활을 가질 수 있다. 그래서 이를 구분하기 위해서 사용한다.


다음에는 prefix가 xsl이 아닌 다른 명칭을 사용하는 경우에 대해 좀더 살펴 보겠다.


Default Namespace

Default namespace을 살펴보자. 이는 별다른 namespace을 지정하지 않으면 적용되는 부분이다. 즉 prefix가 없어도 된다.

2개 이상 namespace을 지정할 수 없기 때문에 prefix을 사용해야하지만, 하나의 namespace을 이용해서 표현한다면 이를 사용하는게 편리하다.

<elementName xmlns="http://www.w3.org/1999/xhtml">
  <childElementName />
</elementName>


childElementName은 모두 http://www.w3.org/1999/xhtml의 namespace에 속한다.  elementName이 끝나기 전에 모든 element은 default namespace의 영향을 받는다.


혹 시나 이야기하는 것이지만 xmlns에 있는 주소에 있는 문서에 DTD 형식이 있겠지만, 실제로 대부분 이를 사용해서 문서 validation을 확인하지는 않는다. 즉, 엉뚱한 주소를 넣어도 사용할 수 있다는 의미이다. 그렇지만, 추후 validation에 의해 표기법을 검증하기를 원한다면 정확한 주소를 넣어주는게 중요하다.


Prefix을 사용한 Namespace 지정

다 음은 새로운 namespace인 a을 추가해보았다. 내부적으로 default namespace와 a namespace가 생겼다. 특별한 prefix을 사용하지 않는다면 default  namespace을 가진다. 특정 namespace을 사용하려면 "a"라는 prefix을 element 명 앞이나 attribute 명 앞에 추가하면 된다.

<elementName xmlns="http://www.w3.org/1999/xhtml" xmlns:a="http://microsoft.com/schemas/VisualStudio/TeamTest/2006">
  <childElementName1 attribute1="value"/>
  <childElementName2 a:attribute1="value"/>
  <a:childElementName3/>
</elementName>


한 단계 더 나아가서 XML 데이터에서 namespace을 사용할 경우를 보자. 아래 default namespace로 사용하고 있다.

<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog xmlns="http://some.company/a">
    <cd lang="en">
        <title>Empire Burlesque</title>
        <artist>Bob Dylan</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>10.90</price>
        <year>1985</year>
    </cd>
</catalog>


XSL에서 title 값을 얻어보자.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:a="http://some.company/a">
  <xsl:value-of select="a:cd[@lang='en']/a:title"/>
</xsl:stylesheet>


중요한 부분은 같은 namespace(http://some.company/a) 을 가져야 한다. 즉 XML에서 element에서 사용한 namespace외 XSL에서 XML에 접근할때 사용할 XPath에서 namespace은 일치해야 한다. Prefix을 일치하는게 아니라 namespace 값이 일치해야한다. 즉 입력 XML에 따라서 XSL에서 사용할 namespace를 적절히 선택해야 한다.

주 의: value-of element에서 select속성에서 "@lang='en'"에서 작은 따옴표로 표시했다. 이는 select 속성에 큰 따옴표로 표시하기 때문에, 따옴표에 대한 표기가 충돌하게 된다. 이를 피하기 이해서 작은 따옴표로 사용했다.



결론

지 금까지 XSL에 대해서 알아보았다. XML은 다양한 문서나 데이터를 구조적으로 표현할 수 있다는 점이다. 구조적이다라는 말은 다른 곳에서도 원하는 값을 쉽게 가공할 수 있다는 말도 된다. XML은 사람이 읽기 편한 구조라고  볼  수 있다. 물론 그렇게 만들지 않을 수 있지만, element에 대한 명칭과 element의 시작과 끝 구분이 쉽게 눈에 들어온다. 그러나 실제 프로그램 내부에서 처리하기에는 불필요한 데이터가 많있는건 사실이다. 그리고, 단순 배열형태의 값을 표현하기 위해서는 많은 element가 들어간다. 이를 보완한 부분이 json이다. 물론 용도에 따라서 달라질 수 있다. 그렇다고 해서 XML이 무용지물이 되는건 아니다.

각각의 장단점을 잘 파악하고, 필요한 곳에 최적에 구성을 하면된다. 물론 이런게 어렵지만...


나 름 XML에 대해 중요성도 알기 때문에 XSL에 대해서 더 살펴보고 정리해보았습니다. 여기 있는 내용만으로는 완벽하게 다루지는 못합니다. 아래 참조를 참고하시기 바랍니다. 그리고, 처음 의도는 XSL 실행 결과도 표시할려고 했는데, 시간 부족으로  하기 힘들듯 합니다. 아래 w3schools.com에 가시면 XSL에 대해 온라인으로 바로 실행해서 결과를 확인할 수 있습니다. 부족하거나 잘못된 부분에 대한 메일을 언제나 환영합니다. 모두 즐프하시기 바랍니다.  ospace.


참조

[1]XML 강좌, http://www.w3schools.com/xml/

[2]XSL 강좌1, http://www.w3schools.com/xsl/

[3]XSL 강좌2, http://jamessong.kr/zbxe/hxml/589

[4]XSL-FO 강좌, http://www.w3schools.com/xslfo/

[5]XML 네임스페이스, thankee, http://thankee.tistory.com/62



출처 - http://ospace.tistory.com/472

'Develop > XML & XSL' 카테고리의 다른 글

XSL (eXtensible Stylesheet Language) 이란?  (0) 2016.11.21
xsl arabic RTL 적용 관련  (0) 2016.11.21
XSL 강좌, 레퍼런스,간단한 정리  (0) 2016.11.21