공룡호가 사는 세상 이야기

Taejon 2001 :
본선문제 PKU 1060 ~ 1092  or  ARC 2321 ~ 2328
http://acmicpc-live-archive.uva.es/nuevoportal/region.php?r=as4&year=2001
http://acm.pku.edu.cn/JudgeOnline/searchproblem?field=source&key=Taejon+2001


Taejon 2002 :
본선문제 PKU 1330 ~ 1337
http://acm.pku.edu.cn/JudgeOnline/searchproblem?field=source&key=Taejon+2002


Seoul 2003 :
본선문제 ZJU 2679 ~ 2687
2679 :
http://acm.zju.edu.cn/show_problem.php?pid=2679


Seoul 2004 :
예선문제 Hello-World 44
http://www.hello-world.co.kr/?q=node/110


Seoul 2005 :
예선문제 Hello-World 41 - 43
http://www.hello-world.co.kr/?q=node/104

본선문제 TJU 2501~2510
http://acm.tju.edu.cn/toj/search_process.php?s=Asia+-+Seoul+2005


Seoul 2006 :
예선문제 Hello-World 35 - 40
http://www.hello-world.co.kr/?q=node/98

본선문제 ZJU 3131 ~ 3140
http://acm.zju.edu.cn/onlinejudge/searchProblem.do?contestId=1&titlefrom=0&authorfrom=0&sourcefrom=0&query=Seoul%202006


Seoul 2007 :
본선문제 ARC 3900~3909
http://acmicpc-live-archive.uva.es/nuevoportal/region.php?r=as4&year=2007


Seoul 2008 :


원본 출처 : wookayin.com


using System;  
using System.Data;  
using System.Data.SqlClient;  
 
public class DB_TEST  
{  
    public static void Main(string[] args)  
    {  
        SqlConnection conn = new SqlConnection();  
        conn.ConnectionString =  
            "Server=ip;database=CL_ADMIN;uid=sa;pwd=password;";  
 
       try 
       {  
          conn.Open();  
          Console.WriteLine("데이터베이스 연결성공..");  
         String log = " SELECT * FROM dbo.OB_TEST"; // 쿼리문  
          SqlCommand cmd = new SqlCommand(log, conn); // 적용  
           SqlDataReader rd = cmd.ExecuteReader(); // 쿼리 수행  
 
          while (rd.Read()) //한줄씩 잃기  
          {  
            Console.WriteLine(String.Format("{0}, {1}", rd[0],rd[1]));  
            //내용 출력하는 부분         
                 
          }  
         rd.Close();  
 
       }  
       catch 
       {  
 
            Console.WriteLine("데이터베이스 연결 실패..");  
        }  
        finally 
        {  
            if (conn != null)  
            {  
                conn.Close();  
            }  
            Console.WriteLine("데이터베이스 연결해제");  
 
        }  
    }  
}

프로젝트 문서화는 소프트웨어 제품을 내 놓을 때, 종종 필요악이 됩니다.
참 맞는 말이다. 개발 할 시간도 없는데 언제 문서까지 만들고 있을까... 실제로, 학부생 때, 프로젝트를 진행 하면서, 중간 보고 때 마다 진척 상황를 문서화 해야 하는 사실이 너무나 귀찮고 어려웠다. 왜 하는 지도 몰랐었던 때가 있었는데, 얼마 후, 코드가 모두 담겨 있는 USB 메모리 스틱을 분실했다. 물론, 백업을 해 두지 않은 잘못이 크긴 하지만, 절망적이었다. 6개월 간의 코드를 분실했다고 생각해 보라.
형식도, 정형화도 되어 있지 않은 내 나름대로의 문서였지만, 나는 그 간의 문서들을 기초로 다시금 코드를 작성했고, 기간은 한 달도 채 걸리지 않았다. 그러나 여전히 필요악인 건 사실인..가(?)

문서화는 중요하다. 진행 중인 프로젝트의 팀원이 변경 되거나, 통채로 중지했다 다시 시작하거나, 실수로 데이터를 유실했을 여러가지 경우에 대해서 문서는 정말 중요한 수단이 된다. 그러나, 개발 할 시간도 부족한데, 일일이 문서를 만드는 것을 좋아 할 개발자가 어디있겠는가.. 비슷한 맥락에서 다음 내용을 보자.

내 경험에 비춰봤을 때, 두 개의 핵심 문제 때문에 소프트웨어 개발 문서화가 병들고 있다. 첫 번째는 아무도 그것을 읽지 않을 것이라는 가능성 때문이다. 두 번째로 흔한 문제는 문서 작성 시기가 거의 대부분 지연된다는 것이다.

그러면 문서작성을 자동화 하는 것을 생각해 볼 수 있다. 코드가 작성될 때 마다, 버튼 한 번으로 문서를 작성할 수 있다면, 그것을 항상 최신 상태로 유지함으로써 프로젝트에 참여한 모든 인원들 그리고 사용자 까지도 더 유용하게 만들 수 있다.
과연, 어떻게 그것을 자동화 할 수 있을까? dW에서 그 해답을 찾아보는건?

원문보기
http://www.ibm.com/developerworks/kr/library/j-ap06108/

사용자 삽입 이미지
앞서 리뷰했던 메모리 관련 Article과 관련 있는 기사를 한번 더 보고자 한다.
프로그래밍에서 메모리 결함은 대부분 잘못된 코딩 습관에서 온다고 언급했었다.
사실, 메모리 결함 뿐 만이 아니다. 모든 오류나 결함은 마찬가지이다.
같은 맥락에서, 이번 Article을 읽다가 인상 깊은 구절을 발견했다.
C 프로그램에서 컴파일 옵션에 -O -Wall -W -Wshadow -pedantic을 사용하면, 소스코드에서 올바르지 않거나 의심스러운 부분진단 메시지로 날려준다.

많은 개발팀이 컴파일러가 제공하는 진단 결함을 불치병이나 세금처럼 필요악으로 취급한다.

내 경험으로는 아무리 잘 관리해도 진단 메시지를 무시하는 50만 줄짜리 프로젝트는 오류가 적어도 5000개 정도 존재한다. 물론, 그 중 적어도 몇 개 정도는 자주 발생하는 오류로 드러난다. 결코 음수가 되지 않는 unsigned 정수를 조건으로 사용하거나, 선언한 변수에 철자 오류가 있어 전혀 사용되지 않는 경우 등이다. 모든 컴파일러 진단 메시지를 하나씩 없애가는 과정에서 코드 품질은 극적으로 향상된다. 컴파일러 진단 메시지는 자동화하기가 쉬우므로 비용도 적게 든다

사실, 그렇지 않은가 Error는 수정하지 않으면, 컴파일을 할 수 없으므로 어쩔 수 없이 하게 되지만, Warnning은 그냥 지나치기 일쑤다. 지나치다 보면 이제 손대기 귀찮고 짜증날 정도로 많아지게 되고, 나중엔 아예 손을 쓰기조차 어려워진다. 그래도 컴파일은 된다. 기대하는 대로 작동한다. 하지만 오류는 언제나 잠재 해 있다는 것이 문제이다.

메모리 오류에 한정되어 있지만, 이는 굉장히 중요한 문제이다.
컴파일 옵션을 주어 모든 진단 메시지를 확인하고 그에 따른 진단 과정을 살펴보면서, 올바른 코딩 습관에 대해 다시 한번 더 생각 할 기회와 메모리 오류에 대해 진단하고 해결하는 과정도 함께 익힐 수 있을 것 같다. 코드 품질을 극적으로 높이는 관건은 기술적 혁신이 아니라 문화적인 혁신이다. 맞는 말이다.

Ping 날리기 공개 소스

// ping.cpp
// Borland C++ 5.0: bcc32.cpp ping.cpp
// Visual C++ 5.0: cl ping.cpp wsock32.lib

Resource Leaking

프로그래밍2007. 8. 13. 18:33

MFC 에서, 컨트롤의 색상을 변경하고자 할 때, OnCtlColor()을 사용한다. (버튼 컨트롤 제외)

HBRUSH CPppDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
 HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

 if( pWnd->GetDlgCtrlID() == IDC_DIC)
 {
  hbr = CreateSolidBrush( RGB(0,0,255) );
  pDC->SetBkMode( TRANSPARENT );
  pDC->SetBkColor( RGB(0,0,255) );
  pDC->SetTextColor( RGB(255,255,0) );
    
  return hbr;       
 }
 return hbr;
}


여기서 문제가 있다. 이 메소드는 해당 컨트롤을 다시 그려야 할 이유가 생길 때 마다 자동적으로 호출된다.
따라서, 프로세스의 메모리 점유가 늘어날 수 밖에 없다.
계속해서 CreateSolidBrush()를 통해 계속해서 브러시를 생성하기 때문.

프로그램 시작시, 단 한번만 브러시를 생성하고 프로그램 종료 시, 생성된 브러시를 파괴해 주는 것으로 이 부분은 해결된다. 코드는 다음과 같다.

생성자에 다음과 같은 코드를 삽입한다.
물론 hBkBrush 는 HBRUSH type 이며, 클래스 정의부분에 명시해 둔다.
hBkBrush = CreateSolidBrush(RGB(0,0,255));

그리고 위의 코드 중, 붉은색으로 된 부분을 다음과 같이 변경한다.
hbr = hBkBrush;

마지막으로, 프로그램 종료시 호출되는 파괴자나, 기타 메소드 중에 적당한 곳을 골라 브러시 객체를 파괴한다.
DeleteObject(hBkBrush);

'프로그래밍' 카테고리의 다른 글

C# TIP 몇가지  (0) 2007.10.04
구글 가젯 만들기, Part1  (1) 2007.08.21
WebPage Redirect (MFC / API)  (0) 2007.05.16
SetTimer()  (0) 2007.05.14
ROBOCODE Master의 비밀!!!  (0) 2007.04.23

SetTimer()

프로그래밍2007. 5. 14. 16:15

일정 시간마다 특정한 일을 수행할 때 대개 SetTimer() 함수를 사용한다. (일정 시간이 경과할 때까지 Sleep하는 건 유치할 것같다.. ㅋㅋ) 책을 좀 찾아보니 SetTimer()는 SDK에서 제공되는 API 함수가 원조격이다. 일단, MSDN을 열어봤다.

이미지를 클릭하시면 원본크기로 보실수 있습니다.

보다시피 VC++에서 제공되는 SetTimer() 함수는 총 3개가 존재한다. 그런데, 맨 위의 CWindows::SetTimer는 ATL에서 사용되기 때문에 통상으로 사용되는 SetTimer() 함수는 SDK의 API 함수와 CWnd::SetTimer 멤버함수가 되겠다. (따라서, SetTimer()는 SDK버전과 MFC버전 두개만 정리하면 된다.)

먼저, SDK의 SetTimer() 함수의 원형을 살펴본다.

UINT SetTimer(
  HWND hWnd,    // handle of window for timer messages
  UINT nIDEvent,          // timer identifier
  UINT uElapse,           // time-out value
  TIMERPROC lpTimerFunc   // address of timer procedure
);

첫번째 인자는 SetTimer()를 호출하는 윈도우의 핸들이고, 두번째는 타이머의 ID이다. 애플리케이션은 여러 개의 독립된 타이머를 이용할 수 있다. 따라서, 각각의 타이머를 구별하기 위해 ID를 부여한다. 세번째 인자는 타이머의 주기(단위는 밀리초)이며, 마지막 인자는 타이머가 동작할 때 시스템이 호출하는 콜백함수(이를 타이머 프로시져라 한다)의 함수포인터(여기서, 타이머 프로시져의 함수이름은 자기 마음대로 결정해도 된다)이다. 즉, 일정 시간이 발생하면 해당 콜백함수를 실행하게 되는데, 거기에 우리가 필요로 하는 루틴을 넣어주면 된다.

그러면, SetTimer()에 등록하는 콜백함수(타이머 프로시져)는 어떻게 정의해야 할까? (타이머 프로시져는 콜백함수이기 때문에 함수이름은 SetTimer에 등록한 함수이름과 동일해야 하며, 시스템이 정한 호출 형식대로 정의를 해두어야 한다.)

VOID CALLBACK TimerProc(
  HWND hwnd,     // handle of window for timer messages
  UINT uMsg,     // WM_TIMER message
  UINT idEvent,  // timer identifier
  DWORD dwTime   // current system time
);

호출되는 타이머 프로시져 함수는 위와 같은 형식이다. 첫번째 인자인 hWnd는 타이머를 호출한 윈도우의 핸들이며(SetTimer()함수의 첫번째 인자를 생각할 것), 두번째는 시스템이 던져주는 타이머 메시지(항상 WM_TIMER이다), 세번째는 호출한 SetTimer함수의 Id값, 네번째는 시스템 시간이다. 위의 인자들은 TimerProc가 콜백함수이기 때문에 시스템이 알아서 던져준다. 따라서, 우리는 타이머 Id를 조사(if 내지는 switch)하여 해당 타이머에 대한 기능을 구현하면 될 것이다.

그런데, MSDN을 자세히 읽어보면 SetTimer()의 인자 중에서 콜백함수 대신 NULL을 대입하는 경우가 있다. 이 경우, 시스템은 일정 시간에 이르면 콜백함수를 호출하는 것이 아니라 애플리케이션에 WM_TIMER 메시지를 전달한다. 따라서, Win32 프로그램의 경우라면 WndProc에서 WM_TIMER 발생에 따른 처리루틴을 구현하면 된다.

정리하면, SDK의 SetTimer함수는 콜백함수에 의한 처리방식과 WM_TIMER 메시지에 대한 처리방식으로 그 사용방법이 나뉘어진다. 이는 MFC에서도 마찬가지이다. 이제 MFC의 SetTimer() 함수를 살펴보자.

UINT

CWnd::SetTimer(

            UINT nIDEvent,

            UINT nElapse,

void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT,

                                        UINT, DWORD) );

MFC의 SetTimer() 함수는 CWnd클래스의 멤버함수로 구현되어 있기 때문에 SDI, MDI, 다이얼로그 애플리케이션에서 모두 사용이 가능하다. SDK와의 차이점은 SDK의 첫번째 인자인 hWnd를 가지고 있지 않다는 점. 당연히 CWnd의 멤버함수이므로 hWnd를 알고 있기 때문일 거다. 그 점을 제외하면 SDK버전과 별반 다를게 없다.

다만, MFC에서는 타이머 프로시져를 사용하지 않을 경우 WM_TIMER의 처리를 위해서 OnTimer() 이벤트 핸들러를 추가해서 사용하면 될 것이고, 타이머 프로시져를 사용할 경우 타이머 프로시져는 전역함수이기 때문에 주윈도우(또는 주다이얼로그)의 멤버에 접근하기 위해서 다음과 같은 방법을 사용할 수 있다.

가령, 다이얼로그 기반으로 TestProg라는 애플리케이션을 작성하였을 경우

void CALLBACK TimerProc(HWND hWnd, UINT nIDEvent, UINT nElapse, DWORD dwTime)

{

    ...

    CWnd *pWnd = AfxGetMainWnd();

    CTestProgDlg *dlg = (CTestProgDlg *)pWnd;

    dlg->멤버함수();

}


이런 식으로 하면 된다.

'프로그래밍' 카테고리의 다른 글

Resource Leaking  (6) 2007.08.13
WebPage Redirect (MFC / API)  (0) 2007.05.16
ROBOCODE Master의 비밀!!!  (0) 2007.04.23
우연히 보게 된 코드  (2) 2007.04.19
공사  (0) 2007.04.17

yjae.net 님의 블로그에서 다음과 같은 코드를 보았다.

protected void myButton_Click (object sender, EventArgs e)
{
   myPanel.Visible = !myPanel.Visible;
}

나는 왜 이런 걸 생각하지 못했을까. 나 또한 내공 부족인 걸까, IQ부족인걸까, 응용력 부족인걸까... -_ㅜ

if (myPanel.Visible == true)
{
   myPanel.Visible = false;
}
else
{
   myPanel.Visible = true;
}

'프로그래밍' 카테고리의 다른 글

SetTimer()  (0) 2007.05.14
ROBOCODE Master의 비밀!!!  (0) 2007.04.23
공사  (0) 2007.04.17
매시업 데이터  (0) 2007.04.15
동적으로 생성된 컨트롤의 이벤트 처리시 넘기는 인자값으로 인한 문제  (0) 2007.04.07

동적으로 생성된 컨트롤의 이벤트 처리시 넘기는 인자값으로 인한 문제입니다.

 

int NumSearch = 1

LOOP()

{

                        Button btnSearchUp = new Button();  // 버튼 객체 생성

                        btnSearchUp.Width = 70;

                        btnSearchUp.Text = "UpLoad";

                        btnSearchUp.ID = "btnSearchUp" + NumSearch.ToString();

                       

                        // 이 버튼의 명령인자에 파일의 경로와 파일 이름으로 설정

                        btnSearchUp.CommandArgument = temp;

 

                        // 해당 버튼에 이벤트를 걸어준다.

                        btnSearchUp.Click += new EventHandler(btnSearchUpClick);

 

                        NumSearch++;

}

 

 

이런 식으로 하여, 동적으로 컨트롤을 생성합니다.

컨트롤 아이디는 보시는 바와 같이 "btnSearchUp" + 1 ... 2 ... 3 이런식으로 컨트롤의 아이디가 붙습니다.

그리고 버튼의 CommandArgument 속성에 temp라는 string을 넣습니다. 그러면

아래쪽에 해당 버튼의 클릭 이벤트를 만들어 준 곳에서 이 CommandArgument 속성이 전달이 됩니다.

 

        void btnSearchUpClick(object sender, EventArgs e)

        {

             ((Button)FindControl("btn")).CommandArgument    

        }

 

이벤트 메서드 입니다.

이 부분은 엄준일 님께서 알려 주셨는데요. 이렇게 이벤트를 처리하는 메소드는 1개 뿐입니다.

전달 인자를 찾아 내기 위해서 위와 같은 방법을 쓴다는데, 이 부분은 버튼 컨트롤을 FindControl() 메서드로 찾아서 해당 속성을

추출하는 것 처럼 보입니다만, 저 부분의 "btn" 부분은 컨트롤의 아이디가 아닌가요?

컨트롤의 아이디로 알고 있는데, 여기서 문제가 생깁니다.

 

예를 들어, 위에서 동적으로 10개의 버튼 컨트롤을 생성했습니다.

그런데 사용자가 어떠한 버튼을 클릭할 지 알 수 없는데,

이벤트 처리 메서드에서는 어떻게 사용자가 클릭한 버튼 컨트롤의 아이디를 찾아서 해당 속성을 가져온다는 말인가요?

 

이러한 문제는 어떻게 해결해야 하나요?

 


 

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

<head runat="server">

    <title>제목 없음</title>

</head>

<body>

    <form id="form1" runat="server">

    <div>

               <input type="hidden" id="hid" name="hid" />

    </div>

    </form>

</body>

</html>

----------------------------------------------------------------------------

        protected void Page_Load(object sender, EventArgs e)

        {

               for (int i = 0; i < 10; i++)

               {

                       Button btn = new Button();

                       btn.ID = "btn" + i;

                       btn.Click += new EventHandler(btn_Click);

                       btn.Attributes["onclick"]     = "form1.hid.value = '" + "btn"+i + "';";

                       btn.Text = i.ToString();

                       btn.CommandArgument = "인자값 : " + i.ToString();

 

                       form1.Controls.Add(btn);

                       form1.Controls.Add(new LiteralControl("<br/>"));

               }

        }

 

        void btn_Click(object sender, EventArgs e)

        {

               string btnString       = Request["hid"].ToString();

 

               Response.Write( "버튼 컨트롤 아이디 : " + btnString + "<br>");

               Button btn = (Button)FindControl( btnString );

               Response.Write( btn.CommandArgument );

        }

---------------------------------------------------------------------------------------------

이 소스는 10 개의 버튼을 생성한 후에 버튼을 클릭하게 되면 html 히튼 컨트롤에 버튼의 아이디 값을 넣습니다.

 

그리고 포스트백 후에 버튼 이벤트가 실행되겠지요.

 

버튼 이벤트에서 버튼의 아이디 값을 가져옵니다. 그것으로 마져 CommandArgument 값을 가져오지요..

 

ASP나 JSP 식의 코딩이지요~

 

이전에도 말씀드렸다 시피, 닷넷의 생산성이 높다는 것의 하나가 바로 바인딩 가능한 서버 컨트롤이 있기 때문이지요.

 

똑같은 소소를 DataList 로 작성해 보면..

 

<%@ Import Namespace="System.Data" %>

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<script runat="server">

        private void Page_Load(object sender, EventArgs e)

        {

               if( IsPostBack ) return;

              

               // 가상의 데이터

               DataTable dt = new DataTable();

               dt.Columns.Add("Title", typeof(string) );

 

               for (int i = 0; i < 10; i++)

               {

                       DataRow row = dt.NewRow();

                       row["Title"] = "btn"+i;

                       dt.Rows.Add( row );

               }

              

               dlList.DataSource      = dt;

               dlList.DataBind();

        }

 

        protected void dlList_ItemCommand(object source, DataListCommandEventArgs e)

        {

               if (e.CommandName == "upload")

               {

                       Response.Write( e.CommandArgument.ToString() + "버튼이 클릭되었습니다");

               }

        }

</script>

 

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

<head runat="server">

    <title>제목 없음</title>

</head>

<body>

    <form id="form1" runat="server">

    <div>

               <asp:DataList ID="dlList" runat="server" OnItemCommand="dlList_ItemCommand">

                       <ItemTemplate>

                              <%# DataBinder.Eval(Container.DataItem,"Title") %> <asp:Button ID="btn" runat="server" CommandName="upload" Text='Upload' CommandArgument='<%# DataBinder.Eval(Container.DataItem,"Title") %>'></asp:Button>

                       </ItemTemplate>

               </asp:DataList>

    </div>

    </form>

</body>

</html>

 

소스량은 언듯 비슷해 보이네요~

 

하지만 작성하면서 직관성이 매우 차이가 나고, 직관적이므로 디버깅도 용이해 지겠죠~

 

또한 후자처럼 작성하시게 되면 아시겠지만, 속도면에서도 굉장히 빨라집니다.

 

VS 2003 에서 작성하시는거라 위의 녹색 부분은 Oninit 메서드에서 이벤트로 따로 연결해 주셔야 합니다.

 

DataList 의 편리함을 뒤늦게라도 아시면... "아차~ 왜 진작 안썼지~" 라고 후회하실거에영^^;

'프로그래밍' 카테고리의 다른 글

공사  (0) 2007.04.17
매시업 데이터  (0) 2007.04.15
C#으로 openAPI 이용. 그리고 XML의 파싱  (0) 2007.04.04
WEB 2.0 관련자료  (0) 2007.03.27
DefiningSOA as an Architectural Style  (0) 2007.03.27

naver OpenAPI의 내PC 검색은 일반적인 검색과 리턴 값이 달랐다.
일반적인 openAPI의 리턴값은 다음과 같다. 예를들어 검색 api는 다음과 같은 XML을 리턴한다.
<?xml version="1.0" encoding="UTF-8" ?>
- <rss version="2.0">
- <channel>
  <title>Naver Open API - webkr ::'go'</title>
  <link>http://search.naver.com</link>
  <description>Naver Search Result</description>
  <lastBuildDate>Tue, 11 Apr 2006 14:36:33 +0900</lastBuildDate>
  <total>18992582</total>
  <start>1</start>
  <display>10</display>
- <item>
  <title><b>GO</b>.com</title>
  <link>http://www.go.com/</link>
  <description>... Victims, Military Personnel Sell Rations Online Government Report Finds Ready-to-Eat Meals for Sale on eBay...... trailers and the latest buzz on... Harry Potter and the Goblet of Fire , X-Men 3 , Spider-Man 3 , more... Tonight...</description>
  </item>

보면 알겠지만 <TAG>TEXT</TAG> 형식으로 구성되어 있으므로 파싱하기가 편리하다.
직접 파싱을 해도 되지만, C#에서 파서를 제공해 주는데 굳이 할 필요는 없지 않은가.
최초 XML을 접하고 파싱에 애를 먹어 각지의 도움을 얻었었다. 그리고 준일님께서 도와주셨다.

웹서비스는 XML 을 이용한 HTTP 간의 통신 방법이다.
이 기술이 현재 각광을 받는 이유는 방화벽간에 통신을 위한 포트가 아닌,
HTTP 로 어떤 플랫폼에서도 인식이 가능한 규격화된 텍스트 형식, 즉 XML 이라는 것이다.

DataSet 이란 클래스는 무수한 기능을 가진 컬렉션이다.
이부분은 ADO.NET에 대해서 더 공부하면 알겠지만, 메모리 상의 작은 데이터베이스라고 칭할만큼 무수한 기능이 많다.
DataSet 의 ReadXml 이란 메서드는 XML 형식의 데이터를 DataSet 으로 파싱할 수 있게 된다.
(단, 모든 DataSet 에 변환가능한 형식 이어야 한다.)

파싱의 예는 다음과 같다.
string QueryURL = "쿼리문"
XmlTextReader txtReader = new XmlTextReader(QueryURL);
while(txtReader.Read())
{
 if(txtReader.NodeType == XmlNodeType.Element)
 Response.Write(txtReader.Name + " : ");
 if(txtReader.NodeType == XmlNodeType.Text)
 Response.Write (txtReader.Value + "<br>");
}

쿼리문을 던져 해당 노드의 타입을 보고 Element와 Text를 구분하여 출력해 주는 예제이다.
하지만, 문제가 있다.
naver 내PC 검색의 리턴XML의 출력은 표준 형식인 RSS 2.0 형식 (http://blogs.law.harvard.edu/tech/rss)을 따른다.
표준 RSS에 내PC검색 API용으로 추가된 태그는 nns XML namespace를 가진다.

<?xml version="1.0" encoding="UTF-8" ?>
- <rss version="2.0" xmlns:nns="http://mypc.naver.com/nnsrss">
- <channel>
  <title>Naver OpenAPI - MyPC Search Result</title>
  <link>http://127.0.0.1:4311/openapi/search?key=mypc&query=%BF%E4%BF%F8</link>
  <description>Naver MyPC Search Result</description>
  <language>ko</language>
  <generator>Nano Search 2.0</generator>
  <nns:total>5</nns:total>
  <nns:start>1</nns:start>
  <nns:display>5</nns:display>
  <nns:errorcode>0</nns:errorcode>
- <item>
- <title>
<![CDATA[alias.2x03.cipher.ws_dvdrip_xvid-fov.avi  ]]>
  </title>
- <link>
<![CDATA[G:\alias.s02\alias.2x03.cipher.ws_dvdrip_xvid-fov.avi  ]]>
  </link>
- <description>
- <![CDATA[ 

와 같은 형식은 <TAG><![CDATA[TEXT]]</TAG> 형식이다. 위의 파싱 방법으로 파싱을 할 경우에는, 올바로 파싱이 되지 않는다. <![ 형식을 Element로 판단하지 못하고 무시해 버린다.
위 파싱 방법의 소스 중, Value는 Xml Element 의 내용을 그대로 가져오게 된다.
ReadElementString() 메서드를 사용하면 말끔히 해결된다.
다음 예제는 이러한 문제도 말끔히 해결된다.

XMLFile1.XML
<?xml version="1.0" encoding="utf-8" ?>
<title><![CDATA[타이틀]]></title>
Program.CS
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
namespace ConsoleTest
{
 class Program
 {
  static void Main(string[] args)
  {
   XmlTextReader reader = new XmlTextReader("../../XMLFile1.xml");
   while (reader.Read())
   {
    if (reader.NodeType == XmlNodeType.Element && reader.Name == "title")
     Console.WriteLine(reader.ReadElementString());
   }
   reader.Close();
  }
 }
}

이상. XML의 파싱은 여기까지.
XML을 적절히 파싱한다면, 이를 이용하는 방법은 헤아릴 수도 없을 정도일 것이다.
이것이 XML의 강점(?) 이며, openAPI의 매력일지도 모르겠다. *-_-*