" xslt(으)로 태그된 글들"

XSLT로 만든 XMLViewer

1 30, 2009   //   alexken작성   //   기술  //  No Comments

xml의 많은 장점에도 불구하고 떨어지는 readability엔 불만이다.
업무상 xml을 자주 만지다 보니 xml 내의 정보를 쉽게 보는 도구가 간절했고, 그래서 예전에 java로 만든 TreeView 형태의 XmlViewer도 만들었다.

이번에는 xlst로 만들었는데 생각보다 깔끔하고 맘에 든다.
TreeView 형태보다 쉽게 포함관계를 표현한다.

맨 처음, element와 attribute를 일일히 지정하면서 xslt를 작성하다 보니 1000라인이 넘어 섰다.
그래서 거의 90% 완성된 시점에서 처음부터 다시 시작해 element와 attribute의 이름을 지정하지 않는 형태로 바꾸었더니 css, javascript를 포함해서 120라인 가량으로 끝낼 수 있을 뿐더러 특정 dtd/schema의 xml 뿐만 아니라 범용 XMLViewer로 사용가능해 졌다.

만들다 보니 포함관계만 표시하는 심플한 뷰, 모든정보를 빠짐없이 보여주는 뷰를 표현하기 위해 javascript를 이용했고 web에서 찾은 코드를 근간으로 했는데
원리는 숨기거나 보여질 영역을 < div class="ClassName" >으로 설정한뒤 해당 class를 가지는 element를 돌면서 처리하는 루틴이었다.

문제는 C 스타일의 for 루프문

for( var i=0; i<Max; i++){
   BLOCK;
}

이 내가 주로 사용하는 브라우저인 safari에서는 돌지 않았다.

그래서

for( var i in Collection){
   BLOCK;
}

형태로 바꿔서 브라우저 의존성을 제거하고,

포함관계를 색상으로 표현하기 위해서 CSS에서

*              {background: none;}
div            {background: #6666ff;}
div>div        {background: #7777ff;}
div>div>div    {background: #8888ff;}

형태로 가능했다.

내가 javascript/CSS 쪽은 거의 문외한이라 이게 최적의 코드인지는 모르지만, 내가 원래 의도했던 기능이나 목표는 다 동작해서 맘에 든다.

그리고 지금까지

< xsl:apply-templates/>

는 select로 자식 element를 지정해야지만 되는줄 알았는데,
그냥 apply-templates만 불러주니 알아서 자식 element들을 알아서 불러주네…(오늘 첨 알았음 ^^;)

Simple View

Complex View

<?xml version='1.0' encoding='utf-8'?>
<xsl:stylesheet version='2.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>

<xsl:template match="/">
<html>
<head>
<title>XML Viewer</title>
<style type="text/css">
div.element{
    float:      left;
    display:    block;
    padding:    1em;    
    border:     solid 1px black;    
    margin:     1em;
}

/*
    element의 이름과 attr을 header-area로 싸는 이유
    attr 옆에 하위 element가 붙는게 보기 싫어서...
    정답은   overflow:auto;
*/
div.header-area{
    overflow:         auto;
    background:  none;
}

div.attr{
    float:            left;
    margin-right:  2em;
    background:  none;
}

i.att_name{ color:  #333333}
i.att_value{ color: #666666}

/*
    nested elemement를 다른 색으로 표시하기
    이게 제일 좋은 방법인지는 모르겠지만...
*/
*                                        {background: none;}
div                                      {background: #6666ff;}
div>div                                  {background: #7777ff;}
div>div>div                              {background: #8888ff;}
div>div>div>div                          {background: #9999ff;}
div>div>div>div>div                      {background: #aaaaff;}
div>div>div>div>div>div                  {background: #bbbbff;}
div>div>div>div>div>div>div              {background: #ccccff;}
div>div>div>div>div>div>div>div          {background: #ddddff;}
div>div>div>div>div>div>div>div>div      {background: #eeeeff;}
div>div>div>div>div>div>div>div>div>div  {background: #ffffff;}
</style>

<script type="text/javascript" language="JavaScript">

    function toggle(obj){
        if(obj.style.display != "block")
            obj.style.display = "block";
        else
            obj.style.display = "none";
    }

    function toggle_all_attr(){
        var divs = document.getElementsByTagName('div');
        var tcl = " attr ";
        for( var i in divs ){
             var test = " " + divs[i].className + " ";
             if(test.indexOf(tcl) != -1){
                toggle(divs[i]);
             }
        }
    }

</script>
</head>
<body>
    <h2><a href="#" onclick="toggle_all_attr()">simple/complex</a></h2>
    <xsl:apply-templates/>
</body>
</html>
</xsl:template>

<!-- element 처리 -->
<xsl:template match="*">
    <div class="element">
   
        <!-- 본인의 attr 처리하고 -->
        <div class="header-area">
            <h3><xsl:value-of select="name(.)"/></h3>
            <xsl:apply-templates select="@*"/>
        </div>

        <!-- sub element들 처리... -->
        <xsl:apply-templates/>
       
    </div>
</xsl:template>

<!-- attribute 처리 -->
<xsl:template match="@*">
    <div class="attr">
        <i class="att_name"><xsl:value-of select="name(.)"/></i><br/>
        <i class="att_value"><xsl:value-of select="."/></i>
    </div>
</xsl:template>
</xsl:stylesheet>

messier 페이지에 type icon 표시 추가

1 10, 2007   //   alexken작성   //   기술, 천문  //  4 Comments

메시에 페이지에 가면 메시에 DB가 있다.
테이블 보기에서는 모든 정보가 보이지만,
촬영 시기별 보기나, 촬영 장비별 보기에서는 대상이 은하인지, 성운인지 알 방법이 없어서,
모든 대상 옆에 icon을 붙였다.
각 대상은 다음과 같다.

  • 행성상 성운/초신성 잔해물 :
  • 성운 :
  • 은하 :
  • 산개 성단 :
  • 구상 성단 :
  • 이중성, 성군(星群), 기타 :

(icon 이미지는 천문노트에 있는 별 있는거 안에 있는 이미지를 편집해서 사용했다.
이 글을 쓰고나서 제작자의 양해를 구해야지…)

messier페이지는 서버에서 html로 렌더링 해서 뿌리기 때문에, 소스보기해도 알 방법은 없지만,
현재는 messier DB를 xml 로 저장해서

<object>
    <num>M1</num>
    <ngc>NGC1952</ngc>
    <const>Taurus</const>
    <constabbr>Tau</constabbr>
    <type>Supernova Remnant</type>
    <subtype>-</subtype>
    <ra>05 34.5</ra>
    <dec>+22 01</dec>
    <mag>8.4</mag>
    <diameter>6</diameter>
    <distance>6.3</distance>
    <desc>Crab Nebula</desc>   
</object>

xslt를 여러개 만들어서 각 보기마다 실시간으로 렌더링해서 html을 생성하는 구조이다.
이를 위해서 <xsl:choose><xsl:when>을 사용했다.

아래 소스는 xslt 안에 있는 type에 대한 <xsl:template>이다.

<xsl:template match="type">
    <xsl:choose>
        <xsl:when test="contains(.,'Open Cluster')">
            <img src="/images/deepskyicon/OpenCluster.png"/>
        </xsl:when>
        <xsl:when test="contains(.,'Galaxy')">
            <img src="/images/deepskyicon/Galaxy.png"/>
        </xsl:when>
        <xsl:when test="contains(.,'Globular Cluster')">
            <img src="/images/deepskyicon/GlobularCluster.png"/>
        </xsl:when>
        <xsl:when test="contains(.,'Nebula')">
            <img src="/images/deepskyicon/DiffuseNebular.png" />
        </xsl:when>
        </xsl:when>
        <xsl:otherwise>
            <img src="/images/deepskyicon/BinaryStar.png" />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

몇가지 패턴을 알수 있다.

  • 거리순 보기를 보면, 은하들은 죄다 거리가 멀다는 걸 알수 있다. – 당근 나머지 대상은 우리 은하 내의 대상이니까
  • 시기별 보기를 보면, 2~3월엔 거진 외부 은하들만 바글바글하고 5~6월(여름), 11~12월(겨울)엔 은하 찾기가 힘들다. – 여름 겨울철엔 은하수(즉 우리은하)가 흐르니까 우리은하내에 있는 성운, 성단들이 주로 보이는 게다.
  • 밝기별 보기를 보면, 은하들은 순위가 떨어진다. (독보적인 M31을 제외하면) – 역시 은하들은 거리가 머니까…

Astronomy Picture of the Day 페이지 추가

6 22, 2006   //   alexken작성   //   기술, 천문  //  7 Comments

이전 글에 이어서 계속….
바로 밑에 Ajax가 어쩌구 XMLHttpRequest가 저쩌구 했는데,
브라우저간 약간 씩 서로 다른 동작이나, IE인 경우엔 ActiveX 경고창이 뜨고해서,

서버에서 렌더링 해서 내리기로 변경….

코드도 의외로 간단.

$xml = new DomDocument;
$xml->load("http://www.jwz.org/cheesegrater/RSS/apod.rss");

$xsl = new DomDocument;
$xsl->load("apod.xsl");

$proc = new xsltprocessor;
$proc->importStyleSheet($xsl);
echo $proc->transformToXML($xml);
apod.rss와 apod.xsl을 읽어와서
apos.rss를 apod.xsl을 이용해서 렌더링 해서 그냥 화면에 뿌려줌.  끝

apod.xsl파일

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html"/>
   
    <xsl:template match="/rss/channel">
        <xsl:value-of select="pubDate"/> by NASA
        <xsl:value-of select="item/description"
                disable-output-escaping = "yes" />
    </xsl:template>
   
</xsl:stylesheet>

/rss/item/description의 내용이 escape처리된 html 소스인데, 그냥 처리하면 화면에 html 소스가 출력된다.
value-of의 disable-output-escaping 속성 “yes”로 해주어야 한다.(이거 몰라서 한참을 찾았음)

블로그 카테고리

천체사진 갤러리