참고: http://www.psuedoguru.com/roller/page/psuedoblog?entry=failed_to_create_an_xpathfactory

XPathFactory factory = XPathFactory.newInstance();
여기에서 아래와 같은 에러가 나올 때가 있다.

java.lang.RuntimeException: XPathFactory#newInstance() failed to create an XPathFactory for the default object model: http://java.sun.com/jaxp/xpath/dom with the XPathFactoryConfigurationException: javax.xml.xpath.XPathFactoryConfigurationException: No XPathFctory implementation found for the object model: http://java.sun.com/jaxp/xpath/dom

문제는 아래.

Finally found out that the problem was due to the Tomcat Java 1.4 compatibility libraries. I had recently upgraded to Java 1.5, but forgot to remove them.
$TOMCAT_HOME/common/endorsed/xercesImpl.jar
$TOMCAT_HOME/common/endorsed/xml-apis.jar

톰캣의 xml관련 api에서 문제가 밸생한 것임.
파일을 옮기던가 지우던가 하면 해결된다.

[BASE64] BASE64 인코딩

프로그래밍/Library 2009. 2. 27. 15:03 Posted by galad
// Encode the bytes of the string
String encoding = new sun.misc.BASE64Encoder().encodeBuffer(userPassword.getBytes());
// Set the "Authorization" request property for the URLConnection
// chuck로 인한 줄바꿈 문자 삭제. PW가 길면 문제.
uc.setRequestProperty("Authorization","Basic " + encoding.substring(0, encoding.length() - 2)); 


import org.apache.commons.codec.binary.Base64;

// false - chunk하지 않는다(chuck하면 76자 단위로 줄바꿈)
String encoding = new String(Base64.encodeBase64(userPassword.getBytes(), false));
uc.setRequestProperty("Authorization","Basic " + encoding);

둘 중에 하나 쓰면 됨.
아래 것은 라이브러리 받아야 한다.

[HTTP] HTTP BASIC-AUTH

프로그래밍/Web 2009. 2. 27. 14:59 Posted by galad
참조: http://www.ibm.com/developerworks/kr/webservices/library/ws-sec1.html
참조: http://www.java-tips.org/other-api-tips/httpclient/how-to-use-basic-authentication.html
참조: http://docstore.mik.ua/orelly/java-ent/servlet/ch08_01.htm
참조: http://www.javaworld.com/javaworld/javatips/jw-javatip47.html

HTTP를 이용한 웹 서비스 보안
    * HTTP 기본 권한
    * HTTPS (HTTP Secure) 또는 보안 소켓 레이어(SSL)를 갖춘 HTTP
    * HTTP 기본 권한 + HTTPS

HTTP 기본 권한
HTTP 기본 권한(BASIC-AUTH)은 HTTP에 사용된 간단한 메커니즘이다. 이 메커니즘을 사용하여 권한을 부여받지 못한 접근으로 부터 웹 리소스를 방어할 수 있다.

Step 1: 웹 서비스 작성 및 전개 
EchoService.jws라는 웹 서비스를 작성.
하지만 서비스는 안전하지 않다. 이를 안전하게 하려면 '%TOMCAT_HOME%\webapps\axis' 내부에 'protected'(본인이 선택해도 무방)라는 디렉토리를 만들고 'EchoService.jws'를 이 디렉토리로 옮긴다. 이제 웹 서비스 URL은 http://localhost:8080/axis/protected/EchoService.jws?wsdl이 되었다.

Step 2:사용자 기밀 정의
새로운 사용자 기밀을 추가하려면 '%TOMCAT_HOME%\conf'에 있는 'tomcat-users.xml'을 편집하고 아래와 같이 새로운 사용자를 추가한다.
<tomcat-users>
  <user name="tomcat" password="tomcat" roles="tomcat,manager" />
  <user name="role1"  password="tomcat" roles="role1"  />
  <user name="both"   password="tomcat" roles="tomcat,role1" />
  <!-- Define new user name and password with the role -->

      <user name="wsuser" password="wspwd" roles="wsuser" />
</tomcat-users>

Step 3: 웹 서비스 URL에 보안 제한 추가하기
보안 제약을 추가하려면 '%TOMCAT_HOME%\webapps\axis\WEB-INF'에 있는 'web.xml'을 편집하고 <web-app> 엘리먼트의 끝 직전에 이 라인을 삽입한다.
<Security-constraint>
   <web-resource-collection>
      <web-resource-name>Protected</web-resource-name>
      <!-- specify the directory for restricted Web Services application -->
      <url-pattern>/protected/*</url-pattern>
   </web-resource-collection>
   <auth-constraint>
      <!-- specify the role name of the new user added in step 2 -->
      <role-name>wsuser</role-name>
   </web-resource-collection>
   <auth-constraint>
</security-constraint>

<!-- Define the Login Configuration for this Application -->
<login-config>
   <auth-method>BASIC</auth-method>
   <realm-name>Protected Web Services</realm-name>
</login-config>

<!-- 이거 없으면 경고문 나옴. -->
<security-role>
   <role-name>wsuser</role-name>
</security-role>

URL http://localhost:8080/axis/protected/EchoService.jws?wsdl로 가서 WSDL에 접근시도 한다. 브라우저는 사용자 권한을 위해 사용자이름과 패스워드를 입력을 요청 할 것이다.

Listing 4. BASIC-AUTH를 사용하여 서비스를 호출하는 클라이언트 작성하기
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import javax.xml.namespace.QName;
 
public class TestClient {
 public static void main(String [] args) {
  try {
    String endpoint = "http://localhost:8080/axis/protected/EchoService.jws";
    Service service = new Service();
    Call    call    = (Call) service.createCall();
    call.setTargetEndpointAddress( new java.net.URL(endpoint) );
    call.setOperationName(new QName("echoString"));
      
    call.setUsername("wsuser");
    call.setPassword("wspwd");

    String ret = (String) call.invoke( new Object[] { "Hello!" } );
    System.out.println("Sent 'Hello!', got '" + ret + "'");
  } catch (Exception e) {
    System.err.println(e.toString());
  }
 }
}

HttpURLConnection을 사용하는 방법
직접 HTTP Header에 Base64로 인코딩한 유저/패스워드 정보를 설정한다.
// HTTP BASIC-AUTH
String userPassword = "wsuser" + ":" +"wspwd"; // USERNAME:PASSWORD
//// Encode the bytes of the string
//String encoding = new sun.misc.BASE64Encoder().encodeBuffer(userPassword.getBytes());
//// Set the "Authorization" request property for the URLConnection
//uc.setRequestProperty("Authorization","Basic " + encoding.substring(0, encoding.length() - 2));  // chuck로 인해 줄바꿈 문자 삭제. PW가 길면 문제.
       
String encoding = new String(Base64.encodeBase64(userPassword.getBytes(), false)); // false - chunk하지 않는다(chuck하면 76자 단위로 줄바꿈)
uc.setRequestProperty("Authorization","Basic " + encoding);



참고 : http://charmpa.egloos.com/1336665

        String RMS_URL = "http://localhost:8080/SMILE_RMS/rms/request_deploy";
        URL url = new URL(RMS_URL);
        HttpURLConnection uc = (HttpURLConnection) url.openConnection();
       
        uc.setDoInput(true);
        uc.setDoOutput(true);
        uc.setUseCaches(false);
        uc.setRequestMethod("POST");
       
        // Http Header
        String ver = "X-RMS-VER 1.0";
        String uid = "X-RMS-UID 1.0";
        String upw = "X-RMS-UPW 1.0";
        String tid = "X-RMS-TID " + System.currentTimeMillis();
        String length = msg.length()+"";
        uc.setRequestProperty("X-RMS-VER", ver);
        uc.setRequestProperty("X-RMS-UID", uid); // md5 encoded
        uc.setRequestProperty("X-RMS-UPW", upw); // md5 encoded
        uc.setRequestProperty("X-RMS-TID", tid);
        uc.setRequestProperty("Content-Length", length);
       
        // 보내기
        PrintWriter pw = new PrintWriter(uc.getOutputStream());
        pw.write(msg.toString());
        pw.flush();
        pw.close();
       
        // 받기
//        BufferedReader br = new BufferedReader(new InputStreamReader(uc.getInputStream()));
//        String str = null;
//        while((str = br.readLine()) != null) {
//            System.out.println(str);
//        }
       
        // 실질적으로 웹서버에 접속하여 요청을 보내고 응답을 수신하는 시점은 con.getResponseCode();로 판단된다.
        // getResponseCode() 를 호출하지 않으면, Network Connection 연결 요청 자체가 시도되지 않음이 확인되었다..
        // 실제로 서버로부터 아무런 정보도 받지 않더라도(현재 InputStream처리부분은 주석임), request의 결과로
        // response가 어떤지(성공/실패 등)를 받지 않으면 서버에 아무것도 보내지 않는듯.
        // 결국 서버가 request에 대한 처리를 하고 response를 주기 전까지는 대기상태. 동기화되어서 작동.
//        OutputStream out = uc.getOutputStream();// internally change to 'POST'
        int resCode = uc.getResponseCode(); // connect, send http reuqest, receive htttp request
        System.out.println ("code = "+ resCode);

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

[java] 소스 분석  (0) 2009.09.06
[HttpURLConnection] POST로 파라미터 넘기기  (0) 2009.07.27
CLASSPATH  (0) 2009.01.06
HttpURLConnection 사용례  (0) 2009.01.06
[펌] HttpURLConnection 을 이용하세요  (0) 2009.01.02
URLConnection을 이용해서 서버로 보낸 데이타를
         PrintWriter pw = new PrintWriter(uc.getOutputStream());
        
//        pw.write("url="+url);
        pw.write(sb.toString());
        
        pw.flush();
        pw.close();


서버의 서블릿에서 request의 input steam / reader를 이용해서 읽어들일 때
 //        String a = request.getParameter("//DATETIME[@type='T' and @qualifier='DOCUMENT']/YEAR"); // 이건 특수문자에 띄어쓰기까지 있어서 데이터를 념겨받을 수 없다
//        String a = request.getParameter("sap_element_01");
//        String b = request.getParameter("sap_element_02");
//        String c = request.getParameter("sap_element_03");
        
//        System.out.println(a);
        BufferedReader br = request.getReader();
        String str;
        StringBuffer sb = new StringBuffer();
        while((str = br.readLine()) != null) {
            sb.append(str);
        }
        br.close();
        
        PrintWriter w = response.getWriter();
        w.println(request.getParameter("sap_element_01") + " " + request.getParameter("sap_element_02") + " " + request.getParameter("sap_element_03"));
        w.flush();
        w.close();


읽어 들이기 전에 getParameter해버리면 아무런 데이타도 얻을 수 없다.(readLine할 때)
맨 위의 주석에 주목!

참고 : http://blog.dasida.com/1055732
http://www.exampledepot.com/egs/javax.servlet/GetReqUrl.html

A servlet container breaks up the requesting URL into convenient components for the servlet. The standard API does not require the original requesting URL to be saved and therefore it is not possible to get the requesting URL exactly as the client sent it. However, a functional equivalent of the original URL can be constructed. The following example assumes the original requesting URL is:
    http://hostname.com/mywebapp/servlet/MyServlet/a/b;c=123?d=789
The most convenient method for reconstructing the original URL is to use ServletRequest.getRequestURL(), which returns all but the query string. Adding the query string reconstructs an equivalent of the original requesting URL:
    // http://hostname.com/mywebapp/servlet/MyServlet/a/b;c=123?d=789
public static String getUrl(HttpServletRequest req) {
String reqUrl = req.getRequestURL().toString();
String queryString = req.getQueryString(); // d=789
if (queryString != null) {
reqUrl += "?"+queryString;
}
return reqUrl;
}
If the hostname is not needed, ServletRequest.getRequestURI() should be used:
    // /mywebapp/servlet/MyServlet/a/b;c=123?d=789
public static String getUrl2(HttpServletRequest req) {
String reqUri = req.getRequestURI().toString();
String queryString = req.getQueryString(); // d=789
if (queryString != null) {
reqUri += "?"+queryString;
}
return reqUri;
}
The original URL can also be reconstructed from more basic components available to the servlet:
    // http://hostname.com:80/mywebapp/servlet/MyServlet/a/b;c=123?d=789
public static String getUrl3(HttpServletRequest req) {
String scheme = req.getScheme(); // http
String serverName = req.getServerName(); // hostname.com
int serverPort = req.getServerPort(); // 80
String contextPath = req.getContextPath(); // /mywebapp
String servletPath = req.getServletPath(); // /servlet/MyServlet
String pathInfo = req.getPathInfo(); // /a/b;c=123
String queryString = req.getQueryString(); // d=789

// Reconstruct original requesting URL
String url = scheme+"://"+serverName+":"+serverPort+contextPath+servletPath;
if (pathInfo != null) {
url += pathInfo;
}
if (queryString != null) {
url += "?"+queryString;
}
return url;
}

[펌] SOAP란 무엇인가??

프로그래밍/읽을거리 2009. 2. 18. 16:46 Posted by galad
출처: http://blog.naver.com/devils129/80009306881
덧글 달려면 로그인 필수라 퍼간다는 글을 안남겼습니다. 문제있으면 알려주세요.


SOAP (Simple Object Access Protocol)이란 무엇인가?

 

SOAP이란 것은 무엇일까?

 

검색엔진에서 SOAP을 검색하면 무슨 비누, 향수, 샴푸등등... 이딴 것들만 검색된다.

그럼 SOAP은 세제란 뜻인가?  절대 그럴리 없다..

강좌가 무슨 빨래 이런 세제를 쓰면 살균 소독까지.. 강좌도 아니고 무슨 비누란 말인가?

아직은 SOAP이 표준화 과정에 있고 따라서 많은 자료들이 만들어지지 못해서 이런 일이 일어나는 뿐이다..   "(,. )a

 

SOAP은 XML과 HTTP 통신을 기반으로 하여 네트워크 상에 존재하는 각종 컴포넌트간의 호출을 효율적으로 실현하기 위한 방법을 제시하는 규약이다.

 

말이 어렵다.. 쉽게 말하면 네트워크 상에서 Client와 Service Provider간에 메시지를 요청하고 이에 응답해주는 방법을 제공하는 것이다..  이러한 방식들은 기존의 RPC(Remote Procedure Call)라 묶여서 불려오던 것들이다.. 따라서 SOAP은 RPC의 한가지 방법이라 수가 있다..  어려운가? ^^:

 

SOAP은 여러 Application Layer Protocol 중에 HTTP를 사용함으로써 여러 시스템간의 통신과 통합을 위한 좀더 단순하면서도 가벼운 메카니즘을 제공한다,,

이외에... HTTP를 사용하게 중요한 이유는 바로 방화벽에 제한을 받지 않는 범용성 때문이라 말할 있다.

 

다른 Application Layer Protocol의 경우 그들만의 약정된 TCP 또는 UDP 포트를 사용하기 때문에 인터넷상에 설치되어있는 방화벽에 많은 제약을 받게 된다.. 하지만 SOAP은 HTTP를 채택함으로써 방화벽의 제약을 받지 않고 불특정 다수의 클라이언트 또는 인터넷 상의 특정한 서버와의 RPC를 효율적으로 수행할 있도록 해준다.   

 

그렇다면 보안의 문제는 아예 생각지 않는 것인가? 이렇게 생각하는 사람도 있을지 모르겠다.. SOAP은 SOAP만이 가지는 특정한 HTTP Header를 방화벽의 필터링 부분에 보냄으로써 메시지의 통과여부를 가릴 있게 하는 방법으로 보안이라는 문제를 해결한다. 

 

SOAP은 현재 1.1버전이 널리 사용되고 있으며, w3c와 Microsoft등과 같은 쟁쟁한 몇몇 단체들이 모여 표준화 작업이 한창이다,, 현재는 1.2 버전까지 나온 상태이다..

자세한 내용은 www.w3c.org나 www.microsoft.com을 참조하기 바란다..

  

그럼 본격적으로 SOAP의 내부를 살펴보도록 하자..

 

SOAP은 크게 다음의 4가지로 구성되어있다..

 

° SOAP envelope

Message에 무엇이 있는가, 누가 무엇을 다루는가, 어떤 것이 Optional이고 mandatory인가를 나타내기 위한 전체적인 framework를 제공한다..

 

° SOAP encoding rules

Application에 정의된 data type들의 instance를 교환하는데 사용되는 메카니즘이다.

 

° SOAP RPC 표현

Remote procedure call과 response들을 나타내는데 사용되는 규약을 정의한다.

 

° SOAP binding

peer 간의 전송프로토콜을 사용하여 SOAP envelope 교환에 대한 규약을 정의한다.

 

위의 4가지 중에 envelope와 encoding rule은 서로 다른 namespace에 정의되어있는 XML 이며, link를 걸어놓음으로써 정의된 내용들을 사용할 있다. 

 

SOAP은 Message Based Protocol이기 때문에 시스템간의 통합 쌍방 간의 Message Format만을 약속하면 되므로 통합시간 효율을 높일 있으며, 매우 간단하다.

 

 

 

1. SOAP Message Exchange Model

 

SOAP은 HTTP 통신을 위한 Webserver, XML과 Service Provider의 3가지로 구성되어있다.

 

 


                                        < SOAP의 동작방식 >

 

 

1) Client가 어떤 Service Provider의 Service가 어떤 것이 있는지를 파악하기 위해 제공하는 Service의 목록을 HTTP를 통해 XML형태로 요청한다. (만약 목록을 이미 알고 있는 경우라면 과정은 생략가능)

 

2) Server는 자신이 제공하는 Service의 목록을 XML로 응답을 보낸다. (만약 목록을 이미 알고 있는 경우라면 과정은 생략가능)

 

3) 응답을 받은 Client는 자신이 원하는 Service를 알아내어 다시 Provider에 요청을 한다.

 

4) Provider는 받은 요청에 대한 처리를 결과를 되돌려 준다.

 

 

 

2. SOAP Message

 

다음은 HTTP Request 속에 포함된 SOAP Message의 구조이다..

 

POST /StockQuote HTTP/1.1

Host: www.stockquoteserver.com

Content-Type: text/xml; charset="utf-8"

Content-Length: nnnn

SOAPAction: "http://example.org/2001/06/quotes"

 

<Envelope ...>

   <Header>

      ......

   </Header>

 

   <Body>

      <Content>

         ......

      </Content>

   </Body>

</Envelope>

 

° Envelope : Root Tag로써 SOAP Message가 시작됨을 나타낸다.

° Header : 가외의 정보를 나타내기 위한 것으로 생략이 가능하다.

° Body : 내용이 들어가는 Tag이며 다양한 형태의 태그들이 들어간다.

° Content : 서비스에 대한 요청이나 응답이 들어간다.

 

 

일단 간단한 예제를 보면서 이해해보자..

 

SOAP은 XML의 형태로 Message를 교환한다,,,

 

 

Example 1 ( Request Message 형태 )

 

POST /StockQuote HTTP/1.1

Host: www.stockquoteserver.com

Content-Type: text/xml; charset="utf-8"

Content-Length: nnnn

SOAPAction: "http://example.org/2001/06/quotes"

 

<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope" >

 <env:Body>

  <m:GetLastTradePrice

        env:encodingStyle="http://www.w3.org/2001/06/soap-encoding"

        xmlns:m="http://example.org/2001/06/quotes">

    <symbol>DIS</symbol>

  </m:GetLastTradePrice>

 </env:Body>

</env:Envelope>

 

Service Provider가 가지고 있는 서비스 중에 LastTradePrice 정보를 요청하는 SOAP Message로 DIS의 값을 요구하고 있다.

 

 

 

Example 2 (Response Message 형태 )

 

HTTP/1.1 200 OK

Content-Type: text/xml; charset="utf-8"

Content-Length: nnnn

 

<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope" >

 <env:Body>

  <m:GetLastTradePriceResponse

        env:encodingStyle="http://www.w3.org/2001/06/soap-encoding"

        xmlns:m="http://example.org/2001/06/quotes">

   <Price>34.5</Price>

  </m:GetLastTradePriceResponse>

 </env:Body>

</env:Envelope>

 

Response Message의 경우에는 Client가 요청한 Service 이름에 Response가 붙게되며 (GetLastTradePriceResponse) Request에 대한 결과 값을 가지고 있다.

 

 

그럼 좀더 구체적으로 살펴보자,,

 

2-1. SOAP Envelope

 

SOAP Message는 필수항목인 SOAP envelope와 생략 가능한 SOAP Header 그리고 SOAP Body로  구성되어 있는 XML Document이다.

 

2-2. SOAP Header

 

SOAP는 Header라는 element를 통해 통신을 하는 쌍방 간의 어떤 제약없이 Message를 확장할 있는 융통성 있는 구조를 제공한다. 일반적으로 Header는 authentication이나 transaction과 같은 비교적 연관성이 없는 정보들을 구현할 있도록 해준다.  Header element는 SOAP Envelope 바로 다음에 오는 번째 Child element로서 모든 Header 다음에 오는 Child element들을 Header Entry라고 한다.

 

Example 3 ( SOAP Header block )

 

<env:Header xmlns:env="http://www.w3.org/2001/06/soap-envelope" >

  <t:Transaction xmlns:t="http://example.org/2001/06/tx" env:mustUnderstand="1" >

    5

  </t:Transaction>

</env:Header>

 

2-3 SOAP Body

 

SOAP Body element는 필수 정보를 교환하기 위해 사용되는 간단한 메카니즘을 제공한다, 일반적으로 Body는 어떤 결과나 error를 보고하기 위해 사용된다. Body는 SOAP Envelope 바로 다음에 오는 Child element로서 만약 Header가 존재하면 Header 다음에 와야하고 Header가 정의되어있지 않으면 Envelope 바로 다음에 와야한다. Header와 마찬가지로 Body element 바로 다음에 오는 Child element들을 Body entry라고 부른다.

 

2-4. Fault Code

 

SOAP은 error를 reporting 하기 위해 Fault element를 사용한다. Fault element는 다음과 같은 Child element로 구성된다.

 

° faultcode : Software나 Provider가 사용하는 error number로 error를 구분하기 위해 사용된다. 반드시 존재해야하는 element이다.

° faultstring : error에 대한 간단한 이유나 제목을 기술하며 반드시 존재해야하는 element이다.

° faultactor : message 경로에서 누구에 의해 야기되는 error인지에 대한 정보를 나타낸다. 반드시 존재해야하는 것은 아니다.

° detail : error에 대한 상세 정보를 기술한다. 반드시 요구되는 것은 아니고 사용자가 정의한 error tag가 있다.

 

Example 4 ( SOAP Fault Code )

 

<env:Envelope xmlns:env='http://www.w3.org/2001/06/soap-envelope'

                      xmlns:f='http://www.w3.org/2001/06/soap-faults' >

  <env:Header>

    <f:Misunderstood qname='abc:Extension1'

                                xmlns:abc='http://example.org/2001/06/ext' />

    <f:Misunderstood qname='def:Extension2'

                                xmlns:def='http://example.com/stuff' />

  </env:Header>

  <env:Body>

    <env:Fault>

      <faultcode>MustUnderstand</faultcode>

      <faultstring>One or more mandatory headers not understood</faultstring>

    </env:Fault>

  </env:Body>

</env:Envelope>



출처 : http://www.ibm.com/developerworks/kr/series/web/index.html
아래 내용은 위 출처의 기사의 일부를 복사 후 편집/수정한 것입니다.
단순히 개인적으로 알고자하는 내용만을 남긴 것이니, 자세한 정보는 위의 출처를 참조하세요.

JSON의 실질적 가치
JSON은 Ajax 애플리케이션을 위한 유용한 포맷으로서 JavaScript 객체와 스트링 값 사이를 빠르게 변환할 수 있게 해준다. Ajax 애플리케이션들은 플레인 텍스트를 서버 측 프로그램으로 보내고 받는데 가장 알맞고, 텍스트를 생성하는 API는 텍스트를 생성하지 않는 API를 통해서 이루어진다. JSON은 네이티브 JavaScript 객체들과 함께 작동할 수 있도록 해주며, 이러한 객체들이 표현되는 방식에 대해서는 걱정하지 않는다.

XML은 똑같은 텍스트 효과를 제공하지만, JavaScript 객체를 XML로 변환하는 API는 JSON API만큼 성숙하지 못했다. JavaScript 객체를 생성하여 여러분이 선택했던 XML 변환 API로 실행될 수 있는지를 확인해야 한다. JSON은 다르다. 매우 인지 가능한 객체 유형을 핸들하고 훌륭한 JSON 데이터 표현을 제공한다.

JSON의 가장 큰 가치는 JavaScript가 데이터-포맷 언어로서가 아닌 JavaScript로서 역할을 할 수 있다는 점이다. JavaScript 객체를 사용하면서 배운 모든 것을 코드에 적용할 수 있고, 이러한 객체들이 텍스트로 변환되는 방식에 대해서는 걱정할 필요가 없다. 이제 간단한 JSON 메소드 호출을 해보자.
String myObjectInJSON = myObject.toJSONString();

JSON을 서버로 보내기

GET을 통해 이름/값 쌍으로 JSON 보내기
JSON 데이터를 서버로 보내는 가장 쉬운 방법은 이것을 텍스트로 변환하고, 이름/값 쌍의 값으로 보내는 것이다. JSON으로 포맷된 데이터는 하나의 긴 객체일 뿐이다.

JSON 포맷으로 된 JavaScript 객체
var people =  { "programmers": [    { "firstName": "Brett", "lastName":"McLaughlin",
"email": "brett@newInstance.com" },    { "firstName": "Jason", "lastName":"Hunter",
"email": "jason@servlets.com" },    { "firstName": "Elliotte", "lastName":"Harold",
"email": "elharo@macfaq.com" }   ],  "authors": [    { "firstName": "Isaac",
"lastName": "Asimov", "genre": "science fiction" },    { "firstName": "Tad",
"lastName": "Williams", "genre": "fantasy" },    { "firstName": "Frank",
"lastName": "Peretti", "genre": "christian fiction" }   ],  "musicians": [   
{ "firstName": "Eric", "lastName": "Clapton", "instrument": "guitar" },  
{ "firstName": "Sergei", "lastName": "Rachmaninoff", "instrument": "piano" }   ]  }

이것을 이름/값 쌍으로서 서버 측 스크립트로 보낼 수 있다.
var url = "organizePeople.php?people=" + people.toJSONString();
xmlHttp.open("GET", url, true);
xmlHttp.onreadystatechange = updatePage;
xmlHttp.send(null);

잘 되는 것처럼 보이지만, 한 가지 문제가 있다. 웹 브라우저가 인터프리팅을 시도할 수도 있는 공간과 모든 종류의 문자들이 JSON 데이터에 생겼다. 이러한 문자들이 서버에서(또는 데이터를 서버로 전송할 때) 혼란을 일으키지 못하게 하려면, JavaScript escape() 함수를 추가한다.
var url = "organizePeople.php?people=" + escape(people.toJSONString());
request.open("GET", url, true);
request.onreadystatechange = updatePage;
request.send(null);

이 함수는 공백, 사선(slash) 등을 처리하고, 이것들을 안전한 문자로 변환한다. (예를 들면, 공백은 %20으로 변환되어, 브라우저는 이것을 공백으로 취급하지 않고, 변경되지 않은 채로 서버로 전달한다. 그리고 나면, 서버는 (일반적으로 자동으로) 이것을 전송 후에 다시 변환한다.

이러한 방식의 단점은 두 가지이다.
    * GET 요청을 사용하여 많은 데이터 청크를 보내는데, 이는 URL 스트링에 길이 제한을 갖고 있다. 이것은 허용되는 길이이지만, 객체의 JSON 스트링 표현의 길이는 가늠할 수 없다. 특히 매우 복잡한 객체를 사용할 때는 더욱 알 수가 없다.
    * 텍스트로서 네트워크를 통해서 모든 데이터를 보낼 때, 이는 매우 불안한 상태로 데이터를 보내는 것이다.

간단히 말해서, 이러한 문제들은 JSON 데이터와 구체적으로 관련이 있다기 보다는 GET 요청의 제한 요소라고 볼 수 있다. 하지만, 사용자의 이름과 성 이외의 것을 보낼 때 큰 문제가 된다. 원격으로 확인이 되었거나, 매우 긴 경우를 다룰 경우에는 POST를 고려해 볼 수 있다.

JSON 데이터의 포스팅(POST)
var url = "organizePeople.php?timeStamp=" + new Date().getTime();
request.open("POST", url, true);
request.onreadystatechange = updatePage;
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.send(people.toJSONString());

요청은 GET 대신 POST를 사용하여 열리고, Content-Type 헤더는 서버가 어떤 종류의 데이터를 기대하는지 알 수 있도록 설정된다. 이 경우, application/x-www-form-urlencoded인데, 이것은 서버가 텍스트를 통해 보낸 것이 일반 HTML 폼에서 온 것처럼 알도록 한다.

한 가지 주지할 점은 URL에 현재 시간을 붙였다는 점이다. 이로써 요청이 처음 보내진 후에 캐싱되지 않고, 메소드가 호출될 때마다 재생성 및 재전송 된다는 것이 확실해 진다. 이 URL은 변화하는 타임 스탬프 때문에 미묘하게 다르다. 이것은 스크립트로 POST 하는 것이 반복적으로 새로운 요청을 매번 생성하고 웹 브라우저는 서버에서 응답을 시도하고 저장하지 않는다.

JSON은 텍스트일 뿐이다!
GET 또는 POST를 사용하든지 간에, 중요한 것은 JSON은 단순한 텍스트 데이터일 뿐이라는 점이다. 특별한 인코딩을 필요로 하지 않으므로 쉽게 조작할 수 있고 서버로 보낼 수 있고, 모든 서버 측 스크립트는 텍스트 데이터를 처리할 수 있다.

서버에서 JSON 인터프리팅 하기
클라이언트 측 JavaScript 코드를 작성했고, 사용자들이 웹 폼과 페이지와 상호 작동 할 수 있도록 했고, 서버 측 프로그램으로 보내야 하는 정보를 수집했다면, 서버가 이제 중요한 역할을 할 차례이다.

JSON 두 단계
서버에서 어떤 언어를 사용하든지 간에, 서버 측에서 JSON을 작동시키는 것은 두 단계이다.
   1. 자신이 사용하고 있는 언어용 JSON parser/toolkit/helper API를 찾아서 서버 측 프로그램을 작성한다.
   2. JSON parser/toolkit/helper API를 사용하여 클라이언트에서 요청 데이터를 가져다가 이것을 스크립트가 이해할 수 있는 것으로 바꾼다.

JSON 파서 찾기
JSON 파서나 툴킷을 찾을 수 있는 최상의 리소스는 JSON 웹 사이트이다.
스크립트가 작성된 언어를 찾고 툴킷을 다운로드 한다. 이것을 제거, 확장, 설치하여(서버에서 C#, PHP, 또는 Lisp를 사용할 때 여러 변수들이 있다.) 서버 상의 스크립트와 프로그램이 이 툴킷을 사용할 수 있도록 한다.

JSON 파서 사용하기
프로그램에 사용할 수 있는 리소스가 있다면, 호출 할 올바른 메소드를 찾는 것이 중요하다.
예를 들어, PHP와 함께 JSON-PHP 모듈을 사용하고 있다면,
// This is just a code fragment from a larger PHP server-side script
require_once('JSON.php');

$json = new Services_JSON();

// accept POST data and decode it
$value = $json->decode($GLOBALS['HTTP_RAW_POST_DATA']);

// Now work with value as raw PHP
여기에서, 여러분은 모든 데이터 -- 배열 포맷, 다중 행, 단일 값, JSON 데이터 구조에 들어갈 것들 -- 를 $value 변수에 네이티브 PHP 포맷으로 한다.

서블릿에서 org.json 패키지를 사용한다면, 다음과 같이 한다.
public void doPost(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {

  StringBuffer jb = new StringBuffer();
  String line = null;
  try {
    BufferedReader reader = request.getReader();
    while ((line = reader.readLine()) != null)
      jb.append(line);
  } catch (Exception e) { //report an error }

  try {
    JSONObject jsonObject = new JSONObject(jb.toString());
  } catch (ParseException e) {
    // crash and burn
    throw new IOException("Error parsing JSON request string");
  }

  // Work with the data using methods like...
  // int someInt = jsonObject.getInt("intParamName");
  // String someString = jsonObject.getString("stringParamName");
  // JSONObject nestedObj = jsonObject.getJSONObject("nestedObjName");
  // JSONArray arr = jsonObject.getJSONArray("arrayParamName");
  // etc...
}

Ajax라는 용어는 새롭지만, 이를 구현하는 기술요소들은 전혀 새로운 것이 아닙니다. 하지만 이를 이용할 경우 사용자는 원하는 응답을 빠른 시간에 받을 수 있고 이에따라 서버의 부담이 줄어들며, 개발자는 페이지 화면구성을 다이나믹하게 할 수 있고, 플래시나 액티브엑스(ActiveX) 의존도를 상당부분 대체 할 수 있다는 장점이 있습니다.

그렇다는군...
출처 : http://www.ibm.com/developerworks/kr/series/web/index.html
아래 내용은 위 출처의 기사의 일부를 복사 후 편집/수정한 것입니다.
단순히 개인적으로 알고자하는 내용만을 남긴 것이니, 자세한 정보는 위의 출처를 참조하세요.

선택할 수 있는 권한
여러분에게 선택권이 많이 주어지고 문제에 대한 옵션들이 많아질수록, 단 하나의 솔루션 보다는 문제에 대한 최상의 솔루션을 찾을 수 있는 더 좋은 기회들이 생기기 때문이다.

name/value 쌍과 XML
본 시리즈에서는 name/value 쌍이 적합한 상황과 XML을 사용하기에 적합한 상황에 대해 이미 다루었다. 거듭 말하지만, 여러분은 우선 name/value 쌍을 사용하는 것을 늘 생각해야 한다. 이것은 대부분의 비동기식 애플리케이션에서 생기는 문제들에 대한 가장 간단한 솔루션이고, JavaScript에 대한 기본적인 지식만 있어도 간단히 해결된다.

여러분은 XML로 전향하는데 제약이 없다면 대안 데이터 포맷을 사용하는 것에 관해 걱정할 필요가 없다. 확실히, XML 포맷의 입력을 요하는 서버 측 프로그램으로 데이터를 보낸다면, 데이터 포맷으로 XML을 사용해야 한다. 대부분의 경우, XML은 애플리케이션에 여러 정보 조각들을 보내야 하는 서버용으로 적합하다. 다시 말해서, XML은 Ajax 애플리케이션으로부터의 요청 보다는, Ajax 애플리케이션으로의 응답으로 더 일반적으로 사용된다.

JSON 기초
JSON으로는 JavaScript 객체로 표현된 데이터를 한 함수에서 다른 함수로, 또는 비동기식 애플리케이션의 경우, 웹 클라이언트에서 서버 측 프로그램으로 쉽게 전달할 수 있는 스트링으로 변형할 수 있다. 문자열이 약간 이상해 보이지만 JavaScript에 의해 쉽게 인터프리팅 되고, JSON은 name/value 쌍 보다 복잡한 구조도 표현한다. 예를 들어, 단순한 키와 값 리스트 대신, 배열과 복합 객체들을 나타낼 수 있다.

JSON 예제
JSON에서는 name/value 쌍이 다음과 같이 표현된다.
 { "firstName": "Brett" }

JSON은 여러 name/value 쌍들을 하나로 연결할 때 진가를 발휘한다. 우선, 다음과 같이, 여러 name/value 쌍으로 데이터 레코드를 생성할 수 있다.
 { "firstName": "Brett", "lastName":"McLaughlin", "email": "brett@newInstance.com" }

신택스의 관점에서 보면 name/value 쌍 보다 나은 점이 없어 보이지만, 이 경우, JSON은 훨씬 더 사용하기 쉬우며, 가독성도 놀랍다. 예를 들어, 위 세 개의 값들은 같은 레코드의 일부이다. 중괄호는 그 값이 같은 커넥션을 갖고 있다는 것을 표시하고 있다.

값들의 배열
JSON에서는 다음과 같이 괄호를 사용하여 레코드를 그룹핑 할 수 있다.
{ "people": [
  { "firstName": "Brett", "lastName":"McLaughlin", "email": "brett@newInstance.com" },
  { "firstName": "Jason", "lastName":"Hunter", "email": "jason@servlets.com" },
  { "firstName": "Elliotte", "lastName":"Harold", "email": "elharo@macfaq.com" }
]}

이해하기도 어렵지 않다. 이 경우, people이라는 하나의 변수가 있고, 값은 세 개의 아이템을 포함하고 있는 배열이며, 각각의 레코드에는 이름, 성, 이메일 주소가 있다. 위 예제는 레코드들을 모두 투입하는 방법과, 아이템을 괄호가 있는 싱글 값으로 그룹핑 하는 방법을 설명하고 있다.
{ "programmers": [
  { "firstName": "Brett", "lastName":"McLaughlin", "email": "brett@newInstance.com" },
  { "firstName": "Jason", "lastName":"Hunter", "email": "jason@servlets.com" },
  { "firstName": "Elliotte", "lastName":"Harold", "email": "elharo@macfaq.com" }
 ],
"authors": [
  { "firstName": "Isaac", "lastName": "Asimov", "genre": "science fiction" },
  { "firstName": "Tad", "lastName": "Williams", "genre": "fantasy" },
  { "firstName": "Frank", "lastName": "Peretti", "genre": "christian fiction" }
 ],
"musicians": [
  { "firstName": "Eric", "lastName": "Clapton", "instrument": "guitar" },
  { "firstName": "Sergei", "lastName": "Rachmaninoff", "instrument": "piano" }
 ]
}

여기에서 주목해야 할 점은 각각이 다수의 값을 내포하고 있는 많은 값들을 표현할 수 있는 당신의 능력이다. 또 하나 주목해야 할 점은 레코드의 name/value 쌍들은 다른 메인 항목(programmers, authors, musicians)에 따라 변한다는 것이다. JSON은 완전히 동적이고, JSON 구조 안에서 데이터를 표현하는 방식을 바꿀 수 있다.

또 한 가지 알아두어야 할 것은 JSON 포맷 데이터로 작업할 때 제약 조건이 없다는 점이다. 따라서, 어떤 것을 표현하는 방식을 바꿀 수 있고, 심지어는 같은 데이터 구조 내에서 같은 것을 다른 방식으로 나타낼 수도 있다

JavaScript에서 JSON 사용하기
JSON 포맷을 다룬 후라면, JavaScript에서 이것을 사용하는 것은 간단하다. JSON은 네이티브 JavaScript 포맷이고, JavaScript 내에서 JSON 데이터와 작업하기 위해 특별한 API나 툴킷이 필요 없다.

JSON 데이터를 변수에 할당하기
예를 들어, 새로운 JavaScript 변수를 만들고, JSON 포맷 데이터 스트링을 여기에 직접 할당한다고 해보자.
var people =
  { "programmers": [
    { "firstName": "Brett", "lastName":"McLaughlin", "email": "brett@newInstance.com" },
    { "firstName": "Jason", "lastName":"Hunter", "email": "jason@servlets.com" },
    { "firstName": "Elliotte", "lastName":"Harold", "email": "elharo@macfaq.com" }
   ],
  "authors": [
    { "firstName": "Isaac", "lastName": "Asimov", "genre": "science fiction" },
    { "firstName": "Tad", "lastName": "Williams", "genre": "fantasy" },
    { "firstName": "Frank", "lastName": "Peretti", "genre": "christian fiction" }
   ],
  "musicians": [
    { "firstName": "Eric", "lastName": "Clapton", "instrument": "guitar" },
    { "firstName": "Sergei", "lastName": "Rachmaninoff", "instrument": "piano" }
   ]
  }

데이터에 액세스 하기
programmers 리스트의 첫 번째 엔트리의 성(last name)에 액세스 하려면, JavaScript에서 다음과 같은 코드를 사용해야 한다.
 people.programmers[0].lastName;

인덱싱은 '0' 부터 시작한다. 따라서, 이것은 people 변수에 있는 데이터로 시작한다. 그리고 나서, programmers라고 하는 아이템으로 이동하고, 첫 번째 레코드([0])에 액세스 한다. 마지막으로, lastName 키의 값에 액세스 한다. 결과는 "McLaughlin"이라는 스트링 값이다.
people.authors[1].genre            // Value is "fantasy"

people.musicians[3].lastName        // Undefined. This refers to the fourth entry, and there isn't one

people.programmers.[2].firstName    // Value is "Elliotte"

JSON 데이터 수정하기
위에 나타난 점과 괄호 표기법을 사용하여 데이터에 액세스 하듯, 같은 방식으로 데이터를 쉽게 수정할 수 있다.
 people.musicians[1].lastName = "Rachmaninov";

문자열로 변환하기
물론, 모든 데이터 수정은 텍스트 포맷으로 쉽게 변환할 수 없다면 가치가 없다. 이것 역시 JavaScript에서는 간단하다.
 String newJSONtext = people.toJSONString();

이것이 다이다. 원하는 곳 어디에서나 사용할 수 있는 텍스트 문자열이 생겼으니, 이것을 Ajax 애플리케이션에서 요청 스트링으로 사용할 수 있다.

훨씬 더 중요한 것은, 어떤 JavaScript 객체라도 JSON 텍스트로 변환할 수 있다. 원래 JSON 포맷 스트링으로 할당된 변수로만 작업할 필요가 없다. myObject라는 객체를 변형하려면, 같은 종류의 명령어를 실행하면 된다.
 String myObjectInJSON = myObject.toJSONString();


출처 : http://www.ibm.com/developerworks/kr/series/web/index.html
아래 내용은 위 출처의 기사의 일부를 복사 후 편집/수정한 것입니다.
단순히 개인적으로 알고자하는 내용만을 남긴 것이니, 자세한 정보는 위의 출처를 참조하세요.

Google Ajax Search API 설정하기
Google에서 개발자 키 얻기
Google에서 받은 여러분의 개발자 키로 대체하는 것을 잊지 말라.

JavaScript 분해

새로운 GSearchControl 생성하기
먼저, 새로운 GSearchControl이 만들어진다. 이것은 모든 검색을 수행할 수 있도록 해주는 구조이다.
function OnLoad() {
  // Create the Google search control
  var searchControl = new GSearchControl();

  ...
}
그런 다음 이 코드는 GlocalSearch를 사용하여 새로운 로컬 검색을 설정한다. 이것은 특정 위치에 기반한 검색을 수행하는 특별한 Google 구조이다.

새로운 로컬 검색 설정하기
새로운 로컬 검색자를 만든 다음, 검색의 중심 포인트를 설정한다.
function OnLoad() {
  // Create the Google search control
  var searchControl = new GSearchControl();

  // These allow you to customize what appears in the search results
  var localSearch = new GlocalSearch();
  ...                            

  // Tell Google your location to base searches around
  localSearch.setCenterPoint("Dallas, TX");

  ...
}

검색 유형
검색 컨트롤에게 어떤 유형의 검색을 수행해야 하는지를 지시하고 있다.
function OnLoad() {
  // Create the Google search control
  var searchControl = new GSearchControl();

  // These allow you to customize what appears in the search results
  var localSearch = new GlocalSearch();
  searchControl.addSearcher(localSearch);
  searchControl.addSearcher(new GwebSearch());
  searchControl.addSearcher(new GvideoSearch());
  searchControl.addSearcher(new GblogSearch());

  // Tell Google your location to base searches around
  localSearch.setCenterPoint("Dallas, TX");

  ...
}

여러 가지 검색 유형들을 요약하면 다음과 같다.

    * GwebSearch: 웹 검색용 객체이고, Google은 이것으로 유명해졌다.
    * GvideoSearch: 검색어와 관련된 비디오를 찾는다.
    * GblogSearch: 이 객체는 블로그를 통한 검색에 특별한 초점을 맞추고 있는데, 다른 웹 콘텐트 유형과는 약간 다르게 구성되고, 다른 태그가 붙는다.

draw() 메소드 호출
이 호출을 HTML에 있는 DOM 엘리먼트에 준다.

검색 컨트롤 가져오기
function OnLoad() {
  // Create the Google search control
  var searchControl = new GSearchControl();

  // These allow you to customize what appears in the search results
  var localSearch = new GlocalSearch();
  searchControl.addSearcher(localSearch);
  searchControl.addSearcher(new GwebSearch());
  searchControl.addSearcher(new GvideoSearch());
  searchControl.addSearcher(new GblogSearch());

  // Tell Google your location to base searches around
  localSearch.setCenterPoint("Dallas, TX");

  // "Draw" the control on the HTML form
  searchControl.draw(document.getElementById("searchcontrol"));

  searchControl.execute("Christmas Eve");
}

Ajax는 어디에 있는가?
검색어를 입력하고 Search 버튼을 클릭하면, 매우 Ajax 다운 응답을 보게 된다. 검색 결과는 페이지를 재 로딩하지 않아도 나타난다. 바로 이것이 대부분의 Ajax 애플리케이션의 특징이다. 페이지를 다시 로딩하지 않고 시각적인 콘텐트 변화가 이루어 진다.

가장 중요한 JavaScript 파일
<script
    src="http://www.google.com/uds/api?file=uds.js&v=1.0&key=[YOUR GOOGLE KEY]"
    type="text/javascript"> </script>
신택스는 특별한 것은 없지만, 중요한 것은 Google이 uds.js라는 파일을 호스팅하는데, 이 안에 검색 박스가 작동하는데 필요한 모든 JavaScript가 들어있다는 점이다. 엄밀히 말하면 다른 사람들의 코드를 사용하고 있는 것이다. 여러분은 서드 파티가 여러분의 애플리케이션이 사용하는 코드를 호스팅 하도록 할 수 있다. Google은 보존과 관리까지 다루기 때문에 이것은 매우 중요하고, 기업이 JavaScript 파일을 업그레이드 할 때 자동적으로 혜택이 미친다. Google은 여러분 모르게 API를 변경하지 않기 때문에 여러분의 코드는 JavaScript 파일이 수정되더라도 계속 실행된다.

GSearchControl 객체
여기에서 숨겨진 한 가지는 GSearchControl 객체용 코드로서 onLoad() JavaScript 함수에서 생성된다.

GSearchControl 객체 생성하기
// Create the Google search control
var searchControl = new GSearchControl();

검색 컨트롤을 만드는데 필요한 모든 HTML
<div id="searchcontrol" />

위의 검색 컨트롤용 HTML에 실제로 그려넣기
// "Draw" the control on the HTML form
searchControl.draw(document.getElementById("searchcontrol"));

Google에서 API Key를 얻을 때, 어느 사이트에서 사용할 것인가를 등록하지 않으면 안되므로, localhost에서는 테스트 불가

http://lonelycat.hosting.paran.com/test/04_ajax_test.html
출처 : http://www.ibm.com/developerworks/kr/series/web/index.html
아래 내용은 위 출처의 기사의 일부를 복사 후 편집/수정한 것입니다.
단순히 개인적으로 알고자하는 내용만을 남긴 것이니, 자세한 정보는 위의 출처를 참조하세요.

Ajax 애플리케이션에서, 송신 데이터 포맷으로서 XML을 사용하는 경우는 드물지만, 서버에서 XML을 클라이언트로 보내야 하는 이유는 충분하다.

클라이언트는 이름/값 쌍으로 말한다.
클라이언트는 대부분의 경우에 XML을 사용할 필요가 없다. 이름값 쌍을 사용하여 요청을 보낼 수 있기 때문이다. 따라서, 다음과 같이 이름을 보내게 된다: name=jennifer. 또한 이어지는 이름값 쌍들은 앰퍼샌드(&)를 사용하여 추가할 수 있다: name=jennifer&job=president. 간단한 텍스트와 이러한 이름값 쌍을 사용하면, 클라이언트는 여러 값을 가진 요청을 서버로 쉽게 보낼 수 있다. XML이 제공하는 추가 구조(오버헤드)가 필요 없다.

사실, XML을 서버로 보내야 하는 대부분의 이유들이 다음 두 개의 범주로 나뉠 수 있다.

    * 서버는 XML 요청을 수락하기만 한다. 이 경우, 선택권이 없다. 지난 달 기술자료에서, 이러한 유형의 요청들을 보낼 때 필요한 모든 툴을 제공했다.
    * XML 요청이나 SOAP 요청만 수락하는 원격 API를 호출할 경우. 이것은 매우 특별한 케이스이지만, 짚고 넘어가야 한다. 비동기식 요청에서 Google이나 Amazon에서 API를 사용할 경우, 특별히 고려해야 할 것이 있다. 다음 달 기술자료에서 API로 요청하는 문제를 예제를 통해 설명하겠다.

서버는 (표준 방식으로) 이름값 쌍을 보낼 수 없다.
서버가 name=jennifer&job=president 스트링으로 애플리케이션에 응답한다면, 클라이언트는 두 개의 이름값 쌍을 나누고, 각 쌍을 이름과 값으로 나눌 표준화 된 쉬운 방법이 없다. 리턴된 데이터를 직접 파싱해야 할 것이다. 서버가 이름값 쌍으로 구성된 응답을 리턴하면, 응답은 세미콜론, 파이프 심볼, 기타 비표준 포맷팅 문자로 구분된 엘리먼트를 가진 응답만큼이나 해석하기 어렵다.

응답에 플레인 텍스트를 사용하고, 적어도 응답에 여러 값이 포함되어 있을 때, 클라이언트가 그 응답을 받아서 표준 방식으로 인터프리팅 해야 하는 쉽지 않은 방식이다. 서버가 넘버 42를 보냈다면, 플레인 텍스트로도 충분하다. 하지만, TV 쇼 Lost, Alias,, Six Degrees,의 최근 시청률을 보냈다면? 여러분은 플레인 텍스트를 사용하여 이 응답을 보낼 많은 방법들을 선택할 수 있지만(Listing 1), 클라이언트에 의한 작업 없이는 쉬운 인터프리팅 방법이 없고, 표준화된 방법도 없다.

싱글 스페이스(single space)!
대부분의 HTTP 요청에서, %20은 싱글 스페이스를 나타내는데 사용된다. 따라서 "Live Together, Die Alone"이라는 텍스트는 Live%20Together,%20Die%20Alone 형태로 HTTP로 보내진다.

이러한 응답 스트링들을 나누는 방법을 알아내는 것이 어려운 일은 아니지만, 클라이언트는 세미콜론, 등가 표시, 파이프, 앰퍼샌드에 따라 스트링을 파싱하고 나누어야 한다. 이는 다른 개발자들이 쉽게 이해하고 관리할 수 있는 강력한 코딩 방법이 아니다.

XML
이름값 쌍으로 서버가 클라이언트에 응답하는 표준 방법이 없다는 것을 깨달았다면, XML을 사용해야 하는 이유가 분명해진다. 데이터를 서버로 보낼 때, 이름값 쌍은 최상의 선택이다. 서버와 서버 측 언어는 그 쌍들을 쉽게 인터프리팅 할 수 있기 때문에다. 마찬가지로, 데이터를 클라이언트로 리턴할 때 XML을 사용하면 일이 쉬워진다. 이전 기술자료들에서 XML을 파싱할 때 DOM을 사용하는 것에 대해 다루었고, 앞으로의 기술자료에서는 JSON이 XML을 파싱하는 옵션을 어떻게 제공하는지를 설명할 것이다. 무엇보다도, 여러분은 XML을 플레인 텍스트로서 취급할 수 있고, 이러한 방식으로 값을 얻어낼 수 있다. 따라서, 서버에서 XML 응답을 얻을 수 있는 여러 가지 방식이 있고, 매우 표준적인 방식으로 클라이언트에 있는 데이터를 가져다가 사용할 수 있다.

서버에서 XML 받기
서버에서 오는 XML 응답을 두 가지 기본 방식으로 취급할 수 있다.

    * XML로 포맷팅 되는 플레인 텍스트
    * DOM Document 객체로 나타나는, XML 문서

XML을 플레인 텍스트로서 처리하기
마치, 서버가 비 XML 응답을 보낼 때처럼, 요청 객체의 responseText 속성을 사용한다
function updatePage() {
  if (request.readyState == 4) {
    if (request.status == 200) {
      var response = request.responseText;

      // response has the XML response from the server
      alert(response);
    }
  }
}
updatePage()는 콜백이고, request는 XMLHttpRequest 객체이다. 모든 것이 response 변수 안에 이어진 XML 응답이 될 것이다. 이 변수를 프린트하면,
<ratings><show><title>Alias</title><rating>6.5</rating></show><show><title>Lost</title><rating>14.2</rating></show><show><title>Six Degrees</title><rating>9.1</rating></show></ratings>
서버는 스페이스와 캐리지 리턴으로 XML을 포맷팅 하지 않는다. 단지 하나로 연결할 뿐이다. 물론, 애플리케이션은 스페이싱(spacing)에 대해서 신경 쓰지 않는다. 다만 읽기가 힘들어질 뿐이다.

이때, JavaScript split 함수를 사용하여 데이터를 나누고, 기본 스트링 조작을 통해서 엘리먼트 이름과 값을 얻을 수 있다. 물론, 이것은 엄청난 작업이고, 이전 시리즈에서 다루었던 DOM(Document Object Model)을 보는데 많은 시간을 보내야 한다.  DOM을 사용할 수 있다면, 이러한 방식을 사용하여 XML 데이터를 얻어서는 안된다.

XML을 XML로 취급하기
JavaScript와 XMLHttpRequest 객체는 서버의 XML 응답을 완벽하게 얻고 이것을 DOM Document 객체 폼으로 얻을 수 있는 속성을 제공한다.

콜백이 responseXML 속성을 사용한다. XMLHttpRequest에 사용할 수 있는 이 속성은 DOM 문서의 형태로 서버 응답을 리턴한다.
function updatePage() {
  if (request.readyState == 4) {
    if (request.status == 200) {
      var xmlDoc = request.responseXML;

      // work with xmlDoc using the DOM
    }
  }
}
DOM Document가 생겼으니, 다른 XML처럼 작업할 수 있다.

모든 show 엘리먼트 얻기
function updatePage() {
  if (request.readyState == 4) {
    if (request.status == 200) {
      var xmlDoc = request.responseXML;

      var showElements = xmlDoc.getElementsByTagName("show");
    }
  }
}

모든 show 엘리먼트들을 통해 반복하기
function updatePage() {
  if (request.readyState == 4) {
    if (request.status == 200) {
      var xmlDoc = request.responseXML;

      var showElements = xmlDoc.getElementsByTagName("show");
      for (var x=0; x<showElements.length; x++) {
        // We know that the first child of show is title, and the second is rating
        var title = showElements[x].childNodes[0].value;
        var rating = showElements[x].childNodes[1].value;

        // Now do whatever you want with the show title and ratings
      }
    }
  }
}

XML을 인터프리팅 하는 기타 옵션
XML을 다루는 한 가지 매우 일반적인 옵션들은, 포맷팅 되지 않은 텍스트로서 취급하는 것 또는 DOM을 사용하는 것 이상으로 중요하다. 이것이 바로 JSON, (JavaScript Object Notation)이고, JavaScript에 포함된 무료 텍스트 포맷이다.

일반적으로, JSON을 사용하여 할 수 있는 모든 것은, DOM을 사용해서도 할 수 있다. 그 반대의 경우도 마찬가지다. 이것은 선호도의 문제이고, 특정 애플리케이션에 알맞은 방식을 선택하는 문제이다.

가장 중요한 것은 XML이 자신의 애플리케이션에 잘 맞는지를 생각하는 것이다. 많은 경우, 애플리케이션이 잘 작동한다면, XML은 그냥 유행어에 지나지 않고, XML을 사용해야 할 것 같은 유혹과 싸워야 한다. 서버가 보내는 데이터가 제한되어 있거나, 이상한 콤마 또는 파이프로 구분된 포맷으로 되어있다면, XML이 확실히 도움이 될 것이다. 서버 측 컴포넌트로 작업하거나 이를 변경하는 것을 고려하여, XML을 사용하여, XML만큼 강력하지 않은 상용 포맷을 사용하는 것 보다는, 표준 방식으로 응답을 리턴할 수 있다.
출처 : http://www.ibm.com/developerworks/kr/series/web/index.html
아래 내용은 위 출처의 기사의 일부를 복사 후 편집/수정한 것입니다.
단순히 개인적으로 알고자하는 내용만을 남긴 것이니, 자세한 정보는 위의 출처를 참조하세요.

평범한 Ajax 개발자들도 Ajax 단어에 있는 x가 XML.을 의미한다는 것 정도는 알고 있다. XML을 통하지 않고서는 중요한 프로그래밍을 수행할 수 없다. 많은 사람들은 이 확장성 있는 마크업 언어를 사용한다. 이쯤 되면, XML이 Ajax를 지탱하고 있는 핵심 기술로 간주되는 것쯤은 놀랄 일도 아니다.

하지만, Ajax 애플리케이션에서 사용되는 핵심 객체(XMLHttpRequest)의 의미를 생각해 봐야 한다. 대부분의 사람들은, XMLHttpRequest 객체가 실제로 언제나 XML을 사용한다고 생각하기 때문에, XML을 Ajax의 핵심 부분으로 생각한다. 이는 사실이 아니며, 그 이유를 밝히는 것이 이 글의 목적이다. 사실, 대부분의 Ajax 애플리케이션에서, XML이 거의 나타나지 않는다.

XMLHttpRequest: 의미와 HTTP

Ajax 애플리케이션에서 사용되는 기본 객체인 XMLHttpRequest에서도 이 같은 일이 발생한다. 이것은 HTTP 요청을 통해서 XML을 보내거나, 일종의 XML 포맷으로 HTTP 요청을 만드는 것처럼 여겨진다. 객체 이름이 어떤 뉘앙스를 풍기든 상관없이, 이것은 실제로 클라이언트 코드(대게 웹 페이지에 있는 JavaScript)가 HTTP 요청을 보낼 수 있는 방식을 제공한다. 이것이 전부이다. 더 이상 어떤 것도 없다.

XMLHttpRequest 객체는 XML이나 HTTP 그 자체 보다는, 페이지 리로드 없이 요청을 할 수 있는 것 이상의 의미를 풍긴다. 요청에 XML을 명확하게 사용하거나, 서버가 XML로 된 응답을 보내지 않는 한,XMLHttpRequest 객체에서 사용되는 것은 평범하고 오래된 HTTP 뿐이다. XML은 전송 프로토콜이 아닌 데이터 포맷이라는 점

경고

XML은 작고, 빠르며, 공간 절약형 포맷이 아니다. 다음 여러 섹션들과 다음 기술자료에서 보겠지만, 어떤 정황에서 XML을 사용해야 하는 몇 가지 이유가 있고, XML이 플레인 텍스트 요청과 응답보다 더 나은 점도 갖고 있다. 하지만, XML은 플레인 텍스트 보다 더 많은 공간을 차지하고, 더 느리다.

매우 빠른 애플리케이션을 작성하고 싶다면, XML은 올바른 선택이 아니다. 플레인 텍스트로 시작하고, 특정 부분에서 XML이 필요할 경우, 그때 XML을 선택하는 것이 좋다. 하지만, 처음부터 XML을 사용한다면, 애플리케이션의 반응이 늦어진다. 대부분의 경우, 다음과 같이 텍스트를 XML로 전환하는 것 보다는 name=jennifer 같은 이름/값 쌍을 사용하여 플레인 텍스트를 보내는 것이 더 빠르다:
<name>jennifer</name>

XML을 클라이언트에서 서버로

여러분이 작성하는 웹 애플리케이션의 90퍼센트 정도가 이름/값 쌍을 서버로 보낸다. 예를 들어, 사용자가 이름과 주소를 웹 페이지의 폼에 입력하면, 폼에서 다음과 같은 데이터를 얻는다:
firstName=Larry
lastName=Gullahorn
street=9018 Heatherhorn Drive
city=Rowlett
state=Texas
zipCode=75080

플레인 텍스트로 된 이름/값 쌍 보내기
function callServer() {
  // Get the city and state from the Web form
  var firstName = document.getElementById("firstName").value;
  var lastName = document.getElementById("lastName").value;
  var street = document.getElementById("street").value;
  var city = document.getElementById("city").value;
  var state = document.getElementById("state").value;
  var zipCode = document.getElementById("zipCode").value;

  // Build the URL to connect to
  var url = "/scripts/saveAddress.php?firstName=" + escape(firstName) +
    "&lastName=" + escape(lastName) + "&street=" + escape(street) +
    "&city=" + escape(city) + "&state=" + escape(state) +
    "&zipCode=" + escape(zipCode);

  // Open a connection to the server
  xmlHttp.open("GET", url, true);

  // Set up a function for the server to run when it's done
  xmlHttp.onreadystatechange = confirmUpdate;

  // Send the request
  xmlHttp.send(null);
}

이름/값 쌍을 XML로 변환하기

여러분은 서버가 기대하고 잇는 것이 무엇인지를 파악하고, 데이터와 포맷을 혼합해야 한다. 그리고 나서야, 클라이언트에서 서버로 XML을 보낼 수 있는 기술을 다룰 준비가 되는 것이다.

서버로 XML 보내기

서버로 XML을 보낼 때, 데이터를 실제로 전송하는 것 보다, 데이터를 취해서 이를 XML로 래핑하는데 코드 작업을 더 많이 해야 한다. 사실, 서버로 보낼 준비가 된 XML 스트링이 있다면, 다른 플레인 텍스트를 보내는 것과 똑같이 보낸다.

XML로 된 이름/값 쌍 보내기
function callServer() {
  // Get the city and state from the Web form
  var firstName = document.getElementById("firstName").value;
  var lastName = document.getElementById("lastName").value;
  var street = document.getElementById("street").value;
  var city = document.getElementById("city").value;
  var state = document.getElementById("state").value;
  var zipCode = document.getElementById("zipCode").value;

  var xmlString = "<profile>" +
    "  <firstName>" + escape(firstName) + "</firstName>" +
    "  <lastName>" + escape(lastName) + "</lastName>" +
    "  <street>" + escape(street) + "</street>" +
    "  <city>" + escape(city) + "</city>" +
    "  <state>" + escape(state) + "</state>" +
    "  <zip-code>" + escape(zipCode) + "</zip-code>" +
    "</profile>";

  // Build the URL to connect to
  var url = "/scripts/saveAddress.php";

  // Open a connection to the server
  xmlHttp.open("POST", url, true);

  // Tell the server you're sending it XML
  xmlHttp.setRequestHeader("Content-Type", "text/xml");

  // Set up a function for the server to run when it's done
  xmlHttp.onreadystatechange = confirmUpdate;

  // Send the request
  xmlHttp.send(xmlString);
}

JavaScript를 사용하는 XML 문서를 만들기 위해 DOM을 사용하지 말란 법은 없지만, GET 또는 POST 요청으로 네트워크를 통해서 이것을 보내기 전에 DOM 객체를 텍스트로 변환해야 한다. 따라서, 일반적인 스트링 조작을 통해 데이터를 포맷팅 하는 것이 훨씬 더 쉽다. 물론, 에러와 타이핑 실수가 있을 수 있으므로, XML을 다루는 코드를 작성할 때 특별히 주의를 기울여야 한다.

XML을 구현하면, 텍스트를 보낼 때와 거의 같은 방법으로 연결을 구축한다. 나는 XML에 POST 요청을 사용하는 것을 더 좋아한다. 어떤 브라우저는 GET 쿼리 스트링에 길이 제한을 두고, 게다가 XML은 길이가 매우 길어질 수 있기 때문이다.  여러분이 요청한 URL의 끝에 고정된 매개변수로서가 아닌, send() 메소드를 통해 XML이 보내진다.
xmlHttp.setRequestHeader("Content-Type", "text/xml");

이해하기 어렵지 않다: 평이한 이름/값 쌍이 아닌 XML로 보낼 것을 서버에 명령하고 있다. 두 경우 모두, 데이터를 텍스트로 보내지만, 여기에서는 text/xml을 사용하거나 플레인 텍스트로 보내진 XML을 보낸다.

XML 보내기: 좋은 것인가, 나쁜 것인가?

XML은 구현이 간단하지 않다.
요청에 사용할 XML은 구성하기가 쉽지 않다. 또 다른 문제는 XML을 직접 구현해야 한다는 점이다. DOM 객체를 요청으로 보낼 수 있는 스트링으로 전환하는 것은 간단한 방법이 아니므로, DOM을 사용하는 것은 좋지 않다. 따라서, 이와 같이 스트링으로 작업하는 것이 최고의 방법이다. 하지만, 관리하기 어렵고, 새로운 개발자들이 이해하기 힘든 방식이기도 하다.

XML은 요청에 어떤 것도 추가하지 않는다.

복잡성 문제 외에도, 요청에 XML을 사용하면 플레인 텍스트와 이름/값 쌍 보다 더 나은 점도 없다. 플레인 텍스트를 사용하여 보낼 수 없는 것을 XML을 사용하여 보낼 수 있다라고 말하는 것이 아니다. 플레인 텍스트를 사용하여 보낼 수 없는 것을 XML을 사용한다고 해서 가능해지는 것은 결코 아니기 때문이다.

이것이 XML과 요청의 본질이다. 여기에 중요한 이유는 없다. 다음 글에서는, 플레인 텍스트를 사용할 때 다루기 어려웠던 몇 가지 사안들을 XML로 해결하는 방법에 대해 설명하겠다. 오직 XML만 받아들일 것을 스크립트에 명령하지 않을 것이라면, 거의 모든 요청 상황에서 플레인 텍스트를 사용하는 것이 더 낫다.
출처 : http://www.ibm.com/developerworks/kr/series/web/index.html
아래 내용은 위 출처의 기사의 일부를 복사 후 편집/수정한 것입니다.
단순히 개인적으로 알고자하는 내용만을 남긴 것이니, 자세한 정보는 위의 출처를 참조하세요.

HTML의 마지막 포인트

폼에 있는 버튼이 제출 버튼이 아닌 button 유형이라는 것이다. 제출 버튼을 사용할 경우, 버튼을 누르면 브라우저가 폼을 제출하게 된다. 물론, 이 폼은 어떤 action 애트리뷰트(완전히 의도적인)가 없기 때문에, 이것은 어떤 액티비티도 없는 무한 루프만을 만들게 된다. (직접 실험해 봐도 좋다.) 정상적인 인풋 버튼을 사용하고, 제출 버튼을 피하면, JavaScript 함수를 버튼에 연결하고 폼을 제출하지 않고 브라우저와 인터랙팅 한다.

이벤트 핸들러 다루기

HTML을 보면, 여기에서 여러분이 다루는 이벤트가 onClick이라는 것을 알 수 있다. JavaScript에서, 이 이벤트는 버튼의 onclick 속성을 사용하여 이벤트를 참조할 수 있다. (HTML에서, 이 속성은 onClick으로 참조된다. 대문자 C라는 것을 주목하라. JavaScript에서는 소문자 c를 사용한 onclick 이다.) 따라서, 버튼에 대해 실행되는 이벤트를 변경할 수 있다: 새로운 함수를 onclick 속성으로 할당하면 된다.

onclick 속성에는 함수의 스트링 이름이 아닌 함수 레퍼런스가 입력되어야 한다. 하지만 함수 자체에 대한 레퍼런스이다. JavaScript에서는 함수를 괄호가 없는 이름으로 참조할 수 있다. 따라서 버튼이 클릭될 때 실행되는 함수를 다음과 같이 변경할 수 있다:
출처 : http://www.ibm.com/developerworks/kr/series/web/index.html
아래 내용은 위 출처의 기사의 일부를 복사 후 편집/수정한 것입니다.
단순히 개인적으로 알고자하는 내용만을 남긴 것이니, 자세한 정보는 위의 출처를 참조하세요.

개념상의 노드

DOM 트리에서 여러분이 만나게 되는 거의 모든 것이 노드이다. 가장 기본적인 레벨에 있고, DOM 트리에 있는 노드이다. 모든 애트리뷰트는 하나의 노드이다. 모든 텍스트 조각도 하나의 노드이다. 심지어 코멘트, (카피라이트 상징을 나타내는 &copy; 같은) 특별 문자도 모두 노드이다.

노드란..

간단히 말해서, 노드는 DOM 트리에 있는 그저 단순한 하나의 존재이다. 엘리먼트와 텍스트가 완전히 다른 유형유형이라면 여러분은 완전히 다른 코드를 작성하여 한 유형에서 다른 유형으로 옮겨가야 한다. 공통 노드 유형을 사용한다면 상황은 달라진다. 이 경우 노드에서 노드로 간단히 움직일 수 있고 엘리먼트나 텍스트의 특정의 것을 수행하고 싶을 때에만 노드의 유형을 생각하면 된다. DOM 트리 주위로 이동할 때 같은 연산을 사용하여 엘리먼트의 부모 또는 자식으로 이동한다. 엘리먼트의 애트리뷰트 같은 특정 노드 유형에서 구체적인 작업이 필요하다면 엘리먼트나 텍스트 같은 하나의 노드 유형에 대해서만 작업하면 된다.

노드의 속성

    * nodeName은 노드의 이름을 나타낸다. (아래 참조)
    * nodeValue:는 노드의 "값"을 제공한다. (아래 참조)
    * parentNode는 노드의 부모를 리턴한다. 모든 엘리먼트, 애트리뷰트, 텍스트는 부모 노드를 갖고 있다는 것을 기억하라.
    * childNodes는 노드의 자식들의 리스트이다. HTML로 작업할 때 엘리먼트를 다룰 경우 이 리스트는 유용하다. 텍스트 노드와 애트리뷰트 노드는 어떤 자식도 갖지 않는다.
    * firstChild는 childNodes 리스트에 있는 첫 번째 노드로 가는 지름길이다.
    * lastChild도 또 다른 지름길이다. childNodes 리스트에 있는 마지막 노드로 가는 지름길이다.
    * previousSibling은 현재 노드 앞에 있는 노드를 리턴한다. 다시 말해서, 현재 것 보다 앞에 있는 노드를 리턴한다. 현재 노드의 부모의 childNodes 리스트에 있는 것 보다 선행하는 노드를 리턴한다. (헷갈린다면 마지막 문장을 다시 한번 더 읽어라.)
    * nextSibling은 previousSibling 속성과 비슷하다. 부모의 childNodes 리스트에 있는 다음 노드로 돌린다.
    * attributes는 엘리먼트 노드에서 유일하게 유용한 것이다. 엘리먼트의 애트리뷰트 리스트를 리턴한다.

몇몇 다른 속성들은 보다 근본적인 XML 문서로 적용되고 HTML 기반의 웹 페이지로 작업할 때 많이 사용되지 않는다.

nodeName과 nodeValue는 실제로 모든 노드 유형에 적용되는 것은 아니다. (한 노드 상의 다른 속성들의 경우도 마찬가지다.) 이 속성들은 null 값을 리턴할 수 있다. (JavaScript에서는 "undefined"로 나타난다.) 예를 들어, 텍스트 노드용 nodeName 속성은 무효이다. (또는 어떤 브라우저에서는 "undefined"이다. 텍스트 노드는 이름이 없기 때문이다. nodeValue는 노드의 텍스트를 리턴한다.)

비슷하게, 엘리먼트는 nodeName --엘리먼트의 이름--을 갖고 있지만 엘리먼트의 nodeValue 속성의 값은 언제나 무효이다. 애트리뷰트는 nodeName과 nodeValue, 이 두 가지 속성에 대한 값을 갖는다.

DOM에서 노드 속성 사용하기
 // These first two lines get the DOM tree for the current Web page,
//   and then the <html> element for that DOM tree
var myDocument = document;
var htmlElement = myDocument.documentElement;

// What's the name of the <html> element? "html"
alert("The root element of the page is " + htmlElement.nodeName);

// Look for the <head> element
var headElement = htmlElement.getElementsByTagName("head")[0];
if (headElement != null) {
  alert("We found the head element, named " + headElement.nodeName);

  // Print out the title of the page
  var titleElement = headElement.getElementsByTagName("title")[0];

  if (titleElement != null) {
    // The text will be the first child node of the <title> element
    var titleText = titleElement.firstChild;

    // We can get the text of the text node with nodeValue
    alert("The page title is '" + titleText.nodeValue + "'");
  }

  // After <head> is <body>
  var bodyElement = headElement.nextSibling;

  while (bodyElement.nodeName.toLowerCase() != "body") {
    bodyElement = bodyElement.nextSibling;
  }

  // We found the <body> element...
  // We'll do more when we know some methods on the nodes.
}

노드의 방식

모든 노드에 사용할 수 있는 메소드

    * insertBefore(newChild, referenceNode)는 newChild 노드를 referenceNode 앞에 삽입한다. newChild의 미래의 부모에 대해 이것을 호출할 것이다.
    * replaceChild(newChild, oldChild)는 oldChild 노드를 newChild 노드로 교체한다.
    * removeChild(oldChild)는 함수가 실행되고 있는 노드에서 oldChild 노드를 제거한다.
    * appendChild(newChild)는 newChild 노드를 이 함수가 실행되고 있는 노드에 추가한다. newChild는 목표 노드의 자식들의 끝에 추가된다.
    * hasChildNodes()는 호출된 노드가 자식을 갖고 있을 경우 true를 , 그렇지 않을 경우 false를 리턴한다.
    * hasAttributes()는 호출된 노드가 애트리뷰트를 갖고 있을 경우 true를, 애트리뷰트가 없을 경우 false를 리턴한다.

대부분의 경우, 이 모든 메소드들이 노드의 자식들을 다루고 있다. 이것이 바로 그들의 주요 목적이다. 텍스트 노드나 엘리먼트의 이름 값을 파악하기 위해 메소드를 많이 호출할 필요가 없다. 단순히 노드의 속성을 사용하면 된다.

DOM에서 노드 메소드 사용하기
 // These first two lines get the DOM tree for the current Web page,
//   and then the <html> element for that DOM tree
var myDocument = document;
var htmlElement = myDocument.documentElement;

// What's the name of the <html> element? "html"
alert("The root element of the page is " + htmlElement.nodeName);

// Look for the <head> element
var headElement = htmlElement.getElementsByTagName("head")[0];

if (headElement != null) {
  alert("We found the head element, named " + headElement.nodeName);

  // Print out the title of the page
  var titleElement = headElement.getElementsByTagName("title")[0];

  if (titleElement != null) {
    // The text will be the first child node of the <title> element
    var titleText = titleElement.firstChild;

    // We can get the text of the text node with nodeValue
    alert("The page title is '" + titleText.nodeValue + "'");
  }

  // After <head> is <body>
  var bodyElement = headElement.nextSibling;

  while (bodyElement.nodeName.toLowerCase() != "body") {
    bodyElement = bodyElement.nextSibling;
  }

  // We found the <body> element...
  // Remove all the top-level <img> elements in the body
  if (bodyElement.hasChildNodes()) {
    for (i=0; i<bodyElement.childNodes.length; i++) {
      var currentNode = bodyElement.childNodes[i];
      if (currentNode.nodeName.toLowerCase() == "img") {
        bodyElement.removeChild(currentNode);
      }
    }
  }
}

DOM을 사용하는 HTML 파일과 JavaScript 코드
 <html>
 <head>
  <title>JavaScript and the DOM</title>
  <script language="JavaScript">
   function test() {
    // These first two lines get the DOM tree for the current Web page,
    //   and then the <html> element for that DOM tree
    var myDocument = document;
    var htmlElement = myDocument.documentElement;

    // What's the name of the <html> element? "html"
    alert("The root element of the page is " + htmlElement.nodeName);

    // Look for the <head> element
    var headElement = htmlElement.getElementsByTagName("head")[0];
    if (headElement != null) {
      alert("We found the head element, named " + headElement.nodeName);

      // Print out the title of the page
      var titleElement = headElement.getElementsByTagName("title")[0];

      if (titleElement != null) {
        // The text will be the first child node of the <title> element
        var titleText = titleElement.firstChild;

        // We can get the text of the text node with nodeValue
        alert("The page title is '" + titleText.nodeValue + "'");
      }

      // After <head> is <body>
      var bodyElement = headElement.nextSibling;
      while (bodyElement.nodeName.toLowerCase() != "body") {
        bodyElement = bodyElement.nextSibling;
      }

      // We found the <body> element...
      // Remove all the top-level <img> elements in the body
      if (bodyElement.hasChildNodes()) {
        for (i=0; i<bodyElement.childNodes.length; i++) {
          var currentNode = bodyElement.childNodes[i];

          if (currentNode.nodeName.toLowerCase() == "img") {
            bodyElement.removeChild(currentNode);
          }
        }
      }
    }
  }
  </script>
 </head>

 <body>
  <p>JavaScript and DOM are a perfect match.
     You can read more in <i>Head Rush Ajax</i>.</p>
  <img src="http://www.headfirstlabs.com/Images/hraj_cover-150.jpg" />
  <input type="button" value="Test me!" onClick="test();" />
 </body>
</html>

API 디자인 설명

DOM은 객체 지향 API가 아니다. 우선, 많은 경우 여러분은 노드 객체에 메소드를 호출하기 보다는 객체의 속성들을 직접적으로 사용할 것이다. 예를 들어, getNodeName() 메소드가 없다. 다만 nodeName 속성을 직접 사용한다. 따라서 노드 객체들은(그리고 다른 DOM 객체들은) 함수가 아닌 속성들을 통해 많은 데이터를 노출한다.

문제는 JavaScript가 메소드 오버로딩(method overloading)이라는 기술을 지원하지 않는다는 점이다. 다시 말해서, JavaScript에서는 주어진 이름에 대해 하나의 메소드나 함수를 가져야 한다는 의미이다. 따라서 스트링을 취하는 getNamedItem() 메소드를 갖고 있다면 getNamedItem()이라는 이름의 다른 메소드나 함수를 가질 수 없다. 두 번째 버전이 다른 유형의 인자를 취하더라도 말이다. (또는 완전히 다른 인자를 취해도 마찬가지다.) 그럴 경우 JavaScript는 에러를 보고하고 코드는 작동하지 않는다.

본질적으로 DOM은 메소드 오버로딩과 다른 OO 프로그래밍 기술들을 피한다. OO 프로그래밍 기술을 지원하지 않는 언어를 포함하여 API는 여러 언어들을 통해서 작동한다는 확신 때문이다. 결국 몇 가지 추가적인 메소드 이름을 배워야 한다는 것이다. 예를 들어 자바 같은 언어에서 DOM을 배울 수 있고 같은 메소드 이름과 코딩 구조가 자바스크립트 같은 DOM 구현을 가진 다른 언어들에도 작동할 것이라는 것을 알 수 있다.

프로그래머를 조심시켜라!

nodeName 속성은 모든 유형이 이름을 가질 수 있도록 하고 있다. 하지만 많은 경우 그 이름은 정의되지 않았거나 프로그래머에게는 어떤 가치도 없는 낯선 이름이다. (예를 들어, 자바에서 텍스트 노드의 nodeName은 많은 경우 "#text"로 리포팅 된다. 근본적으로 에러 핸들링은 여러분에게 남겨지게 된다. 단순히 myNode.nodeName에 액세스 하여 그 값을 사용하는 것은 안전한 방법이 아니다. 많은 경우 그 값은 무효가 될 것이다. 따라서 프로그래밍에 이것이 적용될 때 프로그래머들이 주의해야 한다.

일반 노드 유형들

대부분의 웹 애플리케이션에서 네 가지 유형의 노드로 작업한다.

    * 문서 노드는 전체 HTML 문서를 나타낸다.
    * 앨리먼트 노드는 a 또는 img 같은 HTML 엘리먼트를 나타낸다.
    * 애트리뷰트 노드는 href (a 엘리먼트에 대해) 또는 src (img 엘리먼트에 대해) 같은 HTML 엘리먼트에 대한 애트리뷰트를 나타낸다.
    * 텍스트 노드는 "Click on the link below for a complete set list" 같은 HTML 문서에 있는 텍스트를 나타낸다. 이는 p, a, h2 같은 엘리먼트 내부에 나타나는 텍스트이다.

문서 노드

문서 노드는 실제로 HTML(또는 XML) 페이지에 있는 엘리먼트가 아니라 페이지 그 자체이다. 따라서 HTML 웹 페이지에서 문서 노드는 전체 DOM 트리이다. 자바스크립트에서 document 키워드를 사용하여 문서 노드에 액세스 할 수 있다.

자바스크립트의 document 키워드는 현재 웹 페이지에 대한 DOM 트리를 리턴한다. 여기에서부터 여러분은 트리에 있는 모든 노드들과 작업할 수 있다.

또한 document 객체를 사용하여 다음과 같은 메소드를 사용하는 새로운 노드를 만들 수 있다.

    * createElement(elementName)는 제공된 이름을 가진 엘리먼트를 만든다.
    * createTextNode(text)는 제공된 텍스트를 가진 새로운 텍스트 노드를 만든다.
    * createAttribute(attributeName)는 제공된 이름을 가진 새로운 애트리뷰트를 만든다.

여기에서 주목해야 할 것은 이러한 메소드들이 노드를 만들지만 이들을 첨부하거나 이들을 특정 문서에 삽입하지 않는다는 점이다. 따라서 이미 봤던 insertBefore() 또는 appendChild() 같은 메소드들 중 하나를 사용해야 한다. 따라서 다음과 같은 코드를 사용하여 새로운 엘리먼트를 만들어 문서에 붙여야 한다.
 var pElement = myDocument.createElement("p");
var text = myDocument.createTextNode("Here's some text in a p element.");

pElement.appendChild(text);
bodyElement.appendChild(pElement);

document 엘리먼트를 사용하여 웹 페이지의 DOM 트리에 액세스 하면 엘리먼트, 애트리뷰트, 텍스트와 직접 작업할 준비가 된 것이다.

엘리먼트 노드

   1. 애트리뷰트와 작동하는 것과 관련된 메소드: :
          * getAttribute(name)는 name이라는 애트리뷰트의 값을 리턴한다.
          * removeAttribute(name)는 name이라는 애트리뷰트를 제거한다.
          * setAttribute(name, value)는 name이라는 애트리뷰트를 만들고 이것의 값을 value로 설정한다.
          * getAttributeNode(name)는 name라고 하는 애트리뷰트 노드를 리턴한다. (애트리뷰트 노드는 아래에서 설명한다.)
          * removeAttributeNode(node)는 제공된 노드와 매치되는 애트리뷰트 노드를 제거한다.
   2. 중첩된 엘리먼트를 찾는 메소드: :
          * getElementsByTagName(elementName)는 제공된 이름을 가진 엘리먼트 노드의 리스트를 리턴한다.

새로운 img 엘리먼트를 만들고 애트리뷰트를 설정한 다음 이것을 HTML 페이지의 바디에 추가한다.
var imgElement = document.createElement("img");
imgElement.setAttribute("src", "http://www.headfirstlabs.com/Images/hraj_cover-150.jpg");
imgElement.setAttribute("width", "130");
imgElement.setAttribute("height", "150");
bodyElement.appendChild(imgElement);

중첩 엘리먼트 찾기
HTML 페이지에서 모든 img엘리먼트를 찾아 제거
// Remove all the top-level <img> elements in the body
if (bodyElement.hasChildNodes()) {
  for (i=0; i<bodyElement.childNodes.length; i++) {
    var currentNode = bodyElement.childNodes[i];

    if (currentNode.nodeName.toLowerCase() == "img") {
      bodyElement.removeChild(currentNode);
    }
 }

getElementsByTagName()을 사용하여 비슷한 효과를 얻을 수 있다.
// Remove all the top-level <img> elements in the body
var imgElements = bodyElement.getElementsByTagName("img");

for (i=0; i<imgElements.length; i++) {
  var imgElement = imgElements.item[i];
  bodyElement.removeChild(imgElement);
}

애트리뷰트 노드

DOM은 애트리뷰트를 노드로서 나타내고 여러분은 언제나 엘리먼트의 attributes 속성을 얻을 수 있다.
// Remove all the top-level <img> elements in the body
var imgElements = bodyElement.getElementsByTagName("img");

for (i=0; i<imgElements.length; i++) {
  var imgElement = imgElements.item[i];

  // Print out some information about this element
  var msg = "Found an img element!";
  var atts = imgElement.attributes;

  for (j=0; j<atts.length; j++) {
    var att = atts.item(j);
    msg = msg + "\n  " + att.nodeName + ": '" + att.nodeValue + "'";
  }

  alert(msg);

  bodyElement.removeChild(imgElement);
}

애트리뷰트의 이상한 측면

애트리뷰트는 DOM에 있어서는 조금 특별하다. 애트리뷰트는 다른 엘리먼트나 텍스트의 경우와는 달리 엘리먼트의 자식이 아니다. 다시 말해서 엘리먼트의 밑에 나타나지 않는다. 동시에 이것은 엘리먼트와 관계를 갖고 있다. 엘리먼트는 자신의 애트리뷰트를 소유한다. DOM은 노드를 사용하여 애트리뷰트를 나타내고 이들을 특별한 리스트를 통해 엘리먼트에 대해 사용할 수 있도록 한다. 따라서 엘리먼트는 DOM 트리의 일부지만 이들은 트리에는 나타나지 않는다. DOM 트리 구조의 나머지에 대한 애트리뷰트의 관계는 다소 어지럽다.

  attributes 속성은 실제로 엘리먼트 유형이 아닌 노드 유형에 있다. 이것은 코딩에 영향을 주지 않지만 알아둘 필요가 있다.

애트리뷰트 노드에서 작업하는 것이 가능하지만 엘리먼트 클래스에서 사용할 수 있는 메소드를 사용하여 애트리뷰트 작업을 하는 것이 더 쉽다. 메소드는 다음과 같다.

    * getAttribute(name)는 name이라는 애트리뷰트의 값을 리턴한다.
    * removeAttribute(name)는 name이라는 애트리뷰트를 제거한다.
    * setAttribute(name, value)는 name이라는 애트리뷰트를 만들고 이것의 값을 value로 설정한다.

이 세 개의 메소드들로 인해 여러분은 애트리뷰트 노드와 직접 작업할 필요가 없다. 대신 애트리뷰트와 이것의 값과 함께 간단한 스트링 속성을 설정 및 제거할 수 있다.

텍스트 노드

마지막 노드 유형이자 HTML DOM 트리로 작업하는 유형은 텍스트 노드이다. 텍스트 노드와 작업하기 위해 공통적으로 사용하게 될 거의 모든 속성들은 실제로 노드 객체에서도 사용할 수 있다. 사실 nodeValue 속성을 사용하여 텍스트 노드에서 텍스트를 얻을 수 있다.
var pElements = bodyElement.getElementsByTagName("p");

for (i=0; i<pElements.length; i++) {
  var pElement = pElements.item(i);
  var text = pElement.firstChild.nodeValue;
  alert(text);
}

몇 가지 다른 메소드들은 텍스트 노드만의 것이다. 이들은 노드에 있는 데이터를 추가하거나 쪼갠다.

    * appendData(text)는 여러분이 제공한 텍스트를 텍스트 노드의 기존 텍스트의 끝에 추가한다.
    * insertData(position, text)는 텍스트 노드의 중간에 데이터를 삽입할 수 있다. 이것은 지정된 위치에 여러분이 제공한 텍스트를 삽입한다.
    * replaceData(position, length, text)는 지정된 위치부터 시작하여 지정된 길이의 문자를 제거하고 여러분이 제공한 텍스트를 제거된 텍스트를 대신하여 메소드에 둔다.

노드의 유형

만일 DOM 트리를 통해 검색하고 일반 노드 유형들로 작업한다면 엘리먼트나 텍스트로 이동했는지의 여부를 모를 것이다. 아마도 p 엘리먼트의 모든 자식들을 갖게 되고, 텍스트, b 엘리먼트, 아니면 img 엘리먼트로 작업하는지 확신할 수 없다. 이 경우 더 많은 일을 하기 전에 어떤 유형의 노드를 가졌는지를 규명해야 한다.

다행히도 이것을 파악하기는 매우 쉽다. DOM 노드 유형은 여려 상수들을 정의한다.

   1. Node.ELEMENT_NODE는 엘리먼트 노드 유형에 대한 상수이다.
   2. Node.ATTRIBUTE_NODE는 애트리뷰트 노드 유형에 대한 상수이다.
   3. Node.TEXT_NODE는 텍스트 노드 유형에 대한 상수이다.
   4. Node.DOCUMENT_NODE는 문서 노드 유형에 대한 상수이다.

다른 노드 유형들도 많이 있지만 HTML을 처리할 때에는 이 네 가지 외에는 별로 다루지 않는다.

nodeType 속성

DOM 노드 유형에 대해 정의되었기 때문에 모든 노드에서 사용할 수 있는 nodeType 속성을 사용하여 노드를 위 상수와 비교할 수 있다.
var someNode = document.documentElement.firstChild;

if (someNode.nodeType == Node.ELEMENT_NODE) {
  alert("We've found an element node named " + someNode.nodeName);
} else if (someNode.nodeType == Node.TEXT_NODE) {
  alert("It's a text node; the text is " + someNode.nodeValue);
} else if (someNode.nodeType == Node.ATTRIBUTE_NODE) {
  alert("It's an attribute named " + someNode.nodeName + " with a value of '" + someNode.nodeValue + "'");
}

이것은 매우 단순한 예제이지만 포인트가 있다. 노드의 유형을 얻는 것은 단순하다. 일단 어떤 유형인지를 알면 노드로 무엇을 할 것인지를 규명해야 한다. 하지만 노드, 텍스트, 애트리뷰트, 엘리먼트 유형이 무엇을 제공하는지 확실히 안다면 DOM 프로그래밍을 직접 할 준비가 된 것이다.

nodeType 속성이 노드로 작업할 수 있는 티켓인 것처럼 들린다. 이것으로 여러분은 어떤 유형의 노드로 작업하고 있는지를 규명하고 그 노드를 다룰 코드를 작성할 수 있다. 문제는 위에 정의된 Node 상수들이 Internet Explorer 상에서는 올바르게 작동하지 않는다는 점이다.

Internet Explorer는 여러분이 자바스크립트에서 Node 상수를 사용할 때 마다 에러를 보고 할 것이다. 거의 모든 사람들이 Internet Explorer를 사용하기 때문에 Node.ELEMENT_NODE 또는 Node.TEXT_NODE 같은 구조를 피해야 한다. Internet Explorer 7.0이 이러한 문제를 정정했다 하지만 Internet Explorer 6.x의 대중성에 미치려면 오랜 시간이 남았다. 따라서 Node 사용을 피해라. 여러분의 DOM 코드(그리고 Ajax 애플리케이션)가 모든 주요 브라우저에서 작동해야 하기 때문이다.
출처 : http://www.ibm.com/developerworks/kr/series/web/index.html
아래 내용은 위 출처의 기사의 일부를 복사 후 편집/수정한 것입니다.
단순히 개인적으로 알고자하는 내용만을 남긴 것이니, 자세한 정보는 위의 출처를 참조하세요.

트리 뷰로 이동하기
 <html>
 <head>
  <title>Trees, trees, everywhere</title>
 </head>
 <body>
  <h1>Trees, trees, everywhere</h1>
  <p>Welcome to a <em>really</em> boring page.</p>
  <div>
    Come again soon.
    <img src="come-again.gif" />
  </div>
 </body>
</html>
브라우저는 이것을 트리 구조로 변환한다

 someDiv.style.height = "300px";
다시 말해서, 웹 브라우저는 이와 같이 객체 속성들을 사용하여 트리의 모양과 구조를 쉽게 변경한다. 이것을 복잡한 것과 비교해 보라. 속성과 구조가 변할 때 마다 브라우저는 정적 파일을 재작성 하고, 재 파싱 하고 이를 스크린에 다시 디스플레이 해야 한다. 이 모든 것이 객체로도 가능해진다.

애트리뷰트

사실 애트리뷰트는 브라우저가 사용하는 객체 모델에 저장되지만 이들은 특별한 경우이다. 각 엘리먼트는 여기에 사용되는 애트리뷰트 리스트를 갖고 있고 자식 객체의 리스트에서 분리된다. 따라서 div 엘리먼트는 "id" 애트리뷰트와 또 다른 이름 " class "를 포함하고 있는 리스트를 갖게 된다.

엘리먼트용 애트리뷰트가 유일한 이름을 갖고 있어야 한다는 것을 기억하라. 다시 말해서, 하나의 엘리먼트가 두 개의 "id" 또는 두 개의 "class"애트리뷰트를 가질 수 없다. 보존하고 액세스 할 리스트를 매우 쉽게 만든다. 다음 글에서 보겠지만 getAttribute("id") 같은 메소드를 호출하여 애트리뷰트 값을 이름 별로 얻을 수 있다. 애트리뷰트를 추가하고 기존 애트리뷰트의 값을 비슷한 메소드 호출을 설정(재설정)할 수 있다.

DOM
 var domTree = document;
물론 이 코드는 그 자체로는 쓸모가 없지만 모든 웹 브라우저가 document 객체를 JavaScript 코드에 사용할 수 있도록 하고 객체는 완벽한 마크업 트리를 나타낸다.

마크업의 각 부분이 객체에 의해 구현되지만 이는 하나의 객체(특정 유형의 객체)인 DOM 노드에 불과하다는 것을 이미 알 것이다. 보다 특별한 유형인 텍스트, 엘리먼트, 애트리뷰트는 이러한 기본적인 노드 유형에서 확장된다. 따라서 여러분은 텍스트 노드, 엘리먼트 노드, 애트리뷰트 노드를 갖고 있는 것이다.

JavaScript로 프로그래밍을 했다면 DOM 코드를 사용하는 방법도 알 것이다. 이 Ajax 시리즈를 충실히 이행했다면 여러분도 DOM 코드를 사용한 것이다. 예를 들어, var number = document.getElementById("phone").value; 라인은 DOM을 사용하여 특정 엘리먼트를 찾아 그 엘리먼트의 값(이 경우 폼 필드)을 가져온다. 따라서 여러분이 인식 못했더라도 여러분은 document를 JavaScript 코드에 타이핑 할 때마다 DOM을 사용한 것이었다.

여러분이 배웠던 용어를 정비하기 위해 DOM 트리는 객체의 트리지만 보다 구체적으로는 노드 객체들의 트리이다. Ajax 애플리케이션 또는 JavaScript에서 그러한 노드들과 작업하여 엘리먼트와 이것의 콘텐트를 지우고 특정 텍스트 조각을 강조하고 새로운 이미지 엘리먼트를 추가하는 등 특별한 효과를 만들 수 있다. 이 모든 것은 클라이언트 측(웹 브라우저에서 실행되는 코드)에서 발생하기 때문에 이러한 효과는 서버와 통신 없이 즉시 발생한다. 결국 보다 반응성 있는 애플리케이션이 될 것이다.


출처 : http://www.ibm.com/developerworks/kr/series/web/index.html
아래 내용은 위 출처의 기사의 일부를 복사 후 편집/수정한 것입니다.
단순히 개인적으로 알고자하는 내용만을 남긴 것이니, 자세한 정보는 위의 출처를 참조하세요.

* HTTP 준비 상태
* HTTP 상태 코드
* 요청 유형들

HTTP 준비 상태
* 0: (open()을 호출하기 전에는) 요청이 초기화 되지 않는다.
* 1: (send()를 호출하기 전에는) 요청은 설정은 되지만 보내지지 않는다.
* 2: 요청이 보내지고 처리 중에 있다. (이 시점에서 응답에서 콘텐트 헤더를 얻을 수 있다.)
* 3: 요청이 처리 중에 있다. 부분적인 데이터를 응답에서 사용할 수 있지만 서버는 이 응답으로는 종료되지 않는다.
* 4: 응답이 완료된다. 서버의 응답을 받고 이를 사용한다.

readyState 0 (readyState == 0)으로 표시되는 첫 번째 준비 상태는 초기화 되지 않은 요청을 나타낸다. 요청 객체에 대해 open()을 호출하면 속성은 1로 설정된다. 대부분 요청을 초기화 하면서 open()을 호출하기 때문에 readyState == 0을 보는 일은 드물다. 더욱이 초기화 되지 않은 준비 상태는 실제 애플리케이션에서는 쓸모 없다.

 function getSalesData() {
   // Create a request object
   createRequest();        
   alert("Ready state is: " + request.readyState);

   // Setup (initialize) the request
   var url = "/boards/servlet/UpdateBoardSales";
   request.open("GET", url, true);
   request.onreadystatechange = updatePage;
   request.send(null);
}
open()이 호출되기 전에 준비 상태를 체크
요청 객체가 새로운 요청을 만들기 전에 초기화 되지 않은 상태(readyState == 0)에 있다는 것을 확인

0이 4와 같을 때
다중 JavaScript 함수들이 같은 요청 객체를 사용하는 경우, 그 요청 객체가 사용되고 있지 않다는 것을 확인하기 위해 준비 상태 0을 확인하면 문제가 많아질 수 있다. readyState == 4는 완료된 요청을 나타내기 때문에, 4로 설정된 준비 상태인 채로 사용되지 않은 요청 객체를 종종 보게 된다. abort()이라고 하는 요청 객체를 리셋하는 함수가 있지만 이는 여기에 사용하는 것이 아니다. 다중 함수들을 사용해야 한다면 다중 함수에 객체를 공유하는 것 보다 각 함수용 요청 객체를 생성 및 사용하는 것이 낫다.

브라우저 차이
Firefox 1.5
    * 1
    * 2
    * 3
    * 4

Safari 2.0.1
    * 2
    * 3
    * 4
Safari는 첫 번째 준비 상태를 배제하고 그 이유에 대해서는 자세히 나와있지 않다. 바로 이것이 Safari 방식이다. 또한 중요한 포인트이기도 하다. 서버에서 데이터를 사용하기 전에 요청의 준비 상태가 4라는 것을 확인하는 것은 좋은 생각인 반면 일시적인 준비 상태에 의존하는 코드를 작성하는 것은 다른 브라우저 마다 다른 결과를 얻을 수 있는 확실한 방법이다.

Opera 8.5를 사용할 때 상황은 더 악화된다.
    * 3
    * 4

Internet Explorer
    * 1
    * 2
    * 3
    * 4

responseText
준비 상태 2에서 responseText 속성은 정의되지 않는다
준비 상태 3에서, 서버는 responseText 속성에 값을 배치한다

준비 상태 3의 응답은 스크립트 마다, 서버 마다, 브라우저 마다 다르다. 애플리케이션을 디버깅 하는데 매우 유용하다.
모든 문서와 스팩들에서는 준비 상태가 4가 되어야지만 데이터를 안전하게 사용할 수 있다고 나와있다. 나를 믿으라. 준비 상태가 3일 때에도 responseText 속성에서 데이터를 얻을 수 있다. 하지만 여러분의 애플리케이션에서 이것에 의존하는 것은 좋지 않은 생각이다. 준비 상태 3에서 완전한 데이터에 의존하는 코드를 작성하는 것은 데이터가 불완전하다는 증거이다.

준비 상태가 변할 때 마다 폼이나 페이지에 대한 필드를 업데이트 할 수 있다. 예를 들어, 프로그레스 인디케이터의 넓이를 준비 상태 1에 25 퍼센트, 준비 상태 2에 50 퍼센트, 준비 상태 3에 75 퍼센트, 준비 상태 4에 100 퍼센트를 설정한다. 물론 알다시피, 이 방식은 좋기는 하지만, 브라우저에 의존적이다. Opera에서는 첫 번째 두 개의 준비 상태를 결코 얻지 못하고 Safari는 처음 1 상태를 누락시킨다.

HTTP 상태 코드

* 401: Unauthorized
* 403: Forbidden
* 404: Not Found
* 200: Everything is OK

리다이렉션과 재 라우팅
에러에 대해 이야기 하기 전에 Ajax를 사용할 때 걱정하지 않아도 될 부분에 대해 말해두겠다. 바로 리다이렉션이다. HTTP 상태 코드에서, 이것은 300 대의 상태 코드이다.
* 301: Moved permanently
* 302: Found (요청이 또 다른 URL/URI로 리다이렉션 된다.)
* 305: Use Proxy (요청은 프록시를 사용하여 요청 받은 리소스에 액세스 해야 한다.)

Ajax 프로그래머가 리다이렉션에 대해 염려 할 필요가 없는 이유가 두 가지 있다.
* Ajax 애플리케이션들은 특정 서버측 스크립트, 서블릿, 애플리케이션을 위해 작성된다. 그 컴포넌트를 없애거나 다른 곳으로 이동하기 위함이다. 리소스는 변경되었다는 것을 (이미 이동했기 때문에)알고, 요청에서 URL을 변경하고 이러한 종류의 결과를 절대 만나지 않게 된다.
* 보다 관련성 있는 이유가 있다. Ajax 애플리케이션과 요청들은 샌드박스화 되어있다. Ajax 요청을 만드는 웹 페이지를 공급하는 도메인은 그러한 요청에 응답해야 하는 도메인이다. 따라서 ebay.com에서 공급 받은 웹 페이지는 Ajax 스타일의 요청을 amazon.com에서 실행되는 스크립트에 할 수 없다. ibm.com 상의 Ajax 애플리케이션은 netbeans.org에서 실행되는 서블릿으로 요청할 수 없다.

결국, 요청은 보안 에러를 만들지 않고서는 또 따른 서버로 리다이렉션 될 수 없다. 그러한 경우에, 상태 코드를 전혀 얻을 수 없다. 디버그 콘솔에 JavaScript 에러를 갖게 된다. 따라서 많은 상태 코드에 대해 생각하는 동안 리다이렉션 코드 정도는 무시할 수 있는 것이다.

HTTP 상태코드 처리
 function updatePage() {
  if (request.readyState == 4) {
     if (request.status == 200) {
        var response = request.responseText.split("|");
        document.getElementById("order").value = response[0];
        document.getElementById("address").innerHTML =
         response[1].replace(/\n/g, "<br />");
     } else if (request.status == 404) {
        alert ("Requested URL is not found.");
     } else if (request.status == 403) {
        alert("Access denied.");
     } else
        alert("status is " + request.status);
  }
}

추가 요청 유형
향상된 에러 핸들링과 정보 수집을 위해 HEAD 요청에 대해 배워야 한다.
 function getSalesData() {
    createRequest();
    var url = "/boards/servlet/UpdateBoardSales";
    request.open("HEAD", url, true);
    request.onreadystatechange = updatePage;
    request.send(null);
}

function updatePage() {
   if (request.readyState == 4) {
      alert(request.getAllResponseHeaders());
   }
}

이러한 헤더들을 개별적으로 사용하여 Ajax 애플리케이션에서 추가 정보나 기능을 제공할 수 있다.

유용한 HEAD 요청
HEAD 요청이 유용한 한 가지 부분은 콘텐트 길이나 콘텐트 유형을 검사할 때이다. 요청을 처리하기 위해 많은 양의 데이터를 보낼 것인지, 서버가 HTML, 텍스트, XML 대신 바이너리 데이터를 리턴해야 할지를 결정할 수 있다. (이 세 가지 모두 바이너리 데이터 보다 JavaScript에서 처리하는 것이 더 쉽다.)

이 경우, 적절한 헤더 이름을 사용하고 이를 XMLHttpRequest 객체의 getResponseHeader() 메소드로 보낸다. 따라서 응답의 길이를 알려면 request.getResponseHeader("Content-Length");를 호출한다. 콘텐트 유형을 알려면 request.getResponseHeader("Content-Type");를 사용한다.

많 은 애플리케이션에서 HEAD 요청을 하면 어떤 기능도 추가하지 않고 요청의 속도를 늦출 수 있다. (HEAD 요청을 실행하여 응답에 대한 데이터를 얻고 후속 GET 또는 POST 요청을 통해 응답을 실제로 받는다.) 하지만 스크립트나 서버측 컴포넌트에 대해 확실하지 않은 경우 HEAD 요청으로 기본적인 데이터를 받을 수 있다.


결론

Ajax 와 웹 프로그래머에게 이 글은 다소 어려울 것이다. HEAD 요청을 하는 것의 가치는 무엇인가? JavaScript에서 리다이렉션 상태 코드를 핸들해야 하는 때는 언제인가? 이 모두 좋은 질문이다. 간단한 애플리케이션의 경우, 이 모든 것은 가치가 별로 없다.

하지만 웹이 단순한 애플리케이션만 수용하는 것은 아니다. 사용자는 점점 고급화 되고 고객들도 강력한 에러 리포팅을 원한다. 관리자 역시 애플리케이션이 조금만 느려져도 해고를 당하게 된다.

간단한 애플리케이션을 넘어 XMLHttpRequest에 대한 이해를 높여야 할 때이다.

    * 다양한 준비 상태를 이해하고 이들이 브라우저 마다 어떻게 다른지를 이해하면 애플리케이션을 빠르게 디버깅 할 수 있다. 준비 상태에 기반하여 창조적인 기능을 만들고 요청자의 상태에 대해 사용자와 고객에게 보고할 수 있다.
    * 상태 코드를 핸들했다면 스크립트 에러, 예기치 못한 응답들, 엣지 케이스들을 다룰 수 있다. 결국, 애플리케이션은 언제나 잘 작동될 것이다.
    * 여기에 더하여 HEAD 요청을 만들고, URL의 존재를 검사하고 파일이 언제 수정되었는지를 파악하고 사용자가 유효 페이지를 얻었는지를 확인할 수 있다면 언제나 최신의 정보와 강력한 기능으로 사용자들을 만족시킬 수 있을 것이다.


사실 HEAD 요청은 뭐에 필요한지 잘 모르겠음.
리다이렉션 상태 코드는 핸들하지 않아도 상관없어 보임.
결론에서도 보듯이 핸들하면 좋다...는 정도일려나?
12장 동적 유효성 검사 프로그래밍도 패스.

13장 XPath 검색 프로그래밍


10장 SAX 기반 문서 처리 프로그래밍

빠르게 순차적으로 처리하기엔 좋으나, 한번 XML을 파싱한 다음 여러번 검색하기엔 안좋다.
순차적으로 검색하므로, 검색때마다 파싱해야함.


11장 XSLT 문서 변환 프로그래밍은 패스.
필요할 때 찾아볼 것
8장 XSL는 읽고 넘겼음. 필요할 때 찾아보면 될 듯.

9장 DOM 기반 문서 처리 프로그래밍

<parent>
  <element>TEXT</element>
</parent>

위의 경우 TEXT 자체도 노드로 취급한다는 점에 주의.
parent <- element <- TEXT 이런 식으로 상위 노드에 종속되어 있다.


<parent attr="ATTR">TEXT1
  <element>TEXT2</element>
</parent>

예를 들다보니 위와 같이 되었지만, 위와 같은 것은 없는듯.
TEXT1과 element의 레벨이 같아지므로, 관리불가!? 어느게 TEXT이고 어느게 element인지 알 수 없다. 전부 NODE이므로..
책이나 웹 찾아봐도 MIXED라는 것이, 문자 데이터 또는! 자식 엘리먼트이지, 문자 데이터와 자식 엘리먼트는 아니었음.


<parent attr="ATTR">
  <element>TEXT2</element>
</parent>

위의 경우도 마찬가지로  TEXT2, ATTR은 전부 하나의 노드로 취급한다. 하지만 속성은 그 값을 얻는 방식이 다르다.
parent <- element <- TEXT2
  <- ATTR

parent에 ATTR, element가 종속되어 있으나, ATTR 과 element는 동일 레벨이 아니다.
속성값(ATTR)을 얻을 때는 parent.getAttribute("attr");
TEXT1을 얻을 때는 eText = element.getFirstChild() 한 후, eText.getData();
1~5장까지는 훑어보면 알만한 내용.
6장 XML 스키마 언어는 조금 보다가 복잡해지고, 이번 프로젝트랑은 크게 상관없을 듯 하여 pass.
나중에 필요하면 찾아보는 걸로 해도 괜찮을 듯.

7장 XPath와 그 뒤의 DOM 기반 문서 처리, SAX 기반 문서 처리 쪽은 중요!

XPath관련

/child::booklist/child::book
루트 노드의 자식 노드인 booklist의 자식 노드인 book을 찾아라

/child::booklist/child::book/attribute::kind
루트 노드의 자식 노드인 booklist의 자식 노드인 book의 속성 kind값을 찾아라

/child::booklist/child::book[attribute::kind="computer"]
루트 노드의 자식 노드인 booklist의 자식 노드인 book 중에서, 속성 kind 값이 "computer"인 book 노드를 찾아라

/child::booklist/child::book[contains(child::title, "전자")]
루트 노드의 자식 노드인 booklist의 자식 노드인 book 중에서, book의 자식인 title 노드의 문자 데이터 값 중에 "전자" 가 포함된 book 노드를 찾아라.
<book>
    <title>전자사전</title>
</book>
뭐 이런거...

//book
XML문서 전체에서 book 노드를 찾아라.    /booklist/book 은 booklist의 자식 노드인 book을 찾는 것이므로 다르다.

/booklist/book[@kind="computer"]
루트 노드의 자식 노드인 booklist의 자식 노드인 book 중에서, book의 속성 kind의 값이 computer인 book 노드를 찾아라

//book[@kind="computer"]
XML문서 전체에서 속성 kind의 값이 computer인 book 노드를 찾아라

/booklist/book/title[../@kind="computer"]
루트 노드의 자식 노드인 booklist의 자식 노드인 book의 자식 노드인 title 중에서, title의 부모인 book 노드의 속성 kind 값이 computer인 title 노드를 찾아라


XPath 함수 사용

/booklist/book[position()=last()] 또는 /booklist/book[last()]
루트 노드의 자식 노드인 booklist의 자식 노드인 book 중에서, 마지막 위치에 있는 book 노드를 찾아라

/booklist/book[position()=2] 또는 /booklist/book[2]
루트 노드의 자식 노드인 booklist의 자식 노드인 book 중에서, 두번째 위치에 있는 book 노드를 찾아라

count(/booklist/book)
booklist 밑의 book 노드의 총 개수를 얻는다

/booklist/book[starts-with(title, '사')]
booklist 밑의 book 노드 밑의 title 노드의 컨텐츠 내용이 '사'로 시작하는 book 노드를 찾아라

/booklist/book[contains(title, 'XML')]
book 노드 중에서 자식 노드인 title 노드의 컨텐츠 내용에 'XML'이 포함되어 있는 book 노드를 찾아라

/booklist/book[not(contains(title, 'XML'))]
book 노드 중에서 자식 노드인 title 노드의 컨텐츠 내용에 'XML'이 포함되어 있지 않은 book 노드를 찾아라