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 쪽은 거의 문외한이라 이게 최적의 코드인지는 모르지만, 내가 원래 의도했던 기능이나 목표는 다 동작해서 맘에 든다.
그리고 지금까지
는 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></xsl:apply>
</body>
</html>
</xsl:template>
<!-- element 처리 -->
<xsl:template match="*">
<div class="element">
<!-- 본인의 attr 처리하고 -->
<div class="header-area">
<h3><xsl:value -of select="name(.)"></xsl:value></h3>
<xsl:apply -templates select="@*"></xsl:apply>
</div>
<!-- sub element들 처리... -->
<xsl:apply -templates></xsl:apply>
</div>
</xsl:template>
<!-- attribute 처리 -->
<xsl:template match="@*">
<div class="attr">
<i class="att_name"><xsl:value -of select="name(.)"></xsl:value></i><br />
<i class="att_value"><xsl:value -of select="."></xsl:value></i>
</div>
</xsl:template>
</xsl:stylesheet>