* 옵션 * 새창 뛰울때 용도에 맞게 옵션 설정을 해줍니다. "YES" 또는 "NO" 로 지정 해주면 됩니다. menubar - 파일, 편집, 보기....부분 toolbar - 뒤로, 앞으로, 새로고침 아이콘등이 있는 부분 directories - 연결 디렉토리가 표시되는 부분 location - 주소 입력창 status - 아래 브라우저 상태 바 scrollbars - 스크롤 resizable - 리사이즈 옵션
부모창인 index.htm에 삽입 <html> <head> <title>..</title> <meta http-equiv="Content-Type" content="text/html; charset=euc-kr"> <script language="javascript"> <!-- function getCookie(name) { var Found = false var start, end var i = 0 // cookie 문자열 전체를 검색 while(i <= document.cookie.length) { start = i end = start + name.length // name과 동일한 문자가 있다면 if(document.cookie.substring(start, end) == name) { Found = true break } i++ } // name 문자열을 cookie에서 찾았다면 if(Found == true) { start = end + 1 end = document.cookie.indexOf(";", start) // 마지막 부분이라 는 것을 의미(마지막에는 ";"가 없다) if(end < start) end = document.cookie.length // name에 해당하는 value값을 추출하여 리턴한다. return document.cookie.substring(start, end) } // 찾지 못했다면 return "" } function openMsgBox() { var eventCookie=getCookie("memo"); if (eventCookie != "no") window.open('팝업창파일','_blank','width=300,height=300,top=50,left=150'); //팝업창의 주소, 같은 도메인에 있어야 한다. } openMsgBox(); //--> </script> </head> <body> </body> </html>
팝업창인 pop.htm에 삽입 <html> <head> <title></title> <head> <script language="JavaScript"> <!-- function setCookie( name, value, expiredays ) { var todayDate = new Date(); todayDate.setDate( todayDate.getDate() + expiredays ); document.cookie = name + "=" + escape( value ) + "; path=/; expires=" + todayDate.toGMTString() + ";" } function closeWin() { if ( document.myform.event.checked ) setCookie("memo", "no" , 1); // 1일 간 쿠키적용
부모창인 index.htm에 삽입 <html> <head> <title>..</title> <meta http-equiv="Content-Type" content="text/html; charset=euc-kr"> <script language="javascript"> <!-- function getCookie(name) { var Found = false var start, end var i = 0 // cookie 문자열 전체를 검색 while(i <= document.cookie.length) { start = i end = start + name.length // name과 동일한 문자가 있다면 if(document.cookie.substring(start, end) == name) { Found = true break } i++ } // name 문자열을 cookie에서 찾았다면 if(Found == true) { start = end + 1 end = document.cookie.indexOf(";", start) // 마지막 부분이라 는 것을 의미(마지막에는 ";"가 없다) if(end < start) end = document.cookie.length // name에 해당하는 value값을 추출하여 리턴한다. return document.cookie.substring(start, end) } // 찾지 못했다면 return "" } function openMsgBox() { var eventCookie=getCookie("memo"); if (eventCookie != "no") window.open('팝업창파일','_blank','width=300,height=300,top=50,left=150'); //팝업창의 주소, 같은 도메인에 있어야 한다. } openMsgBox(); //--> </script> </head> <body> </body> </html>
팝업창인 pop.htm에 삽입 <html> <head> <title></title> <head> <script language="JavaScript"> <!-- function setCookie( name, value, expiredays ) { //같은 창에서만 안띄움. //expiredays 값은 상관없음. document.cookie = name + "=" + escape( value ) + "; path=/;"; function closeWin() { if ( document.myform.event.checked ) setCookie("memo", "no" , 1); // 1일 간 쿠키적용
부모창인 index.htm에 삽입 _새로 브라우져를 열면 팝업창이 뜸 <html> <head> <title>..</title> <meta http-equiv="Content-Type" content="text/html; charset=euc-kr"> <script language="javascript"> <!-- function getCookie(name) { var Found = false var start, end var i = 0 // cookie 문자열 전체를 검색 while(i <= document.cookie.length) { start = i end = start + name.length // name과 동일한 문자가 있다면 if(document.cookie.substring(start, end) == name) { Found = true break } i++ } // name 문자열을 cookie에서 찾았다면 if(Found == true) { start = end + 1 end = document.cookie.indexOf(";", start) // 마지막 부분이라 는 것을 의미(마지막에는 ";"가 없다) if(end < start) end = document.cookie.length // name에 해당하는 value값을 추출하여 리턴한다. return document.cookie.substring(start, end) } // 찾지 못했다면 return "" } function openMsgBox() { var eventCookie=getCookie("memo"); if (eventCookie != "no") window.open('팝업창파일','_blank','width=300,height=300,top=50,left=150'); //팝업창의 주소, 같은 도메인에 있어야 한다. } openMsgBox(); //--> </script> </head> <body> </body> </html>
팝업창인 pop.htm에 삽입 <html> <head> <title></title> <head> <script language="JavaScript"> <!-- function setCookie( name, value, expiredays ) { //같은 창에서만 안띄움. //expiredays 값은 상관없음. document.cookie = name + "=" + escape( value ) + "; path=/;"; } function closeWin() { if ( document.myform.event.checked ) setCookie("memo", "no" , 1); // 1일 간 쿠키적용 } //--> </script> </head> <body onunload="closeWin()"> <form name="myform"> <input type="checkbox" name="event">다음부터 이 창을 열지않음 <input type=button value="닫기" onclick="self.close()"> </form> </body> </html>
<html> <head> <title>..</title> <meta http-equiv="Content-Type" content="text/html; charset=euc-kr"> <script language="JavaScript"> <!-- function redirectPage() { var url800x600 = "main1.html"; //800*600 에서 열릴문서 var url1024x768 = "main2.html"; //1024*768 에서 열릴문서 var url1152x864 = "main3.html"; //1152*864 에서 열릴문서
32.이미지사이즈에 맞게 새창이 열리며 휠마우스 효과를 내줌 그리고 메인(imgmove-main.html)에서 새창 띄워주는 부분
<SCRIPT LANGUAGE="JavaScript"> <!-- Begin function cnjOpen() { window.open('img-move.html','cnjOpenWin','width=350,height=250,toolbar=0,scrollbars=0,location=0,status=0,menubar=0,resizable=0'); } // End --> </script> <a href="javascript:cnjOpen()"><img src="test.jpg" width="200" height="150" border="0"></a> </center>
이 부분은 이미지를 보여줄 새창(img-move.html)입니다. <style> body {cursor:move;} </style> <body leftmargin=0 topmargin=0 marginwidth=0 marginheight=0 onLoad="fitWindowSize();">
<SCRIPT LANGUAGE="JavaScript"> // 이미지는 별도로 제공하지 않습니다. <!-- CGI 와 JavaScript가 만났을 때=CnJ ☞ http://www.cginjs.com --> <!-- CGI 와 JavaScript가 만났을 때=CnJ ☞ webmaster@cginjs.com --> var ie = 1; var windowX, windowY; var bLargeImage = 0; var x,y;
WritableWorkbook saveExcelWork = Workbook.createWorkbook(new File("./"+fromdate+ "_" + todate + ".xls")); WritableSheet saveSheet = saveExcelWork .createSheet("GoodKeyword", 0); WritableCellFormat numberFormat = new WritableCellFormat(); WritableCellFormat nameFormat = new WritableCellFormat(); WritableCellFormat dataFormat= new WritableCellFormat();
numberFormat.setAlignment(Alignment.CENTRE); // 셀 가운데 정렬 numberFormat.setVerticalAlignment(VerticalAlignment.CENTRE); // 셀 수직 numberFormat.setBorder(Border.ALL, BorderLineStyle.THICK); // 보더와 보더라인스타일 설정 numberFormat.setBackground(Colour.GRAY_25); // 바탕색깔 회색으로 지정
// 데이터 셀 포멧 구성 dataFormat.setAlignment(Alignment.CENTRE); dataFormat.setVerticalAlignment(VerticalAlignment.CENTRE);
saveSheet .setColumnView(0, 8); // 쉬트의 번호 컬럼(0번째)의 넓이 설정.setCloumnView(몇번째 컬럼, 넓이) saveSheet .setColumnView(1, 15); // 쉬트의 이름 컬럼(1번째)의 넓이 설정 saveSheet .setColumnView(2, 20); // 쉬트의 비고 컬럼(2번째)의 넓이 설정
// 라벨을 이용하여 해당 셀에 정보 넣기 시작 Label numberLabel = new Label(0, 0, "키워드", numberFormat); // 라벨(열,행,"문장",포멧) saveSheet .addCell(numberLabel); // 쉬트의 addCell 메소드를 사용하여 삽입
Label nameLabel = new Label(1, 0, "개수", nameFormat); saveSheet.addCell(nameLabel); // 쉬트의 addCell 메소드를 사용하여 삽입
Blank blank = new Blank(2, 0, numberFormat); // 빈 셀(열,행,포멧)
실행해보니 잘되었다. 이제 끝났나 했지만..문제는 약간 있었음..IE 에서만 돌아간다는...그렇지만 일단 되니까 라고 생각해지만.. IE 7.0 에서도 안되었다. .execCommand('SaveAs' ~~ ) 이부분이 7.0에서는 다운로드 창을 못 띄우는 것...처음에 테스트 해본 노트북은 비스타였으니....이렇게 브라우져에 영향 받으면 안되는데..하면서 다른 방법 을 모색 함...
땅파기...........No 3.
제일 간단하고 쉬운 방법... response 에 excel 로 받겠다고 정보를 끼워넣으면 html 에서 열었을 때 자동으로 내려받기로 뜨게 된다. 왜 처음부터 이렇게 생각 안했을까! 이런 방식이 있다고 알고 있긴 했지만 처음 생각은 html 에서 뿌려주지 않고 서블릿 단에서 바로 받기를 원했기 때문이었다.... 정말 길게 돌아와버렸다...
* IE 5.5 에서는..아래와 같이 써야 한다고 한다. response.setHeader("Content-Disposition", "inline; filename=myfile.xls"); response.setHeader("Content-Description", "JSP Generated Data");
생각 좀 하고 짜보자..서버로 받으면 어쩌겠다는 건지..그리고 먼저 사용가능한 환경부터 생각해보고 구현해보자.. 삽질 좀 그만 해보자..
SOAP 기반 XML 웹서비스에 아무리 주의를 기울이고 있다 하더라도 SOAP과 호환되지 않는 수많은 유용한 서비스와 컨텐츠가 있다는 사실을 잊기 쉽다. 이번 테크팁에서는 웹 티어로부터 기존의 웹 리소스들을 사용하기 위해 서블렛을 어떻게 사용하는 지 보여준다. 이 경우에 기존 웹 서비스란 비표준 기반 XML 서비스를 말한다.
기존 리소스 호환
적어도 지금까지는 웹의 대부분의 컨텐츠를 표준 기반 웹 서비스 형식에서 사용할 수 없었다. HTML 페이지, 텍스트 파일, PDF나 워드 프로세서 같은 문서 파일, ftp 사이트 안의 파일들과 이미지들 형식에서 많은 정적 컨텐츠가 존재한다. 어떤 서비스들은 HTTP POST나 GET 요구에 따라 활발하게 XML을 생산하기도 하며, RSS feeds 같은 다른 서비스들은 정적인 URL을 가지고 있으나, 그들의 데이터가 동적이어서 보통 직접 사용자에 의해 사용되기 보다는 프로그램에 의해 사용되기 때문에 서비스의 역할을 한다.
엔터프라이즈Java 테크놀로지는 조직 내 인트라넷과 일반 인터넷에서 모두 기존 리소스들과 훌륭히 호환된다. 엔터프라이즈Java 테크놀로지는 새로운 시스템에 기존 정보 자산을 통합하기 위해 어느 티어에서나 사용될 수 있다. SOAP 기반 웹 서비스들이 기존 리소스들을 통합하는 새로운 시스템을 생성하는 것을 기다릴 필요가 없는 것이다.
다음은 통합적인 애플리케이션을 제공하기 위해 엔터프라이즈 Java 서버가 다양한 기존 웹 리소스들을 통합하는 구성도이다.
업무에서의 검색엔진
The National Library of Medicine은 미국방부의 건강 관련 기관 중 하나이다. PubMed*는 NLM의 서비스 중 하나로, 생체의학분야의 출판물 요약본 DB를 검색 가능하도록 제공한다. PubMed의 검색엔진은 Entrez로 불리며, 주소창에pubmed라고 입력하거나 http://www.ncbi.nlm.nih.gov/entrez/query.fcgi 로 들어가서 이 Entrez를 사용해볼 수 있다.
다음의 그림은 PubMed 사이트에서"neanderthal dna" 를 검색한 결과 중 일부이다.
PubMed는 또한 e-uilities라고 불리는 서비스를 제공한다. 이 서비스는 검색엔진에 프로그램적 인터베이스를 제공하는데, 클라이언트로부터 HTTP GET 요구를 받아 검색 결과를 나타내는 XML을 리턴할 수 있다.
이 테크팁을 수행하는 샘플 코드는 e-utilities 중 두가지에 접근하는 서블렛이다.
esearch. 검색을 실행하고 ID 리스트를 리턴한다.
efetch. 다양한 형식으로 요청된 문서를 불러온다.
esearch 이나 efetch로부터 리턴된 XML을 브라우저에 표시할 수 있게끔 XSLT스타일시트에 의해 변환되도록 지정하는 옵션도 있다. 서블렛은 클라이언트가 어떤 매개변수를 제공하는가에 따라 적절한 스타일시트를 사용할 것이다.
서블렛 개요
Jul2004Servlet라 불리는 샘플코드 서블렛은 새로운 기능을 제공하기 위해 기존 웹 서비스인 esearch와 efetch를 사용한다. 서블렛은 입력 매개변수를 GET URLs로 변환하여, 분석하고 표시하기 위해 데이터를 검색하는데 이를 사용한다. 서블렛은 먼저 검색을 실행하기 위해 esearch를 호출하고, 그 후 결과를 검색하기 위해 efetch를 호출한다.
다음은 서블렛이 결과를 도출하기 위해 진행되는 과정을 보여주는 순서도이다. 서블렛이 결과를 도출하기 위해 다양한 HTTP GETs의 결과를 사용하였다는 것에 주의하기 바란다.
서블렛은 유저 형식로부터 POST 매개변수를 수신하고 esearch가 요청하는 매개 변수로 HTTP GET URL를 구축한다.
서블렛은 URL로 HTTP GET을 실행한다. esearch e-utility는 서버용 결과 집합을 식별하는 데이터를 가진 XML을 리턴한다.
서블렛은 esearch로부터 리턴된 XML을 파싱하고, WebEnv와 QueryKey를 검색하기 위해 DOM API를 호출한다. 그 후 이 값들을 이용해 URL을 구축하여 데이터를 얻는다.
서블렛은 이번엔 efetch에 또다른 HTTP GET를 실행시킨다. 이는 결과 집합을 식별하고 원래의 요청에서 지정된 매개변수들을 형식화한다.
서블렛은 efetch로부터 요청된 문서 데이터를 수신하여 데이터를 XSL로 임의 변환하고 브라우저에 결과를 표시한다.
데이터베이스 검색
Entrez 서버에서 문서정보를 검색하는 첫번째 단계는 애플리케이션의 index.html에 있는 입력폼의 몇가지 매개 변수에 대해 esearch를 실행시키는 것이다. esearch는 Entrez 서버를 조회하여 조회 결과에 부합되는 데이터를 리턴한다. HTTP GET 쿼리 문자열이 "usehistory=y"라는 매개변수를 포함하고 있다면, Entrez 서버는 WebEnv 문자열과 QueryKey 라는 두가지 데이터 아이템을 추가하여 리턴한다. WebEnv 문자열은 Entrez 서버 안의 세션에서 유저 상태(과거에 있었던 쿼리와 그 결과 집합을 포함)에 대한 독자적인 식별자이며, QueryKey는 세션 안의 특정 쿼리를 식별하는 작은 정수이다. 종합하자면, WebEnv와 QueryKey를 합하면 서버에서의 쿼리 결과를 나타내게 된다. 서블렛은 애플리케이션의 index.html 페이지에 있는 입력폼로부터 몇 가지 매개 변수를 수신한다. 다음은 입력폼 샘플이다.
서블렛은 애플리케이션의 index.html 페이지에 있는 입력폼로부터 몇 가지 매개 변수를 수신한다.
다음은 입력폼 샘플이다.
서블렛 코드는URL을 구축하기 위해 다음과 같이POST매개 변수를 사용한다.
AbstractMap paramMap = new TreeMap();
res.setContentType("text/html");
OutputStream os = res.getOutputStream();
// Get parameters
String query = req.getParameter("query");
// Execute esearch
// db=PubMed: search PubMed database
// usehistory=y: return key to server-side result set
// term=$query: search for "$term" in PubMed
paramMap.put("db", "PubMed");
paramMap.put("usehistory", "y");
paramMap.put("term", query);
// Create the URL and get its content
String surl = buildUrl(BASEURL_ESEARCH, paramMap);
InputStream is = getContent(surl);
여기서 사용된 buildUrl메서드는 기본 URL을 받아서 맵 상의 각각의 키와 컨텐츠 쌍에 대해 key=content라는 키를 생성함으로써 HTTP GET URL을 만든다. 컨텐츠는 URL로 인코딩 되어있으며 매개 변수는 스트링"&"와 결합하여 HTTP GET URL을 생성한다. 예를 들어 형식 쿼리가 "neanderthal DNA"이면 쿼리 문자열은 다음과 같다.
db=PubMed&term=neanderthal+dna&usehistory=y
getContent 메서드는 요청된 URL에게 간단히 HttpUrlConnection을 개방하고, 결과 컨텐츠에 대해 다음과 같이 InputStream을 리턴한다.
protected InputStream getContent(String surl)
throws ServletException {
Object content = null;
try {
// Connect to URL
URL url = new URL(surl);
HttpURLConnection conn =
(HttpURLConnection)url.openConnection();
conn.connect();
// Get content as stream
content = conn.getContent();
} catch (Exception e) {
throw new ServletException(e);
}
return (InputStream)content;
}
esearch 요청에 대한 입력 스트림은 다음과 같은 XML 문서를 포함한다.
<?xml version="1.0"?>
<!DOCTYPE eSearchResult PUBLIC
"-//NLM//DTD eSearchResult, 11 May 2002//EN"
"http://www.ncbi.nlm.nih.gov/entrez/query/DTD/eSearch_020511.dtd">
<eSearchResult>
<Count>19</Count>
<RetMax>19</RetMax>
<RetStart>0</RetStart>
<QueryKey>1</QueryKey>
<WebEnv>0ed8yFoq_CFyEEP6hW9aZ9UoTCVrrPm2w343S9MRNaT9MQmwbnjI
</WebEnv>
<!-- additional data removed for brevity -->
</eSearchResult>
서블렛은 이 XML 문서에서 QueryKey와 WebEnv 요소의 컨텐츠를 추출해야하며, 이 컨텐츠를 efetch 후속 호출에 포함시켜야한다. 그러면 디스플레이를 위한 문서 데이터를 리턴하게 될 것이다.
결과 도출
efetch 결과가 작기 때문에 in-memory DOM 트리로 파싱이 가능하다. esearch로 리턴된 스트링을 파싱하는 서블렛은, 파싱하는 동안 Document오브젝트를 메모리로 가져오기 위해 DocumentBuilder를 사용한다.
// Create DOM parser and parse search result
DocumentBuilderFactory dbf =
DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document esearchDoc = db.parse(is);
// Get WebEnv, Count, and QueryKey from result
// WebEnv - result key
// QueryKey - history index
// Count - result set length
String webenv = getElementString(esearchDoc, "WebEnv");
String count = getElementString(esearchDoc, "Count");
String querykey = getElementString(esearchDoc, "QueryKey");
getElementString메서드는 주어진 이름(파일명)의 노드를 찾고 그 노드의 첫번째 Text 하위노드를 리턴하는 간단하고 편리한 기능을 한다. 서블렛은 파싱된 DOM 문서로부터 WebEnv 와 QueryKey 를 추출한다.
이 때에, 서블렛은 서버에서 대기하는 결과 집합을 포함하고 있다. 다음 단계는 efetch를 사용하여 데이터를 검색하고 포맷하는 것이다.
Fetch 매개변수 지정
Efetch에서는 esearch의 결과를 식별하기 위해 단지 몇가지의 매개변수만을 필요로한다.
db. 데이터베이스 식별("PubMed")
WebEnv. 세션 식별
query_key. 세션 안의 쿼리 식별
추가 매개 변수들은 사이즈를 제한하거나, 리턴되는 데이터의 포맷 제어하는 역할을 한다.
retstart와 retmax는 efetch 가 결과 중 일부 집합을 리턴하도록 명령한다. 이 때 이 결과치는 retstart에서 시작하고 retmax 레코드보다 작은 값을 리턴한다. 이 매개 변수들이 없으면 efetch는 종종 몇만 메가바이트가 되곤 하는 전체 결과를 리턴하고 만다.
retmode는 XML, HTML, text, ASN.1 중 어떤 형식으로 데이터를 생성할 것인지 지정한다. 기본값은 ASN.1, PubMed 의 네이티브 스토리지, 그리고 교환 포맷이다.
rettype은 각 레코드에서 어떤 것을 리턴할 지 명령한다. efetch은 기본값으로 abstracts을 리턴한다.
서블렛은 esearch에서와 같이 요청된 매개변수들의 Map을 생성한다. 서블렛이 esearch에서 검색한 WebEnv와 QueryKey스트링을 사용하고, 또한 원래 형식에서 수신한 몇가지 매개변수들을 포함한다. getParameter메서드는, 매개변수가 설정되지 않았을 때 기본값으로 대체하는 요청으로부터 간단히 매개변수를 얻는다.
paramMap = new TreeMap();
paramMap.put("WebEnv", webenv);
paramMap.put("query_key", querykey);
paramMap.put("db", "PubMed");
paramMap.put("retstart", getParameter(req, "start", "0"));
paramMap.put("retmax", getParameter(req, "max", "20"));
paramMap.put("retmode",
retmode = getParameter(req, "retmode", "xml"));
paramMap.put("rettype", getParameter(
req, "rettype", "abstract"));
// Create URL and get its content
surl = buildUrl(BASEURL_EFETCH, paramMap);
is = getContent(surl);
서블렛은 요청된URL을 구축하기위해 맵을 사용하며, 요청 결과로 InputStream 을 얻기 위해 getContent 을 사용한다.
문서 변환
요청된 데이터 형식이 XML이 아니거나 유효한 스타일시트가 없다면 서블렛은 efetch로 리턴된 데이터를 복사하여 브라우저에 표시한다. 이 기능은 e-utilities로 직접 실험할 때 유용하다.
데이터가 XML형식이고 비어있지 않은 유효한 스타일시트가 있다면 서블렛은 이 스타일시트를 데이터에 적용하여 결과를 브라우저에 리턴한다. 브라우저에 리턴엔 XML은 각 레코드에 대해 약간씩의 데이터를 포함하고 있다. 다음은 리턴된 데이터를 발췌한 것이다.
<?xml version="1.0"?>
<!DOCTYPE PubmedArticleSet PUBLIC "...">
<PubmedArticleSet>
<PubmedArticle>
<MedlineCitation Owner="NLM" Status="In-Process">
<!-- ... -->
<Article>
<!-- ... -->
<ArticleTitle>The thermal history of human fossils
and the likelihood of successful DNA amplification.
</ArticleTitle>
<!-- ... -->
이 데이터는 결과를 도출하기 위해 수행되는 스타일시트의 컨텐츠이다.
적용할 스타일시트를 지정하는 데에는 두가지 방법이 있다. 첫번째로는, 사용자형식에는 라디오 버튼으로 되어있는 "isFile" 사용자 형식인제, 변환하기 위해 어떤 시트를 사용할 것인지 지정한다. IsFile이 1이면 매개변수 stylesheet는 웹애플리케이션 아카이브(WAR file)의 스타일시트 이름을 포함하게된다. IsFile이 0이면 매개변수 sstext는 사용자가 형식 안의 TEXTAREA에 넣는 스타일시트를 사용한다. 서식화된 레코드를 보고자 할 때 이 기능을 사용하면 된다. 또한 텍스트 에디터로부터 바로 형식으로 XSL을 카피하여 새로운 레포트를 생성할 때도 사용할 수 있다.
변환을 수행하는 코드는 다음을 얻는다.
efetch 결과로부터 읽어드린 입력 스트림
서블렛 결과에 작성되는 결과 스트림
매개 변수 isFile
스타일시트의 이름이나 스타일시트 안의 텍스트 자체를 포함하는 스트링
이 메서드는 스타일시트로부터 Transformer 오브젝트를 구축한 후 소스와 수신자로서 입력과 출력 스트림을 전달하는 Transformer의 transform메서드를 호출한다.
// Create XSLT transformer for output.
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = null;
// Use identity transform if no transformer was specified
if (stylesheet == null || stylesheet.equals("")) {
t = tf.newTransformer();
} else {
StreamSource xslsource = null;
if (isFile) {
// Read XSL stylesheet from app archive and wrap it as
// a StreamSource. Then use it to construct
// a transformer.
InputStream xslstream = _config.getServletContext().
getResourceAsStream(stylesheet);
xslsource = new StreamSource(xslstream);
} else {
// Read XSL stylesheet from string
xslsource = new StreamSource(
new StringReader(stylesheet));
}
t = tf.newTransformer(xslsource);
}
// Do transform from input (e-utilities result) to
// output (servlet writer)
StreamSource ss = new StreamSource(is);
StreamResult sr = new StreamResult(os);
t.transform(ss, sr);
변환이 완료되면 출력 스트림에 결과 HTML을 작성하게 되며, 서버는 결과 컨텐츠를 브라우저에 표시한다.
결과 보기
애플리케이션 아카이브는 두가지 스타일시트를 포함한다.
titles.xsl는 문서의 타이틀만을 표시한다.
다음은 타이틀 형식의 결과 집합의 일부를 출력한 것이다.
extended.xsl는 국립의학 도서관에서 지정한 표준 추천 도서목록에서 각 레코드를 서식화한다. 덧붙여 실제 인용 정보(저널 종류, 출판 날짜, 쪽수 등)가 PubMed 사이트의 전체 요약문으로 하이퍼링크된다.
따라서 다음의 출력물을 보면 이전과 같은 결과이지만 좀 더 확장된 형식을 보여줌을 알 수 있다.
입력폼에 삽입된 스타일시트를 이용하여 사용자의 기호에 맞는 스타일을 정의할 수도 있다. TEXTAREA 스타일시트는 스타일시트의 골격을 제공한다. 서블렛을 이용하여 간단한 검색을 실행해보자. 스타일시트를 지정하지 않은 채 결과 XML을 파일에 복사하고 이를 텍스트 에디터에서 새로운 스타일시트를 생성하기 위한 XML예제로 사용한다. 스타일시트 전체를 복사하여 form에 붙인 후 "Using custom XSL style:" 라디오 버튼을 클릭하여 Search를 선택한다. 스타일시트가 유효하다면 서블렛은 검색결과를 포맷하기 위해 이 스타일시트를 사용하게 될 것이다.
이 예제 서블렛을 확장하여 좀 더 유용하게 만드는 것도 어려운 일은 아니다. 예를 들어 PubMed로부터 대형 데이터를 다운로드 받아 분석하거나, 링크된 DNA 시퀀스를 표시하는 바이오정보 애플리케이션을 작성하기 위해 e-utilities의 다른 데이터베이스를 사용할 수도 있을 것이다.
private static interface Patterns { // javascript tags and everything in between public static final Pattern SCRIPTS = Pattern.compile("<(no)?script[^>]*>.*?</(no)?script>", Pattern.DOTALL);
public static final Pattern STYLE = Pattern.compile("<style[^>]*>.*</style>", Pattern.DOTALL); // HTML/XML tags
public static final Pattern TAGS = Pattern.compile("<(\"[^\"]*\"|\'[^\']*\'|[^\'\">])*>");
public static final Pattern nTAGS = Pattern.compile("<\\w+\\s+[^<]*\\s*>"); // entity references public static final Pattern ENTITY_REFS = Pattern.compile("&[^;]+;"); // repeated whitespace public static final Pattern WHITESPACE = Pattern.compile("\\s\\s+"); }
/** * Clean the HTML input. */ public String clean(String s) { if (s == null) { return null; }
Matcher m;
m = Patterns.SCRIPTS.matcher(s); s = m.replaceAll(""); m = Patterns.STYLE.matcher(s); s = m.replaceAll(""); m = Patterns.TAGS.matcher(s); s = m.replaceAll(""); m = Patterns.ENTITY_REFS.matcher(s); s = m.replaceAll(""); m = Patterns.WHITESPACE.matcher(s); s = m.replaceAll(" ");
HTML을 파싱해보면 알겠지만, HTML 파싱만큼 비정형적인 것에 대한 분노를 끓어오르게 하는 것은 좀처럼 없는 것 같다. 다소 오바긴 하지만, 지난 며칠간의 상황이 그렇다.
HTML은 알다시피 상당히 융통성 있는 구조를 띄고 있는데, 이 융통성이란 것이 코드를 작성하는 데 있어 가장 골치아프고 황당한 경우를 많이 겪게 만드는 걸림돌로 작용할 때가 많다. 그중 몇 가지를 들자면, 여는 태그와 닫는 태그가 굳이 쌍을 이루지 않아도 브라우저에서 그럭저럭 보여진다는 것, 한 페이지안에 각종 HTML, BODY, 등의 태그가 중복되어 나타나는 것, 설상가상으로 한 페이지에 여러개의 문자 인코딩이 섞여 그것들끼리 꼬이고 충돌하는 등의 문제를 겪게 된다. 특히나 요즘같이 웹 표준에 대한 관심이 고조되고 있는 상황에서조차도 그러한 비정형의 극치를 달리는 HTML 페이지들이 만들어져 버젓이 브라우저의 인내심을 테스트하고 있다.
아무튼, 오늘 소개하는 HTML 파서는 누차 강조하지만 비정형의 극치, HTML을 well-formedness를 요구하는 XML 포맷으로 변환시켜 파싱할 수 있도록 해주는 툴이다. 이름하야 HtmlCleaner!
요즘 자주 쓰고 있는 HTML 파서는 널리 알려져 있는 Java 기반의 HtmlParser인데, 이 HtmlParser는 우연찮게도 Refactoring to Patterns(패턴을 활용한 리팩터링)에 리팩터링 예제로 단골손님처럼 나오는 프로그램이다. 아무튼 문제는 이 HtmlParser가 상당히 섬세하고 다양한 기능을 제공하기는 하지만 치명적인 약점으로 주석처리에 상당히 약하다는 것과 문법에 맞지 않는 HTML 태그가 포함된 HTML 문서의 파싱을 가끔씩 거부한다는 것이다. 예를 들면, 중간에 주석이 포함되어 있고, 그 안쪽으로 태그가 있을 경우 그 안쪽에 있는 태그 처리를 무시하고 넘어가 버린다는 것이다. 정작 필요한 내용이 주석이 시작된 다음에 나올 경우가 있는데, 이럴땐 정말 난감하다. -_-;
오늘도 마침 이러한 문제가 생겨서 고민고민 해가면서 주석을 없애보기도 하고 해보았지만, 워낙 문법을 지키지 않은 페이지라서 주석 제거하는 것조차도 힘에 버거웠다. 그러던 찰나 지난달 쯤인가 HTML 파서중에 HTML 페이지를 XML 파일로(Well-formedness!!!) 둔갑시켜 줘서 파싱을 수행한다는 파서를 소개했던 글이 갑자기 생각나 급하게 인터넷을 찾아보니, 나온게 바로 HtmlCleaner. ^^;
HtmlCleaner는 말 그대로 손쉽게 비정형 HTML 페이지를 파싱해서 중간에 필요없다 싶은 주석이나 몇가지 파싱에 불필요한 요소들을 사전에 미리 제거하고 파싱을 수행하는데, 파싱이 완료되면 알아서 XML 포맷으로 변환된다. 변환된 다음에는 출력을 XML 포맷의 문자열이나 파일과 같은 OutputStream으로도 내보낼 수 있다. 이렇게 나오는 결과물에 대한 파싱은 상당히 쉬워짐은 말할 것도 없다.
위 그림은 HtmlCleaner 클래스의 핵심! setOmitXXX() 메소드들이다. HTML 문서를 파싱할 때 몇 가지 태그나 주석들을 미리 제거할 수 있도록 설정하는 메소드이다. 실제 사용예를 보자면, 가장 간단한 사용법은 이렇다.
import java.io.IOException;
import org.htmlcleaner.HtmlCleaner;
publicclass HtmlCleanerTest {
publicstaticvoid main(String[] args) {
HtmlCleaner cleaner = new HtmlCleaner("test.html");
try {
cleaner.setOmitComments(true);
cleaner.setOmitDeprecatedTags(true);
cleaner.setOmitUnknownTags(true);
cleaner.clean();
cleaner.writeXmlToFile("output.xml");
} catch (IOException e) {
e.printStackTrace();
}
}
}
상당히 간단하다. HtmlCleaner 객체를 만든 다음 몇가지 설정을 해주고 clean() 메소드만 호출하게 되면 파싱 대상 문서가 XML 포맷으로 변환된다. 물론 Well-formed 된 채로.
그렇지만 HtmlCleaner는 HtmlParser 만큼의 파싱 고유의 기능을 풍부하게 제공하지는 않는다. 따라서 HTML을 파싱할 것이라면, 특히나 비구조적인 내용이 충만한 ^^ 골치덩어리 HTML 문서를 파싱할 것이라면 HtmlCleaner와 HtmlParser를 함께 사용하는 것이 좋을 것이다. :)
아래 코드는 현재 블로그에서 적용되고있는 스크립트입니다. 왜 이스크립트를 사용했냐면.. 귀차니즘때문에..ㅋㅋ^^ 문제가 뭐였냐면 글을 작성하다보면 링크항목이 몇개씩 있습니다. 기본으로 "_self" 형태로 링크가되어있어 사용자는 링크확인후 뒤로가기로 페이지를 돌아와야 했습니다. 그렇다고 매번 링크에 target을 "_blank"로 변경해주는것도 한두번이지 많은 링크가 있을땐 어이쿠....
그리하여 document.links로 링크객체들의 타겟속성을 "_blank"로 변경해주었더니 링크가 되는 부분은 전부 새창으로 뜨면서(관리자모드까지..) 더불편해지더라구요 그리하여 내린 대책이 특정영역의 특정태그에 대해서 속성을 변경하면 좋겠다고 생각을 했습니다.
분문에 해당하는 div태그에 id를 "mcontents"로 설정해주고 해당영역에 존재하는 <a>태그들에게 타겟을 새창뜨기로 변경하였더니 본문에 해당하는 링크항목(<a>)만 새창으로 활성화가 되더라구요^^ 저와 같은 고민을 하고 계시는 분은 한번적용시켜보세요^^
function setTarget() { // id가 'mcontents'인 영역안의 'a'태그의 항목을 가져와서 속성을 변경 for(var i=0; i<document.getElementById("mcontents").getElementsByTagName("A").length; i++) { document.getElementById("mcontents").getElementsByTagName("A")[i].target = "_blank"; } }
이번 설정으로 링크 목록의 정보를 가져오는 예제도 한번 만들어 보았습니다. 소스코드는 http://www.koxo.com 사이트에서 참조하였구요(레이아웃 잡는게 귀찮아서;;) 예제는 문서의 모든영역의 링크속성정보 혹은 특정 영역의 특정태그에 대한 속성정보를 보여주는 예제입니다. 특정영역의 특정태그는 위에서 사용했던 "sample" 영역의 <A> 태그만 적용하겠습니다. (약간만 수정하면 여러형태고 사용이 가능합니다. ^^) 소스코드 아래 샘플도 있으니 확인해보시면 더욱 좋습니다.
prototype.js는 Sam Stephenson에 의해 작성된 자바스크립트 라이브러리이다. 이 놀랍도록 멋진 생각과 표준에 의해 잘 작성된 코드의 일부는 웹2.0의 특성을 나타내는 풍부하고 상호작용하는 웹페이지와 많은 연관을 가진다.
만약 당신이 최근 이 라이브러리를 사용하기 시작했다면, 당신은 아마도 이 문서가 가장 좋은 지시사항중에 하나는 아니라는것을 알아차렸을것이다. 나 이전에 다른 많은 개발자들처럼, 나는 소스코드와 이것을 사용한 경험에서 prototype.js에 대한 지식을 가지게 되었다. 나는 모든 이가 배우고 공유하는 동안 좀더 많은 정보를 얻게 되는게 가장 좋은 것이라고 생각한다.
나는 objects, classes, functions, 그리고 이 라이브러리에 의해 제공되는 확장을 위한 비공식적인 참조문서 또한 제공한다.
당신이 예제와 참조문서를 읽었을때, Ruby프로그래밍 언어에 친숙한 개발자는 Ruby의 내장 클래스와 이 라이브러리에 의해 구현된 많은 확장 사이의 의도적인 유사성을 알아차리게 될것이다.
<script>
function testHash()
{
//let's create the object
var a = {
first: 10,
second: 20,
third: 30
};
//now transform it into a hash
var h = $H(a);
alert(h.toQueryString()); //displays: first=10&second=20&third=30
}
</script>
위에서 언급된 유틸리티 함수들은 좋다. 하지만 다시 보자. 그것들은 대부분 고급(advanced) 형태는 아니다. 당신은 스스로 이것들을 만들수 있고 당신 자신만의 스크립트에 유사한 함수를 이미 가지고 있을수도 있다. 하지만 이러한 함수들은 단지 일부분에 해당되는 팁일뿐이다.
나는 prototype.js에 대한 당신의 관심이 대부분의 AJAX기능을 다룰수 있다는 것이라고 확신한다. 그래서 당신이 AJAX로직을 수행할 필요가 있을때 좀더 쉽게 사용하도록 도와주는 라이브러리를 사용하는 방법을 살펴보자.
AJAX객체는 AJAX함수를 작성할 때 포함되는 트릭성격의 코드를 포장하고 단순화하기 위한 라이브러리에 의해 생성된 미리-정의된 객체이다. 이 객체는 캡슐화된 AJAX로직을 제공하는 많은 수의 클래스를 포함한다. 그 클래스중에 몇개를 살펴보자.
만약 당신이 어떠한 헬퍼(helper) 라이브러리도 사용하지 않는다면, 당신은 XMLHttpRequest객체를 생성하기 위한 많은 코드를 작성할 것이고 단계를 비동기적으로 수행할것이다. 그리고나서 응답을 뽑아내고 이것을 처리한다. 그리고나서는 한가지 이상의 브라우저를 지원하지 않는다면 스스로 행운이라고 생각할 것이다.
AJAX기능을 지원하기 위해, 라이브러리는 Ajax.Request클래스를 정의한다.
당신이 다음처럼 XML응답을 반환하는 http://yoursever/app/get_sales?empID=1234&year=1998 url을 통해 서버와 통신할수 있는 애플리케이션을 가지고 있다고 해보자.
XML을 가져오기 위해 서버와 통신하는 것은 Ajax.Request객체를 사용하면 매우 간단하다. 아래의 샘플은 이것을 수행하는 방법을 보여준다.
<script>
function searchSales()
{
var empID = $F('lstEmployees');
var y = $F('lstYears');
var url = 'http://yourserver/app/get_sales';
var pars = 'empID=' + empID + '&year=' + y;
var myAjax = new Ajax.Request(
url,
{
method: 'get',
parameters: pars,
onComplete: showResponse
});
}
function showResponse(originalRequest)
{
//put returned XML in the textarea
$('result').value = originalRequest.responseText;
}
</script>
<select id="lstEmployees" size="10" onchange="searchSales()">
<option value="5">Buchanan, Steven</option>
<option value="8">Callahan, Laura</option>
<option value="1">Davolio, Nancy</option>
</select>
<select id="lstYears" size="3" onchange="searchSales()">
<option selected="selected" value="1996">1996</option>
<option value="1997">1997</option>
<option value="1998">1998</option>
</select>
<br><textarea id=result cols=60 rows=10 ></textarea>
Ajax.Request객체의 생성자의 두번째 파라미터를 알아보겠는가.? {method: 'get', parameters: pars, onComplete: showResponse} 파라미터는 문자적 표기법으로 익명 객체를 나타낸다. 이것이 의미하는 것은 'get' 문자열을 포함하는 명명된 메소드(method)의 프라퍼티, HTTP요청 문자열을 포함하는 명명된 파라미터(parameter)의 프라퍼티, 그리고 함수 showResponse를 포함하는 onComplete 프라퍼티/메소드를 가지는 객체를 전달한다는 것이다.
당신이 AJAX를 비동기적으로(asynchronous) 서버에 호출할지를 결정하고 true나 false값으로 셋팅할수 있는 asynchronous(디폴트 값은 true이다.)와 같은 이 객체내 정의하고 활성화시킬수 있는 다른 프라퍼티가 몇개 있다.
이 파라미터는 AJAX호출을 위한 옵션을 정의한다. 샘플에서, 우리는 HTTP GET명령을 통해 첫번째 인자에서 url을 호출한다. 변수 pars내 포함된 조회문자열(querystring)을 전달하고 Ajax.Request객체는 응답을 받아들이는 작업을 마칠때 showResponse함수를 호출할 것이다.
당신이 아는것처럼, XMLHttpRequest는 HTTP호출을 하는 동안 진행과정을 보고한다. 이 진행과정은 4가지의 단계(Loading, Loaded, Interactive, 또는 Complete)를 알릴수 있다. 당신은 이러한 단계중에서 Ajax.Request객체 호출을 사용자정의 함수로 만들수 있다. Complete는 가장 공통적인 단계이다. 함수를 객체에게 알리기 위해, 우리 예제의 onComplete처럼 요청옵션내 onXXXXX로 명명된 프라퍼티/메소드를 간단히 제공하라. 당신이 전달하는 이 함수는 XMLHttpRequest객체 자체가 될 하나의 인자를 가진 객체에 의해 호출될것이다. 당신은 반환 데이터를 얻기 위해 이 객체를 사용할수 있고 아마도 호출의 HTTP결과 코드를 포함할 상태(status) 프라퍼티를 체크할것이다.
두개의 다른 흥미로운 옵션은 결과를 처리하기 위해 사용될수 있다. 우리는 AJAX호출이 에러없이 수행될때 호출될 함수처럼 onSuccess옵션을 명시할수 있다. onFailure옵션은 서버에러가 발생할때 호출될 함수가 될수 있다. onXXXXX의 선택적인 함수처럼, 이 두가지는 AJAX호출이 옮기는 XMLHttpRequest객체를 전달하도록 호출될수 있을것이다.
1.4.0 버전에서, 이벤트 콜랙 핸들링의 새로운 형태가 소개되었다. 만약 당신이 AJAX호출이 발생하는데도 불구하고 특정 이벤트를 위해 수행되어야 하는 코드를 가지고 있다면, 당신은 새로운 Ajax.Responders 객체를 사용할수 있다.
당신이 AJAX호출이 진행중이라는 시각적 표시를 보여주길 원한다고 해보자. 당신은 두개의 전역 이벤트 핸들러를 사용할수 있다. 하나는 첫번째 호출이 시작되었을때 아이콘을 보여주는것이고 다른 하나는 적어도 하나가 끝났을때 아이콘을 숨기는 것이다. 아래의 예제를 보자.
만약 당신이 HTML로 이미 포맷팅된 정보를 반환할수 있는 서버 종료점(endpoint)을 가진다면, 라이브러리는 당신이 Ajax.Updater클래스를 사용하는것을 좀더 쉽게 만들어준다. 이것으로 당신은 어느 요소가 AJAX호출로부터 반환된 HTML을 채우는지 알리게 된다. 예제는 내가 글로 표현하는 것보다 당신을 좀더 쉽게 이해하도록 도와줄것이다.
<script>
function getHTML()
{
var url = 'http://yourserver/app/getSomeHTML';
var pars = 'someParameter=ABC';
var myAjax = new Ajax.Updater(
'placeholder',
url,
{
method: 'get',
parameters: pars
});
당신이 보는것처럼, 코드는 onComplete함수와 생성자에 전달된 요소 id를 제외하고 이전예제에 비해서 매우 간단하다. 클라이언트에서 서버 에러들을 다루는 것이 어떻게 가능한지 보기 위해 코드를 조금 변경해 보자.
우리는 호출을 위해 더 많은 옵션을 추가하고 에러 상황을 뽑아내기 위해 함수를 명시한다. 이것은 onFailure옵션을 사용하여 수행한다. 우리는 성공적인 작동의 경우에만 활성화될 묶음자(placeholder)를 명시할것이다. 이것을 달성하기 위해, 우리는 간단한 요소 id에서 두개의 프라퍼티(success-모든것이 정상적일때 사용되는, failure-어떤것이 실패일때 사용되는)를 가지는 객체로 첫번째 파라미터를 변경할 것이다. 우리는 예제에서 failure 프라퍼티를 사용하지 않을것이고, onFailure옵션에서 reportError함수를 사용할것이다.
<script>
function getHTML()
{
var url = 'http://yourserver/app/getSomeHTML';
var pars = 'someParameter=ABC';
var myAjax = new Ajax.Updater(
{success: 'placeholder'},
url,
{
method: 'get',
parameters: pars,
onFailure: reportError
});
}
function reportError(request)
{
alert('Sorry. There was an error.');
}
</script>
<input type=button value=GetHtml onclick="getHTML()">
<div id="placeholder"></div>
만약 당신의 서버 로직이 HTML마크업 대신에 자바스크립트 코드를 반환한다면, Ajax.Updater객체는 자바스크립트 코드가 될수 있다. 자바스크립트로 응답을 처리하기 위한 객체를 얻기 위해, 당신은 객체 생성자의 마지막 인자로 프라퍼티들의 목록에 evalScripts: true;를 간단히 추가한다. 하지만 여기엔 문제가 있다. 이러한 스크립트 블럭은 페이지의 스크립트에 추가되지 않을것이다. 옵션이름인 evalScripts이 제시하는것처럼, 스크립트는 평가될것이다. 차이점이 무엇일까.? 요청된 URL이 반환하는 것이 무엇인지 추측해보자.
<script language="javascript" type="text/javascript">
function sayHi(){
alert('Hi');
}
</script>
<input type=button value="Click Me" onclick="sayHi()">
이 경우 당신이 이전에 이것을 시도했다면 이것이 작동하지 않는것을 알고 있을것이다. 이유는 스크립트 블럭은 평가될것이고 평가된 스크립트는 sayHi 라는 이름의 함수를 생성하지 않을것이다. 이것은 아무것도 하지 않을것이다. 이 함수를 생성하기 위해, 우리는 함수를 생성하기 위해 변경할 필요가 있다. 아래를 보라.
우리는 루프(loop)에 친숙하다. 당신이 알다시피, 배열 자체를 생성하고 같은 종류의 요소로 채운다. 루프 제어구조(이를 테면, foreach, while, repeat 등등)을 생성하고 숫자로 된 인덱스를 통해 순차적으로 각각의 요소에 접근하고 그 요소로 작업을 수행한다.
당신이 이것에 대해 생각할때, 언제나 당신은 코드에 배열을 가지고 루프내 배열을 사용할것이라는것을 의미한다. 이러한 반복을 다루기 위해 좀더 많은 기능을 가진 배열 객체가 있다면 좋지 않겠는가.? 그렇다. 많은 프로그래밍 언어는 배열이나 유사한 구조(collection과 list와 같은)에서 이러한 기능을 제공한다.
prototype.js는 우리에게 반복가능한 데이터를 다룰때 사용하도록 구현된 Enumerable 객체를 제공한다. prototype.js 라이브러리는 더 나아가 Enumerable의 모든 메소드로 Array 클래스를 확장한다
위에서 언급된것처럼, 이것은 같은 프라퍼티와 메소드를 가지는 배열내 모든 요소를 위해 공통이다. 우리의 새로운 배열을 가지고 iterator함수의 장점을 가질수 있는 방법을 보자.
문법에 따르는 요소를 찾아라.
<script>
function findEmployeeById(emp_id){
var listBox = $('lstEmployees')
var options = listBox.getElementsByTagName('option');
options = $A(options);
var opt = options.find( function(employee){
return (employee.value == emp_id);
});
alert(opt.innerHTML); //displays the employee name
}
</script>
<select id="lstEmployees" size="10" >
<option value="5">Buchanan, Steven</option>
<option value="8">Callahan, Laura</option>
<option value="1">Davolio, Nancy</option>
</select>
<input type="button" value="Find Laura" onclick="findEmployeeById(8);" >
배열에서 항목을 걸러내는 방법을 보자. 그리고나서 각각의 요소로부터 맴버를 가져온다.
<script>
function showLocalLinks(paragraph){
paragraph = $(paragraph);
var links = $A(paragraph.getElementsByTagName('a'));
//find links that do not start with 'http'
var localLinks = links.findAll( function(link){
var start = link.href.substring(0,4);
return start !='http';
});
//now the link texts
var texts = localLinks.pluck('innerHTML');
//get them in a single string
var result = texts.inspect();
alert(result);
}
</script>
<p id="someText">
This <a href="http://othersite.com/page.html">text</a> has
a <a href="#localAnchor">lot</a> of
<a href="#otherAnchor">links</a>. Some are
<a href="http://wherever.com/page.html">external</a>
and some are <a href="#someAnchor">local</a>
</p>
<input type=button value="Find Local Links" onclick="showLocalLinks('someText')">
이것은 이 문법에 완전히 빠지도록 하기 위한 몇가지 예제를 가진다. 사용가능한 모든 함수를 위해 Enumerable and Array 참조문서를 보라.
인자 value와 index를 반복적으로 전달하는 iterator 함수를 호출하는 것은 iteration과 현재 index내 현재 값을 각각 포함한다.
다음의 예제는 0에서 9까지의 메시지 박스를 표시할것이다.
<script>
function demoTimes(){
var n = 10;
n.times(function(index){
alert(index);
});
/***************************
* you could have also used:
* (10).times( .... );
***************************/
}
</script>
<input type=button value="Test Number.times()" onclick="demoTimes()">
함수(=메소드) 소유자 객체로 미리 묶는 함수의 인스턴스를 반환. 반환된 함수는 원래의 것과 같은 인자를 가질것이다.
bindAsEventListener(object)
instance
object: 메소드를 소유하는 객체
유하는 객체 함수(=메소드) 소유자 객체로 미리 묶는 함수의 인스턴스를 반환. 반환된 함수는 이것의 인자로 현재 이벤트 객체를 가질것이다.
실제로 이 확장중 하나를 보자.
<input type=checkbox id=myChk value=1> Test?
<script>
//declaring the class
var CheckboxWatcher = Class.create();
//defining the rest of the class implementation
CheckboxWatcher.prototype = {
initialize: function(chkBox, message) {
this.chkBox = $(chkBox);
this.message = message;
//assigning our method to the event
Enumerable 객체는 list형태의 구조내에서 항목을 반복하기 위한 좀더 멋진 코드를 작성하는 것을 허용한다.
많은 객체들은 유용한 인터페이스에 영향을 끼치기 위해 Enumerable 을 확장한다.
프라퍼티
타입
상세설명
Version
String
라이브러리의 버전
메소드
종류
인자
상세설명
each(iterator)
instance
iterator: Function(value, index)를 충족하는 함수 객체
주어진 iterator함수를 호출하는 것은 첫번째 인자내 목록으로 각각의 요소와 두번째 인자내 요소의 인덱스 전달한다.
all([iterator])
instance
iterator: Function(value, index)를 충족하는 함수 객체
이 함수는 주어진 함수를 사용하여 값들의 전체 집합을 테스트하기 위한 방법이다. iterator 함수가 어떤 요소를 위해 false나 null을 반환한다면, all은 false를 반환할것이다. 그렇지 않다면 true를 반환할것이다. iterator가 주어지지 않는다면, 요소 자체가 false 나 null이 아닌지 테스트할것이다. 당신은 "모든 요소가 false가 아닌지 체크한다"와 같이 이것을 읽을수 있다.
any(iterator)
instance
iterator: Function(value, index)를 충족하는 함수 객체(선택사항)
이 함수는 주어진 함수를 사용하여 값들의 전체 집합을 테스트하기 위한 방법이다. iterator함수가 어떤 요소를 위해 false 나 null을 반환하지 않는다면 any는 true를 반환할것이다. 그렇지 않다면 false를 반환할것이다. iterator가 주어지지 않는다면, 요소 자체가 false 나 null이 아닌지 테스트할것이다. 당신은 "어느 요소가 false가 아닌지 체크한다"와 같이 이것을 읽을수 있다.
collect(iterator)
instance
iterator: Function(value, index)를 충족하는 함수 객체
집합내 각각의 요소를 위한 iterator함수를 호출하고 Array로 각각의 결과를 반환한다. 집합내 각각의 요소를 위한 하나의 결과 요소는 같은 순서이다.
detect(iterator)
instance
iterator: Function(value, index)를 충족하는 함수 객체
집합내 각각의 요소를 위한 iterator함수를 호출하고 true를 반환하는 iterator함수를 야기하는 첫번째 요소를 반환한다. true를 반환하는 요소가 없다면, detect는 null을 반환한다.
entries()
instance
(none)
toArray()와 같다.
find(iterator)
instance
iterator: Function(value, index)를 충족하는 함수 객체
detect()와 같다.
findAll(iterator)
instance
iterator: Function(value, index)를 충족하는 함수 객체
집합내 각각의 요소를 위한 iterator함수를 호출하고 true로 해석되는 값을 반환하는 iterator함수를 야기하는 모든 요소를 가진 Array을 반환한다. 이 함수는 reject()와는 반대의 함수이다.
grep(pattern [, iterator])
instance
pattern: 요소를 일치시키기 위해 사용되는 RegExp객체, iterator: Function(value, index)를 충족하는 함수 객체
집합내 각각의 요소의 문자열 값을 pattern 정규표현식에 대해 테스트한다. 함수는 정규표현식에 대응되는 모든 요소를 포함하는 Array 를 반환할것이다. iterator함수가 주어진다면, Array는 대응되는 각각의 요소를 가진 iterator를 호출한 결과를 포함할것이다.
include(obj)
instance
obj: 객체
집합내 주어진 객체를 찾도록 시도한다. 객체가 찾아진다면, true를 반환하고 찾지 못한다면 false를 반환한다.
inject(initialValue, iterator)
instance
initialValue: 초기화 값처럼 사용되는 객체, iterator: Function(accumulator, value, index)를 충족하는 함수 객체
iterator함수를 사용하여 집합의 모든 요소를 조합한다. 호출된 iterator는 accumulator인자에서 이전 반복의 결과를 전달한다. 첫번째 반복은 accumulator인자내 initialValue를 가진다. 마지막 결과는 마지막 반환값이다.
집합의 각각의 요소내 methodName에 의해 명시되는 메소드를 호출하는 것은 주어진 인자(arg1에서 argN) 전달하고 Array객체로 결과를 반환한다.
map(iterator)
instance
iterator: Function(value, index)를 충족하는 함수 객체
collect()과 같다.
max([iterator])
instance
iterator: Function(value, index)를 충족하는 함수 객체
집합내 가장 큰 값이나 iterator가 주어진다면 집합내 각각의 요소를 위한 iterator호출의 가장 큰 결과를 반환한다.
include(obj)
instance
obj: 객체
include()과 같다.
min([iterator])
instance
iterator: Function(value, index)를 충족하는 함수 객체
집합내 가장 작은 값을 가진 요소나 iterator가 주어진다면 집합내 각각의 요소를 위한 iterator호출의 가장 작은 결과를 가진 요소를 반환한다.
partition([iterator])
instance
iterator: Function(value, index)를 충족하는 함수 객체
두개의 다른 배열을 포함하는 Array를 반환한다. 첫번째 배열은 true를 반환하는 iterator함수를 야기하는 모든 요소를 포함할것이고 두번째 배열은 남아있는 요소를 포함할것이다. 만약 iterator가 주어지지 않는다면, 첫번째 배열은 true로 해석하는 요소를 포함할것이고 다른 배열은 남아있는 요소를 포함할것이다.
pluck(propertyName)
instance
propertyName : 각각의 요소로부터 읽어들이는 프라퍼티의 이름. 이것은 요소의 인덱스를 포함할수 있다.
집합의 각각의 요소내 propertyName에 의해 명시된 프라퍼티에 값을 가져가고 Array객체로 결과를 반환한다.
reject(iterator)
instance
iterator: Function(value, index)를 충족하는 함수 객체
집합내 각각의 요소를 위한 iterator함수를 호출하고 false로 해석하는 값을 반환하는 iterator함수를 야기하는 모든 요소를 가진 Array를 반환한다. 이 함수는 findAll()과는 반대되는 함수이다..
현재의 집합으로 각각의 주어진 집합을 병합한다. 이 병합 작업은 같은 수의 요소를 가진 새로운 배열을 반환한다. 현재 집합과 각각의 요소가 각각의 병합된 집합으로부터 같은 인덱스를 가진 요소의 배열(이것을 하위 배열이라고 부르자.)이다. transform함수가 주어진다면, 각각의 하위 배열은 반환되기 전에 이 함수에 의해 변형딜것이다. 빠른 예제 : [1,2,3].zip([4,5,6], [7,8,9]).inspect() 는 "[[1,4,7],[2,5,8],[3,6,9] ]" 를 반환한다.
Class 객체는 라이브러리에서 다른 클래스를 선언할때 사용된다. 클래스를 선언할때 이 객체를 사용하는 것은 생성자로 제공되는 initialize()메소드를 지원하기 위한 새로운 클래스를 발생시킨다.
아래의 샘플을 보라.
//declaring the class
var MySampleClass = Class.create();
//defining the rest of the class implmentation
MySampleClass.prototype = {
initialize: function(message) {
this.message = message;
},
showMessage: function(ajaxResponse) {
alert(this.message);
}
};
//now, let's instantiate and use one object
var myTalker = new MySampleClass('hi there.');
myTalker.showMessage(); //displays alert
이 객체는 Ajax관련 이벤트가 발생할때 호출될 객체의 목록을 보존한다. 예를 들어, 당신이 AJAX작업을 위한 전역 예외 핸들러를 연결하길 원한다면 이 객체를 사용할수 있다.
프라퍼티
타입
종류
상세설명
responders
Array
instance
객체의 목록은 AJAX이벤트 알림(notifications)을 위해 등록되었다..
메소드
종류
인자
상세설명
register(responderToAdd)
instance
responderToAdd: 호출될 메소드를 가진 객체
responderToAdd인자를 전달하는 객체는 AJAX이벤트(이를테면, onCreate, onComplete, onException 등등)처럼 명명된 메소드를 포함해야만 한다. 유사한 이벤트가 발생하면, 적절한 이름을 가진 메소드를 포함하는 모든 등록된 객체가 호출되는 메소드를 가질것이다.
unregister(responderToRemove)
instance
responderToRemove: list로부터 제거될 객체
responderToRemove 인자로 전달되는 객체는 등록된 객체의 list로부터 제거될것이다.
dispatch(callback, request, transport, json)
instance
callback: 보고되는 AJAX이벤트 이름, request: 이벤트를 책임지는 the Ajax.Request 객체, transport: AJAX호출을 가지는 XMLHttpRequest 객체, json: 응답의 X-JSON 헤더(존재할때만)
등록된 객체의 목록을 통해 실행하는 것은 callback 인자내 결정된 메소드를 가지는 것을 찾는다. 호출되는 각각의 메소드는 다른 3개의 인자를 전달한다. AJAX응답이 몇몇 JSON컨텐츠를 가지는 X-JSON HTTP 헤더를 포함한다면, 이것은 평가되고 json인자로 전달될것이다. 만약 이벤트가 onException라면, transport인자는 대신에 예외를 가질것이고 json은 전달되지 않을것이다.
AJAX작업중 보고되는 가능한 이벤트/상태의 목록. 목록은 'Uninitialized', 'Loading', 'Loaded', 'Interactive', 그리고 'Complete.'를 포함한다.
transport
XMLHttpRequest
instance
AJAX작업을 가지는 XMLHttpRequest 객체
url
String
instance
요청에 의해 대상이 되는 URL
메소드
종류
인자
상세설명
[ctor](url, options)
constructor
url: 꺼내기 위한 url, options: AJAX 옵션
주어진 옵션을 사용하여 주어진 url을 호출할 이 객체의 하나의 인스턴스를 생성. 중요사항: 선택된 url은 브라우저의 보안 셋팅을 위한 대상이 될 가치가 없다. 많은 경우 브라우저는 현재 페이지처럼 같은 호스트로부터가 아니라면 url을 가져오지 않을것이다. 당신은 설정을 피하거나 사용자의 브라우저를 제한하기 위한 로컬 url만을 사용할 것이다.
evalJSON()
instance
(none)
이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 AJAX응답내 존재하는 X-JSON HTTP헤더의 컨텐츠를 평가하기 위해 내부적으로 호출된다.
evalReponse()
instance
(none)
이 메소드는 대개 외부적으로 호출되지 않는다. AJAX응답이 text/javascript의 Content-type헤더를 가진다면, 응답 몸체는 평가되고 이 메소드는 사용될것이다.
header(name)
instance
name: HTTP 헤더명
이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 AJAX응답의 HTTP헤더의 컨텐츠를 가져오기 위해 내부적으로 호출된다.
onStateChange()
instance
(none)
이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 AJAX호출 상태 변경시 객체 자체에 의해 호출된다.
request(url)
instance
url: AJAX호출을 위한 url
이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 생성자를 호출하는 동안 벌써 호출되었다.
respondToReadyState(readyState)
instance
readyState: 상태 숫자값(1 에서 4)
이 메소드는 대개 외부에서 호출되지 않는다. 이것은 AJAX호출 상태가 변경될때 객체 자체에 의해 호출된다.
setRequestHeaders()
instance
(none)
이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 HTTP요청을 하는 동안 보내어질 HTTP헤더를 조합하기 위한 객체 스스로에 의해 호출된다.
AJAX작업의 중요한 부분은 options 인자이다. 이것은 기대되는 프라퍼티를 가지는 동안 어떠한 객체도 전달될수 있다. 이것은 AJAX호출을 위해 익명 객체를 생성하는 것이 공통적이다.
프라퍼티
타입
디폴트
상세설명
method
String
'post'
HTTP요청의 메소드
parameters
String
''
요청에 전달한 값들의 url형태의 목록
asynchronous
Boolean
true
AJAX호출이 비동기적으로 만들어지는지 표시
postBody
String
undefined
HTTP POST의 경우 요청의 몸체내 전달되는 내용
requestHeaders
Array
undefined
요청과 함께 전달되기 위한 HTTP헤더의 목록. 이 목록은 많은 수의 항목을 가져야 한다. 나머지 항목은 사용자 정의 헤더의 이름이다. 그리고 다음의 항목은 헤더의 문자열 값이다. 예제 : ['my-header1', 'this is the value', 'my-other-header', 'another value']
onXXXXXXXX
Function(XMLHttpRequest)
undefined
각각의 이벤트/상태가 AJAX호출이 발생하는 동안 도착할때 호출될 사용자정의 함수. 예제 var myOpts = {onComplete: showResponse, onLoaded: registerLoaded};. 사용되는 함수는 AJAX작업을 가지는 XMLHttpRequest객체를 포함하는 하나의 인자를 받을것이다.
onSuccess
Function(XMLHttpRequest)
undefined
AJAX호출이 성공적으로 완성될때 호출될 사용자정의 함수. 사용되는 함수는 AJAX작업을 가지는 XMLHttpRequest객체를 포함하는 하나의 인자를 받을것이다.
onFailure
Function(XMLHttpRequest)
undefined
AJAX호출이 에러를 가진채 끝날때 호출될 사용자정의 함수. 사용되는 함수는 AJAX작업을 가지는 XMLHttpRequest객체를 포함하는 하나의 인자를 받을것이다.
insertion
Function(Object, String)
null
삽입하기 위해 호출되는 함수는 텍스트를 요소로 반환한다. 함수는 수정되기 위한 요소객체와 Ajax.Updater객체에만 적용되는 응답 텍스트의 두개의 인자를 가지고 호출된다.
Ajax.PeriodicalUpdater 객체는 받은 응답이 마지막 것과 같을때 비율을 새롭게 하여 연속적인 후퇴를 결정. 예를 들어, 당신이 2를 사용한다면, 새롭게 된것중에 하나가 이전것과 같은 결과를 만든후에, 객체는 다음 refresh를 위한 시간의 두배를 기다릴것이다. 이것은 다시 반복한다면, 객체는 4배를 기다릴것이다. 이것을 후퇴를 피하기 위해 정의되지 않거나 1을 사용하도록 남겨두라.
요청된 url이 당신 페이지의 특정 요소내 직접적으로 삽입하길 원하는 HTML을 반환할때 사용된다. 당신은 url이 도착을 평가할 <script>블럭을 반환할때 이 객체를 사용할수 있다. 스크립트로 작업하기 위해 evalScripts 옵션을 사용하라.
프라퍼티
타입
종류
상세설명
containers
Object
instance
이 객체는 두개의 프라퍼티(containers.success 는 AJAX호출이 성공할때 사용될것이다. 그리고 AJAX호출이 실패한다면 containers.failure가 사용될것이다.)를 포함한다.
메소드
종류
인자
상세설명
[ctor](container, url, options)
constructor
container: 이것은 요소의 id, 요소객체 자체, 또는 두개의 프라퍼티(AJAX호출이 성공했을때 사용될 object.success 요소(또는 id), 그리고 AJAX호출이 실패했을때 사용될 object.failure요소(또는 id))를 가지는 객체가 될수 있다. url: 가져오기 위한 url, options: AJAX 옵션
주어진 옵션을 사용하여 주어진 url을 호출할 이 객체의 하나의 인스턴스를 생성.
updateContent()
instance
(none)
이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 응답을 받았을때 객체 자체에 의해 호출된다. 이것은 HTML로 적절한 요소를 수정하거나 insertion옵션내 전달되는 함수를 호출할것이다. 이 함수는 두개의 인자(수정되기 위한 요소와 응답 텍스트)를 가지고 호출될것이다.
or container:이것은 요소의 id, 요소객체 자체, 또는 두개의 프라퍼티(AJAX호출이 성공할때 사용될 object.success 요소(나 id), AJAX호출이 실패할때 사용할 object.failure 요소(나 id))를 가지는 객체가 될수 있다. url: 가져오기 위한 url, options: AJAX 옵션
주어진 옵션을 사용하여 주어진 url을 호출할 이 객체의 하나의 인스턴스를 생성
start()
instance
(none)
이 메소드는 대개 외부적으로 호출되지 않는다. 이것의 정기적인 작업 수행을 시작하기 위해 객체 자체에 의해 호출된다.
stop()
instance
(none)
이 메소드는 대개 외부적으로 호출되지 않는다. 이것의 정기적인 작업 수행을 시작하기 위해 객체 자체에 의해 호출된다.
updateComplete()
instance
(none)
이 메소드는 대개 외부적으로 호출되지 않는다. 요청을 완성한 후에 사용되는 Ajax.Updater에 의해 호출된다. 이것은 다음 refresh스케줄링 하기 위해 사용된다.
onTimerEvent()
instance
(none)
이 메소드는 대개 외부적으로 호출되지 않는다. 이것은 다음 수정을 위한 시각일때 내부적으로 호출된다.
폼 입력 요소의 값을 모니터링하는 Abstract.TimedObserver의 구현물. 값 변경을 보고하는 이벤트를 드러내지 않는 요소를 모니터링하고자 할때 이 클래스를 사용하라. 이 경우 당신은 Form.Element.EventObserver 클래스를 대신 사용할수 있다.
메소드
종류
인자
상세설명
[ctor](element, frequency, callback)
constructor
element: element 객체 또는 아이디, frequency: interval in seconds, callback: function to be called when the element changes
폼내 데이터 항목 요소의 값이 변경하는지를 모니터링하는 Abstract.TimedObserver의 구현물. 당신이 값 변경을 보고하는 이벤트를 드러내지 않는 요소를 포함하는 폼을 모니터링하고자 할때 이 클래스를 사용하라. 이 경우 당신은 Form.EventObserver 클래스를 대신 사용할수 있다.
메소드
종류
인자
상세설명
[ctor](form, frequency, callback)
constructor
form: form 객체 또는 아이디, frequency: 초단위 간격, callback: form내 데이터 항목 요소가 변경될때 호출되는 함수
요소내 값 변경을 감지하기 위한 폼 데이터 항목 요소의 적절한 이벤트를 위한 콜백 함수를 수행하는 Abstract.EventObserver의 구현물. 만약 요소가 변경을 보고하는 이벤트를 드러내지 않는다면, 당신은 Form.Element.Observer 클래스를 대신 사용할수 있다.
메소드
종류
인자
상세설명
[ctor](element, callback)
constructor
element: element 객체 또는 아이디, callback: function to be called when the event happens
값이 변결될때 감지하기 위한 요소의 이벤트를 사용하여 폼내 포함되는 어느 데이터 항목 요소에 변경을 모니터링하는 Abstract.EventObserver의 구현물. 만약 폼이 변경을 보고하는 이벤트를 드러내지 않는 요소를 포함한다면, 당신은 Form.Observer 클래스를 대신 사용할수 있다.
메소드
종류
인자
상세설명
[ctor](form, callback)
constructor
form: form 객체 또는 아이디, callback: form내 데이터 항목 요소가 변경될때 호출되는 함수
스크롤 위치내 변경을 수용하기 위한 deltaX 와 deltaY 프라퍼티 조정. 페이지 스크롤후 withinIncludingScrolloffset를 호출하기 전에 이 메소드를 호출하는 것을 기억하라.
realOffset(element)
instance
element: object
요소에 영향을 끼치는 어느 스크롤 offset를 포함하는 요소의 정확한 스크롤 offset를 가진 Array을 반환. 이 결과 배열은 [total_scroll_left, total_scroll_top]과 유사하다.
cumulativeOffset(element)
instance
element: object
위치가 할당된 부모 요소에 의해 부과된 어느 offset를 포함하는 요소의 정확한 위치가 할당된 offset를 가진 Array을 반환. 결과 배열은 [total_offset_left, total_offset_top]과 유사하다.
within(element, x, y)
instance
element: object, x 와 y: 위치 조정
만약 주어진 지점이 주어진 요소의 직사각형내 조정이 되는지 테스트.
withinIncludingScrolloffsets(element, x, y)
instance
element: object, x and y: coordinates of a point
overlap(mode, element)
instance
mode: 'vertical' 나 'horizontal', element: object
within()은 이 메소드가 호출되기 전에 호출될 필요가 있다. 이 메소드는 요소에서 겹치는 것을 조정하는 세분화정도를 표현하는 0.0과 1.0사이의 10진수를 반환할것이다. 예를 들면, 만약 요소가 100px를 가지는 정사각형 DIV이고 (300,300)에 위치한다면, within(divSquare, 330, 330); overlap('vertical', divSquare);은 DIV의 top border로부터 10%(30px)를 가리키는 것을 의미하는 0.10을 반환할것이다.
clone(source, target)
instance
source: element 객체 또는 아이디, target: element 객체 또는 아이디
source요소에 대해 똑같이 target요소의 크기를 다시 조정하고 다시 위치를 지정
1.4.0을 위한 이 문서는 여전히 작업중입니다. 이 문서의 업데이트를 계속 지켜봐주십시오. 만약 에러를 발견한다면,
let me know나에게 알려주십시오. 그러면 가능한한 빨리 그것을 수정할것입니다. 한글 번역에 관련된 부분은 한국어 번역자으로 알려주십시오.
마음에 드는 텝메뉴를 선택한 후에 아래 그림처럼 generate & HTML 을 누르면....
저장하라고 묻네요. 일단 저장을 하면...탭용 배경이미지와 html 파일이 하나 저장됩니다.
html 파일을 소스보기 해볼까요.. 대략 이런 형태로 소스들이 만들어지네요. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Free CSS Navigation Menu Designs 1 at exploding-boy.com</title> <style type="text/css"> <!-- body { margin:0; padding:0; font: bold 11px/1.5em Verdana; }
이렇게 하면 한꺼번에 셀의 스타일을 지정할 수 있긴 하지만, 이러면 그 페이지에 있는 모든 테이블의 셀이 획일적으로 지정되어 버리기에 문제가 있습니다. 특히 페이지에 광고가 있다면, 그 광고의 테이블 셀도 여기서 지정한 대로 변하기 때문에, 광고의 레이아웃이 이상하게 됩니다.
id 를 이용하면, 그 id에 해당되는 범위 내에서만, 셀의 배경색을 일괄적으로 지정할 수 있습니다.
우선 테이블 태그에 <table id="foo"> 이렇게 적당한 아이디(id)를 부여합니다. 단 아이디가 숫자로 시작하면 안되고, 한글이나 특수 기호가 포함되면 안되고, 중복되어서도 안됩니다. 한 HTML 페이지에 그 아이디는 단 하나뿐이어야 합니다. 즉 id="foo" 라는 아이디 정의가 다른 태그에도 있으면 안 됩니다. 무슨 아이디든 아이디는 고유해야 합니다.
루트 엘리먼트로써 문서내에서 유일해야 하며, 나머지 구성요소는 루트 엘리먼트내에 위치해야 합니다.
<root></root>
루트 엘리먼트 자식 수준의 데이터를 xml문서라고 합니다. <name>홍길동</name> <age>30</age> <address>서울시 영등포구</address>
XML문서의 종료 1. Well-Formed XML Document : XML 1.0 문법 준수 2. Valid XML Document : DTD, Schema 문법 준수
인코딩 1. ASCII : 7bit 2. ISO Latin-1 : 8bit, 서유럽 문자코드 포함 3. KS C5601 : 한국 공업표준, 2바이트 사용 -> 완성형 한글 표현 4. EUC-KR : 영어(KS C5636) + 한글(KC C5601) 5. Unicode 1) UTF-8 : ASCII 문자(1바이트), 다른 문자(2바이트 이상), 한글 3바이트 2) UTF-16 : 모든 문자 2바이트
엘리먼트 (Element) 1. 시작태그와 끝태그는 항상 쌍을 이룹니다. 2. 단독(빈)태그는 끝에 "/" 를 표시합니다. 3. "<" 는 태그명으로 사용 불가능 합니다. 4. "<" 와 ">" 사이에 공백사용이 불가능 합니다. 5. 태그 중첩 사용이 불가능 합니다. 6. 태그는 모든 문자로 시작 가능하지만, 숫자나 "." 사용 불가능 합니다. 7. ":" 는 태그명으로 사용을 자제하는게 좋습니다. 8. 대소문자를 구별합니다.
엘리먼트 (Element) 종류 1. 내용을 가지는 Element (시작태그&끝태그) - <title>제목</title> - <head> <meta /> </head>
2. 내용을 가지지 않는 Element (시작태그) : 단독태그, 빈태그 - <br /> - <img />
엘리먼트 (Element)의 내용으로 올 수 있는 종류 1. 문자 데이터 2. 자식 엘리먼트 3. 엔티티 & 문자참조 : <name> </name>
※ 문자 데이터와 엔티티는 전혀 틀리며, 이 때 name은 엔티티를 가진다고 합니다. 4. CDATA Section : 해석되지 말아야 하는 데이터 집합으로 이 안에 태그등이 와도 태그로 인식하지 않습니다. 5. 주석 6. 공백 문자열 : 일반 문자 데이터와 틀립니다. (스페이스, 탭, 엔터 등)
속성 (Attribute) - 시작 엘리먼트에 포함되어야 합니다. - 속성명="속성값" or 속성명='속성값', 속성값은 " 나 ' 로 감싸줘야 합니다. - 속성명 명명법 : 엘리먼트명과 동일합니다
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title></title> <script language="javascript"> function Add() { var table1=document.getElementById("table1"); var tr=document.createElement("tr"); var td1=document.createElement("td"); td1.innerText=document.all.txtName.value; var td2=document.createElement("td"); td2.innerText=document.all.txtAddress.value;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title></title> <script language="javascript"> function XmlInfo() { //XML로드 var xmlDoc=new ActiveXObject("microsoft.XMLDOM"); xmlDoc.async=false; xmlDoc.load("cd.xml");
//원본 출력 document.all.txtOut.value=xmlDoc.xml;
//결과 출력(테이블) var result=""; result+="<h3>CD List</h3>"; result+="<table border='1'><tr><th>artist</th><th>title</th><th>tracks</th><th>price</th></tr>";
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title></title> <script language="javascript"> var num=1; var index=1;
function Init() { document.onmousedown=Create; document.oncontextmenu=function(){return false;} }
function Create() { if(event.button==1) { /* //1. CSS 이용 document.getElementById("layer1").style.left=event.x - 25; document.getElementById("layer1").style.top=event.y - 25; document.getElementById("layer1").style.display="block"; */
//2. DOM 이미지 동적 생성 및 Body 추가 var img=document.createElement("img"); img.setAttribute("src","images/img"+num+".gif");//(속성명, 속성값) num++; if(num>7)num=1; img.style.position="absolute"; img.style.left=event.x - 25; img.style.top=event.y - 25; document.body.appendChild(img); } else if(event.button==2) { if(document.body.childNodes.length>2) document.body.removeChild(event.srcElement); } else if(event.button==4) { event.srcElement.style.zIndex=index; index++; } }
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title></title> <script language="javascript"> function XMLCreate() { var xmlDoc=new ActiveXObject("microsoft.XMLDOM");
//1. 선언문 <?xml version='1.0' encoding='euc-kr'?> var PInode=xmlDoc.createProcessingInstruction("xml", "version='1.0' encoding='euc-kr'");
//2. 루트엘리먼트 <compactdiscs></compactdiscs> var rootNode=xmlDoc.createElement("compactdiscs");
//3. 엘리먼트 var compactdiscNode=xmlDoc.createElement("compactdisc"); var titleNode=xmlDoc.createElement("title"); var priceNode=xmlDoc.createElement("price");
//4. 텍스트 노드 var titleTextNode=xmlDoc.createTextNode("연애시대OST");