웹프로그램을 배우려면 게시판을 만들어 보라는 말이 있습니다. XML을 응용한 프로그램을 만들려고 할 때, 다른 언어보다 ASP가 간단하면서도 웹기반 프로그램 제작에 매우 유용합니다. 이 ASP를 이용하여 XML을 다루는 기술을 습득하고자 할 때 게시판을 하나 만들어 보는 것이 좋을 듯 합니다. 여기서는 이에 도움이 되는 가장 기본적인 게시판 소스를 분석하여 설명합니다.

파일은 아래와 같습니다.

content.asp 선택한 글을 인덱스를 이용 검색하여 보여줌.
default.asp 글쓰기.
delete.asp 삭제 처리.
gesipan.xsl 리스트를 출력하는 포맷을 지정한 xsl 파일.
gesipandb.xml 게시판 글 데이터.
list.asp xml DB를 검색 정리하여 리스트를 보여줌.
predel.asp 지우기 전에 보여주는 화면.
save.asp 글쓰기 후 저장 처리.
update.asp 수정을 처리하는 파일.

게시판 파일 받기(암호걸려있음)

소스 중 xml과 관련된 중요 부에 대해 설명을 하겠습니다.

List.asp

'// xml 화일에 대한 xml dom 객체를 생성시킨다
Set oSource=Server.CreateObject("Microsoft.XMLDOM")
oSource.async=false

xml 문서를 다루는 ASP 객체를 생성하기 위해서 서버 컴포넌트로 등록되어 있는 Microsoft.XMLDOM 객체를 생성시켜야 한다.
요즘 윈도우에서는 지원이 되지만 혹 옛날 윈도우 시스템을 사용하면 지원이 되지 않을 수도 있다. 왜냐면 xml 관련 기술이 최근에 발전하였기 때문이다. 이런 이유로 연구실 msdn 시디에서는 xml 관련 정보를 검색할 수 없으니...
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk30/htm/xmconxmldomuserguide.asp

위 사이트에서 xml 문서를 다루는 정보를 얻기를 바란다. 링크가 긴 것은 바로 xml 정보로 가도록 되어 있기 때문이다.

이렇게 생성된 oSource 객체는 다양한 속성과 메서드를 가지고 있는데 이 속성과 메서드가 제대로 설명되어 있는 자료도 역시 msdn 밖에 없는 것 같다.

두번째 줄에서 oSource의 async 속성을 false로 지정하고 있다.
async 속성은 비동기적인 문서 로딩과 관련된 속성이다. 기본값은 true이다. true인 상태에서는 문서를 로딩하는 동안 제어권을 넘겨준다. 따라서 진행중에 지원되는 몇가지 메서드를 사용할 수 있다.

이 값을 false로 두면 문서 로딩이 끝난 후 제어권이 넘어오므로 어떤 면에서 더 안전하게 사용할 수 있다고 말할 수 있다.


'// dom 객체에 xml 화일을 로드한다
oSource.Load Server.MapPath("gesipandb.xml")

'// xsl 화일에 대한 xml dom 객체를 생성시킨다
Set oStyle=Server.CreateObject("Microsoft.XMLDOM")
oStyle.async=false
'// dom 객체에 방명록 xsl 화일을 로드한다.
oStyle.load Server.MapPath("gesipan.xsl")

nodecount = oSource.selectNodes("//guestbook/entry").length
if page="" then page = 1
if start="" then start = nodecount - displayno

gesipan.xml을 oSource에서 로딩하였고, gesipan.xsl을 oStyle에서 로딩하였다. xml 문서와 xsl 문서는 문서자체가 객체이다. 또한 구조적으로 설계 되어 있다.

selectNodes는 xml 문서에서 노드를 선택하는 기능을 수행한다. gesipan.xml의 루트 노드는 guestbook이고, 그 아래 entry 노드가 있다. 따라서 "//guestbook/entry"와 같은 형식으로 entry 노드를 선택하여 준다.

그러면 결과로 gesipan에 guestbook 아래 있는 entry 노드가 모두 선택되어 리스트로 넘어오게 된다. 노드 리스트 객체 역시 속성과 메서드를 가지고 있다. 그 중 하나가 length로 리스트의 길이를 반환한다.

low = start
high= start + displayno
'// 해당 범위에 있는 값들을 가지고 온다.
Set nodes = oSource.selectNodes("//guestbook/entry[number(ref) >= " + CStr(low) + " and number(ref) <= " + CStr(high) + "]")

"//guestbook/entry[number(ref) >= " + CStr(low) + " and number(ref) <= " + CStr(high) + "]"

위 소스의 내용을 가르쳐 주는 곳을 찾기 어렵지만 중요한 내용을 담고 있다. DB에서 리스트를 만들때 자료를 끊어서 정리하는 거야 쉽지만 xml에서는 어떻게 하는가가 매우 궁금하였는데 이 소스가 그 답을 가르쳐 준다.

entry 노드를 받아올 때 []괄호와 number(ref), 부등호 등을 이용하여 일정 범위의 리스트만을 받아 객체로 만들 수 있다.
number(ref)는 xml 내부에서 사용하는 리스트 번호로 생각하면 된다.


'-- 페이지를 알아내서 태그를 만든다.
pagenode = "<pages start=""" & high & """>" ' 페이지 첫 태그를 넣는다.
pagecount = CInt(nodecount / displayno)
m_startpage = page - CInt(cpage/2)

if m_startpage < 1 then m_startpage = 1

for i = m_startpage to cpage + m_startpage-1
m_no = i
m_start = nodecount - (m_no) * displayno - 1

pagenode = pagenode & "<page no='" & m_no & "' start='" & m_start & "'/>"
if pagecount < i or m_start > nodecount-1 then exit for
next

pagenode = pagenode & "</pages>" ' 페이지 끝 태그를 넣는다.

' 임시 Dom을 만든다.
set TempDom =Server.CreateObject("Microsoft.XMLDOM")
' XML Header값과 페이지 Element을 넣는다.
TempDom.loadXML("<?xml version=""1.0"" encoding=""euc-kr""?>" + vbCrLf + "<guestbook count='" + CStr(nodecount) +"'>" & pagenode & "</guestbook>")
' Root노드를 찾아서 선택된 노드를 넣을 노드를 찾는다.
Set node = TempDom.selectSingleNode("//guestbook")
' 선택된 노드들을 TempDom에 넣는다.
for i=0 to nodes.length-1
if nodes.item(i).hasChildNodes then
node.appendChild(nodes.item(i))
end if
next

윗부분에서 살펴볼 것은 기본적인 게시판에서 페이지 나누는 방법과 임시 xml Document 객체를 만들어 후에 xsl 문서를 로딩한 객체와 함께 출력하는 부분이다.
전자는 일반적인 웹프로그래밍에서 반복되는 부분이므로 소스를 보고 참고하기 바란다.

이 소스에서는 TempDom이라는 객체를 생성시킨다.
다음으로 XML 문서에서 필수인 헤더 부분을 loadXML 메서드를 이용하여 삽입한다. 이때 루트 노드까지 생성하고 종료하는 부분("</guestbook>")까지 넣음으로 완전한 xml 문서를 만들어 준다.

왜냐면 추후의 노드는 이 루트 노드의 자식 노드로써 삽입되어야 하기 때문이다. 완전히 만들지 않으면 다음 작업을 할 수 없다.

for 문을 사용할 때 i가 0일때 부터 리스트 nodes의 length-1일때까지 사용하는 것도 눈여겨 보아두기 바란다.

그리고 nodes에 item 속성을 사용하는데 이것은 리스트 안의 개체를 하나씩 지정할 때 사용하는 메서드이다. nodes.item(0) 이면 첫번째 개체를 가리킨다.

XML 개체는 기본적으로 hasChildNodes란 메서드를 갖는데 이것은 자식이 있는지 없는지를 확인하고 참, 거짓 값을 넘겨주는 메서드이다.

appendChild 메서드는 자신 아래 자식 노드를 생성시키는 역할을 한다. 여기서 nodes.item(i)는 완전한 xml 개체이므로 별다른 처리 없이 append가 가능하다. 그렇지 않은 경우의 처리에 대해서는 다른 소스에서 살펴보도록 한다.

'// xsl을 이용해서 xml의 내용을 html양식으로 변화시킨 후 웹브라두져에 출력한다
Response.Write tempdom.TransformNode(oStyle)
'Response.Write(TempDom.xml)
%>

이상에서 처리한 XML 문서를 출력하기 위해서는 asp의 기본 컴포넌트인 Response를 사용하면 된다.
이때 XML Style sheet를 쓰고자 하면 위와 같이 xsl 문서를 로딩한 개체를 이용하면 된다.
xml 객체의 메서드인 TransformNode를 사용하면 원하는 스타일로 출력할 수 있게 된다.


Content.asp

리스트 뷰에서 제목을 클릭한 경우 그 글을 보여주는 파일이다.

<%

Dim ElemList
Dim xmlDoc

key=request("index")


Set xmlDoc = CreateObject("microsoft.xmldom")
xmlDoc.async = False
xmlDoc.load server.mappath("gesipandb.xml")
Set Elemindex = xmlDoc.getElementsByTagName("index")

For i=0 To (Elemindex.length -1)
if Elemindex.item(i).text = key then
exit for
end if
Next
index=Elemindex.item(i).text

여기서는,

For i=0 To (Elemindex.length -1)
if Elemindex.item(i).text = key then
exit for
end if
Next

부분을 살펴볼 필요가 있다. 이것은 xml 문서를 검색하며 index 노드를 모든 Elemindex 개체 중 key와 값이 일치하는 것이 있는지를 살펴보는 부분이다.
노드의 밸류가 일치하는 값이 있는지를 찾고자 할 때 쓰는 가장 기본적인 방법이다. 직접 값을 찾아주는 메서드가 없어서 불편한 것 같은데 앞으로 발전할 것을 기대한다.

Set Elemcount = xmlDoc.getElementsByTagName("count")
Elemcount.item(i).text=Elemcount.item(i).text+1

xmlDoc.Save Server.Mappath("gesipandb.xml")

Set Elemname = xmlDoc.getElementsByTagName("name")
name=Elemname.item(i).text

Set Elemmail = xmlDoc.getElementsByTagName("mail")
mail=Elemmail.item(i).text

Set Elemippaddr = xmlDoc.getElementsByTagName("ipaddr")
ipaddr=Elemippaddr.item(i).text

Set Elemtitle = xmlDoc.getElementsBytagName("title")
title=Elemtitle.item(i).text

Set Elemcontent = xmlDoc.getElementsByTagName("content")
'message=Elemmessage.item(i).text
content = replace(Elemcontent.item(i).text,chr(13) & chr(10),"<br>")

Set Elemcount = xmlDoc.getElementsByTagName("count")
count=Elemcount.item(i).text

Set Elempwd = xmlDoc.getElementsBytagName("pwd")
pass=Elempwd.item(i).text

앞에서 key와 일치하는 인덱스의 순서 i 값을 찾았기 때문에 여기서는 count, name, mail등과 같은 개체를 받아와 리스트를 만들고 i 번째에 접근하기만 하면 원하는 개체의 하위 노드를 건드리게 된다.

이 방법 역시 문제점이 있다.
xml 문서에 모든 노든가 완벽하게 들어 있어야 한다. 그렇지 않은 경우 리스트에서 i 번째 노드가 일치 하지 않을 수 있다.

다른 방식을 시도하는 중인데, 일단은 이 방법이 가장 기본적으로 게시판에서 쓰이는 방법이다.

%>


Delete.asp

글을 삭제하는 경우 처리하는 파일이다.
다른 부분은 앞서 설명한 부분과 크게 다르지 않다.
글을 선택하고 비밀번호를 확인하여 일치하는 경우 삭제를 한다.

이때 처리과정이 일반적인 생각과 다르다.
먼저는

Set root = xmlDoc.documentElement

를 통해 루트 노드를 받아와 root 객체를 생성한다.
그 후에,

root.removeChild(root.childNodes.item(i))

루트 객체의 removeChild 메서드를 이용하여 root 아래 자식 객체인
root.childNodes.item(i)를 제거한다.

이와 같이 처리하는 것은 게시판의 글 하나가 entry 노드를 형성하는데 이 entry 노드는 root의 자식 노드이기 때문이다. 즉 상위 객체를 불러서 거기에 붙어있는 자식 노드를 제거해 주어야 하는 것이다.

'비밀번호 확인
if trim(spwd) = trim(Elempwd.item(i).text) then

'문서의 root 노드를 읽어와서 해당 child node 삭제
Set root = xmlDoc.documentElement
root.removeChild(root.childNodes.item(i))
xmlDoc.Save Server.Mappath("gesipandb.xml")

response.redirect "list.asp"
else
response.redirect "content.asp?index=" & sindex & "&msg=비밀번호가 틀렸습니다.!"
end if


Save.asp

글을 저장하는 부분을 처리하는 파일이다.
역시 다른 부분은 크게 차이가 없고 여기서는 노드를 생성하는 부분만 눈여겨 볼 필요가 있다.

앞서 노드를 생성시킬때는 appendChild 메서드만을 이용하였다.
이는 appendChild 메서드에 들어가는 값이 완전한 노드 개체였기 때문이다. 여기서는 entry, index등의 이름만을 가지고 새로운 개체를 만어야 하므로

AppendChild(oDOM.createElement("entry"))

와 같이 xml DOM 객체인 oDOM의 메서드 createElement 메서드를 이용해서 entry란 이름의 노드를 만들어 준다.


'// 방명록 xml 문서에 'entry' 노드 생성
Set oEntryNode=oDOM.documentElement.AppendChild(oDOM.createElement("entry"))
oEntryNode.setAttribute "date", FormatDateTime(date,yyyy-mm-dd)

'// 방명록 xml 문서에 'index' 노드 생성
Set oDetailsNode = oEntryNode.appendChild(oDOM.createElement("index"))
oDetailsNode.Text=index

'// 방명록 xml문서에 'name' 노드 생성
Set oDetailsNode = oEntryNode.appendChild(oDOM.createElement("name"))
oDetailsNode.Text=sName

'// 방명록 xml문서에 'email' 노드 생성
Set oDetailsNode = oEntryNode.appendChild(oDOM.createElement("mail"))
oDetailsNode.Text=sMail

'// 방명록 xml문서에 'homepage' 노드 생성
Set oDetailsNode = oEntryNode.appendChild(oDOM.createElement("ipaddr"))
oDetailsNode.Text=sIpaddr

'// 방명록 xml문서에 'ref' 노드 생성
Set oDetailsNode = oEntryNode.appendChild(oDOM.createElement("ref"))
oDetailsNode.Text=ref

'// 방명록 xml문서에 'ref_step' 노드 생성
Set oDetailsNode = oEntryNode.appendChild(oDOM.createElement("ref_step"))
oDetailsNode.Text=ref_step

'// 방명록 xml문서에 'tag' 노드 생성
Set oDetailsNode = oEntryNode.appendChild(oDOM.createElement("tag"))
oDetailsNode.Text = tag

'// 방명록 xml문서에 'count' 노드 생성
Set oDetailsNode = oEntryNode.appendChild(oDOM.createElement("count"))
oDetailsNode.Text=sCount

'// 방명록 xml문서에 'subject' 노드 생성
Set oDetailsNode = oEntryNode.appendChild(oDom.createElement("title"))
oDetailsNode.Text=sTitle

'// 방명록 xml문서에 'message' 노드 생성 -이것은 cdata 섹션으로 둔다.
Set oDetailsNode = oEntryNode.appendChild(oDOM.createElement("content"))
oDetailsNode.appendChild oDOM.createCDATASection(sContent)

'// 방명록 xml문서에 'pwd' 노드 생성
Set oDetailsNode = oEntryNode.appendChild(oDom.createElement("pwd"))
oDetailsNode.Text=sPwd

'// 이제 xml 문서를 저장한다
'// 주의사항!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'// save 시킬 디렉토리는 반드시 "쓰기 권한"이 설정되어 있어야 한다.

oDOM.Save Server.MapPath("gesipandb.xml")

response.redirect("list.asp")

'asp' 카테고리의 다른 글

ActiveX Data Object 2.5 and over  (0) 2007.05.02
ActiveX Data Object 2.5 and over  (0) 2007.05.02
ASP에서 성능문제 향상방법  (0) 2007.05.02
쿠키  (0) 2007.05.02
ASP에러체크  (2) 2007.05.02

+ Recent posts