최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday

티스토리 뷰



   HTML Table을 엑셀로 저장하기 : Export to excel sheet on client side


1. <A> 엘리먼트의 download 속성을 이용하여 저장하기.


2. <A> 엘리먼트의 download속성과 URL에 data타입을 사용하기, 엑셀 파일 이름 지정하기.


3. jquery.battatech.excelexport 라이브러리를 사용하기.


4. jquery.battatech.excelexport 라이브러리를 사용하여 파일이름 지정하기.


5. jquery.battatech.excelexport 라이브러리를 사용하여 파일이름 지정하기2.




   1. <A> 엘리먼트의 download 속성을 이용하여 저장하기.


[ code ]

<!DOCTYPE html>
<html lang="en">
<head>
	<meta name="Author" content="serpiko@hanmail.net" />
	<meta name="description" content="http://serpiko.tistory.com" />

	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
	<!--<meta name="viewport" content="width=device-width, initial-scale=1">-->
	<meta name="format-detection" content="telephone=no" />

	<link rel="styleesheet" type="text/css" href="" />
	<link rel="shortcut icon" href="" />
	<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
	<title>Document</title>
	<style>
		* {
			box-sizing: border-box;
			-moz-box-sizing: border-box;
			-webkit-box-sizing: border-box;
		}
		table{
			width: 650px;
			text-align: center;
			border: 1px solid black;
		}
	</style>
</head>
<body>
	<div id="wrap">
		<table id='tblExport'>
			<thead>
				<tr>
					<th>No</th>
					<th>Title</th>
					<th>Type</th>
					<th>Author</th>
					<th>URL</th>
				</tr>
			</thead>
			<tbody>
				<tr>
					<td>1</td>
					<td>SAP : Study And Programming</td>
					<td>Blog</td>
					<td style='background-color: LightBlue;'>Serpiko</td>
					<td>http://serpiko.tistory.com/</td>
				</tr>
				<tr>
					<td>2</td>
					<td>Twitter</td>
					<td>SNS</td>
					<td>Obvious, LLC</td>
					<td>https://www.twitter.com/</td>
				</tr>
				<tr>
					<td>3</td>
					<td>Instagram</td>
					<td>SNS</td>
					<td>Kevin Systrom, Mike Krieger</td>
					<td>https://instagram.com/</td>
				</tr>
			</tbody>
		</table>

		<button id='btnExport' type='button'>Export</button>
	</div>

	<script>
		$(document).ready(function(){
			$('#btnExport').click(function(){
				var link = document.createElement('a');
				link.download = "myFirstExample.xls";
				link.href = 'data:,' + $('#tblExport').text();
				link.click();
			});
		});
	</script>
</body>
</html>

32 : table에 id를 지정해 준다.
67 : button을 만들고 id를 지정해 준다.
73 : 새로운 엘리먼트인 <a>를 만들고
74 : HTML5 에서 추가된 속성인 download 속성에 파일 이름인 "myFirstExample.xls"를 지정해 준다.
75 : URL에 data형식, 표시될 내용을 넣고
76 : <a> 엘리먼트를 클릭한 것과 같은 트리거를 넣어준다.

[ 직접 보기 ↓ www.serpiko.meximas.com/JAVASCRIPT/excel/01_dataUse.html ]


[결과 화면]

myFirstExample.xls 로 제대로 저장되고 실행도 된다.

그러나 셀에 내용을 살펴 보면 테이블이 아닌 일반 텍스트로 내용이 들어가 있어서 표의 형태가 아니다.




   2. <A> 엘리먼트의 download속성과 URL에 data타입을 사용하기, 엑셀 파일 이름 지정하기.


[ code ]


<!DOCTYPE html>
<html lang="en">
<head>
	<meta name="Author" content="serpiko@hanmail.net" />
	<meta name="description" content="http://serpiko.tistory.com" />

	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
	<!--<meta name="viewport" content="width=device-width, initial-scale=1">-->
	<meta name="format-detection" content="telephone=no" />

	<link rel="styleesheet" type="text/css" href="" />
	<link rel="shortcut icon" href="" />
	<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
	<title>Document</title>
	<style>
		* {
			box-sizing: border-box;
			-moz-box-sizing: border-box;
			-webkit-box-sizing: border-box;
		}
		table{
			width: 650px;
			text-align: center;
			border: 1px solid black;
		}
	</style>
</head>
<body>
	<div id="wrap">
		<table id='tblExport'>
			<thead>
				<tr>
					<th>No</th>
					<th>Title</th>
					<th>Type</th>
					<th>Author</th>
					<th>URL</th>
				</tr>
			</thead>
			<tbody>
				<tr>
					<td>1</td>
					<td>SAP : Study And Programming</td>
					<td>Blog</td>
					<td style='background-color: LightBlue;'>Serpiko</td>
					<td>http://serpiko.tistory.com/</td>
				</tr>
				<tr>
					<td>2</td>
					<td>Twitter</td>
					<td>SNS</td>
					<td>Obvious, LLC</td>
					<td>https://www.twitter.com/</td>
				</tr>
				<tr>
					<td>3</td>
					<td>Instagram</td>
					<td>SNS</td>
					<td>Kevin Systrom, Mike Krieger</td>
					<td>https://instagram.com/</td>
				</tr>
			</tbody>
		</table>

		<button id='btnExport' type='button'>Export</button>
	</div>

	<script>
		$(document).ready(function(){

			function itoStr($num)
			{
				$num < 10 ? $num = '0'+$num : $num;
				return $num.toString();
			}

			var btn = $('#btnExport');
			var tbl = 'tblExport';

			btn.click(function(e){

				var dt = new Date();
				var year =	itoStr( dt.getFullYear() );
				var month = itoStr( dt.getMonth() + 1 );
				var day =	itoStr( dt.getDate() );
				var hour =	itoStr( dt.getHours() );
				var mins =	itoStr( dt.getMinutes() );

				var postfix = year + month + day + "_" + hour + mins;
				var fileName = "MyTable_"+ postfix + ".xls";

				var a = document.createElement('a');
				var data_type = 'data:application/vnd.ms-excel';
				var table_div = document.getElementById( tbl );
				var table_html = table_div.outerHTML.replace(/ /g, '%20');

				a.href = data_type + ', ' + table_html;
				a.download = fileName;
				a.click();

				e.preventDefault();
			});
		});
	</script>
</body>
</html>


32 : table에 id를 지정해 준다.
67 : button을 만들고 id를 지정해 준다.
73 : 10 이하인 수는 0을 붙여준다. 반환값의 타입은 문자열 속성이다.
84 ~ 89 : 년 월 일 시간 분 을 파일이름에 바인딩 하기 위해서 선언된 변수들이며, 2015년 4월 3일인 경우
           2015 4 3 이 되는데 문자열 속성으로 변환하지 않으면
91 : 91번 라인 처럼 변수+변수를 하게 되면 우리가 원하는 "2015 + 4 + 3 = 201543" 이 아니라 연산이 되어서 2022로 변한다.
     따라서 일단 한자릿 수 일경우 0을 붙여주고 문자열 처리(73)를 하면 "2015" + "04" + "03" ... 이 되고  "20150403"이 된다.
97: outerHTML으로 <table id='tblExport'> ~ </table> 의 범위까지 잡고, 
   ( innerHTML은 <table id='tblExport> 의 안에있는 <thead>~</tbody> 까지를 대상으로 한다. )
 
     table_div의 공백을  %20으로 치환한다.  
     공백을 치환하는 이유는 "My Str Variables"와 같이 띄어쓰기된 부분을 %20으로 인코딩 하기 위해서 이며 
     2가지 방법이있다.

     var uri = "My Str Variables";

     encodeURI(uri); //결과  : My%20Str%20Variables
     uri.replace(/ /g, '%20');   //결과  : My%20Str%20Variables
    
     결과는 모두 같다.
     다시 풀어서 사용하려면  console.log( decodeURI(str) ); // "My Str Variables"

94~101 : 위 (1. <A> 엘리먼트의 download 속성을 이용하여 저장하기.) 에서 설명한 내용과 같다.

103 : btn = $("#btnExport") 를 클릭했을 때 발생되는 event를 처리하는데 preventDefault를 쓰는 이유는 다음과 같다.
       ㄱ. 현재 버튼이 button이 아닌 A element이고 A element를 쓰는 이유는? 파일 네임을 바인딩 하기 위해서 download속성을 
           사용하고 엑셀 기능을 href에 URL로 사용하기 위해서 이다.
       ㄴ. 기존 <a>링크를 클릭했을때 이 요소에 click 이벤트 핸들러를 등록한다면, click 이벤트 실행과 동시에 새로운 페이지를 
            로드하게 된다. 마찬가지로 form도 기본동작인 submit 이벤트가 발생하는데, 이런 기본 동작을 중지시키고 click 이벤트
            핸들러만 실행 시키게 하는 방법이 바로 preventDefault 메서드를 사용하는 것이다.


[ 직접 보기 ↓  http://www.serpiko.meximas.com/JAVASCRIPT/excel/02_dataAndAuse.html ]




[결과 화면 ]


위에 살펴보았던 것 과 다르게 테이블의 형태를 유지하며, 파일이름도 지정해 줄 수 있다. 


그러나 자세히 보면 엑셀 특유의 그리드가 보이지 않는다.






   3. jquery.battatech.excelexport 라이브러리를 사용하기.


1,2 의 단점을 모두 해결해 줄 jquery.battatech.excelexport 라이브러리를 소개한다.


단순히 TABLE element말고도 XML, JSON 등을 같이 지원한다.


다운로드 https://github.com/battatech/battatech_excelexport


jquery.techbytarun.excelexportjs.min.js

jquery.techbytarun.excelexportjs.js



개요 : http://battatech.com/blog/how-to-export-to-excel-sheet-on-client-side


기본사용법은 다음과 같다.


[ code ]


<!DOCTYPE html>
<html lang="en">
<head>
	<meta name="Author" content="serpiko@hanmail.net" />
	<meta name="description" content="http://serpiko.tistory.com" />

	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
	<!--<meta name="viewport" content="width=device-width, initial-scale=1">-->
	<meta name="format-detection" content="telephone=no" />

	<link rel="styleesheet" type="text/css" href="" />
	<link rel="shortcut icon" href="" />
	<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
    <script type="text/javascript" src="js/jquery.battatech.excelexport.js"></script>
	<title>Document</title>
	<style>
		* {
			box-sizing: border-box;
			-moz-box-sizing: border-box;
			-webkit-box-sizing: border-box;
		}
		table{
			width: 650px;
			text-align: center;
			border: 1px solid black;
		}
	</style>
</head>
<body>
	<div id="wrap">
		<table id='tblExport'>
			<thead>
				<tr>
					<th>No</th>
					<th>Title</th>
					<th>Type</th>
					<th>Author</th>
					<th>URL</th>
				</tr>
			</thead>
			<tbody>
				<tr>
					<td>1</td>
					<td>SAP : Study And Programming</td>
					<td>Blog</td>
					<td style='background-color: LightBlue;'>Serpiko</td>
					<td>http://serpiko.tistory.com/</td>
				</tr>
				<tr>
					<td>2</td>
					<td>Twitter</td>
					<td>SNS</td>
					<td>Obvious, LLC</td>
					<td>https://www.twitter.com/</td>
				</tr>
				<tr>
					<td>3</td>
					<td>Instagram</td>
					<td>SNS</td>
					<td>Kevin Systrom, Mike Krieger</td>
					<td>https://instagram.com/</td>
				</tr>
			</tbody>
		</table>

		<button id='btnExport' type='button'>Export</button>
	</div>

	<script type="text/javascript">
    $(document).ready(function () {
        $("#btnExport").click(function () {
            $("#tblExport").excelexportjs({
                containerid: "tblExport"
               , datatype: 'table'
            });
        });
    });
	</script>
</body>
</html>

15 ~ 16 : 엑셀 라이브러리를 불러오기 전에 반드시 제이쿼리 엔진이 먼저 호출되어야 한다.

33 : Table에 ID를 지정해 주고

68 : Button 에 ID를 지정해 준다.

73 : 버튼을 클릭하면 battatech_excelexport 객체에 접근하여 containerid는 테이블이름, datatype은 table로 지정해 준다.


[ 직접 보기 ↓ http://www.serpiko.meximas.com/JAVASCRIPT/excel/03_libTable.html ]



[ 결과 확인 ]


드디어 말끔하게 이상없이 다 출력된다. 그러나 파일명을 지정하지 않았기 때문에 "다운로드.xls"로 되어있다.





   4. jquery.battatech.excelexport 라이브러리를 사용하여 파일이름 지정하기.


jquery.battatech.excelexport 라이브러리에서 파일명을 지정하는 방법은 다음과 같다.


<!DOCTYPE html>
<html lang="en">
<head>
	<meta name="Author" content="serpiko@hanmail.net" />
	<meta name="description" content="http://serpiko.tistory.com" />

	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
	<!--<meta name="viewport" content="width=device-width, initial-scale=1">-->
	<meta name="format-detection" content="telephone=no" />

	<link rel="styleesheet" type="text/css" href="" />
	<link rel="shortcut icon" href="" />
	<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
    <script type="text/javascript" src="js/jquery.battatech.excelexport.js"></script>
	<title>Document</title>
	<style>
		* {
			box-sizing: border-box;
			-moz-box-sizing: border-box;
			-webkit-box-sizing: border-box;
		}
		table{
			width: 650px;
			text-align: center;
			border: 1px solid black;
		}
	</style>
</head>
<body>
	<div id="wrap">
		<table id='tblExport'>
			<thead>
				<tr>
					<th>No</th>
					<th>Title</th>
					<th>Type</th>
					<th>Author</th>
					<th>URL</th>
				</tr>
			</thead>
			<tbody>
				<tr>
					<td>1</td>
					<td>SAP : Study And Programming</td>
					<td>Blog</td>
					<td style='background-color: LightBlue;'>Serpiko</td>
					<td>http://serpiko.tistory.com/</td>
				</tr>
				<tr>
					<td>2</td>
					<td>Twitter</td>
					<td>SNS</td>
					<td>Obvious, LLC</td>
					<td>https://www.twitter.com/</td>
				</tr>
				<tr>
					<td>3</td>
					<td>Instagram</td>
					<td>SNS</td>
					<td>Kevin Systrom, Mike Krieger</td>
					<td>https://instagram.com/</td>
				</tr>
			</tbody>
		</table>

		<a id="btnExport" href="#" download="">Export</a>
	</div>

	<script type="text/javascript">
    $(document).ready(function () {
        $("#btnExport").on('click', function () {
            var uri = $("#tblExport").excelexportjs({
                containerid: "tblExport"
                , datatype: 'table'
                , returnUri: true
            });

            $(this).attr('download', 'ExportToExcel.xls').attr('href', uri).attr('target', '_blank');
        });
    });
	</script>
</body>
</html>

68 : 위에서 썼던 방식과 다르게 button element가 아니라 <a> element를 사용한다.

77 : battatech_excelexport객체의 멤버변수인 returnUri가 기본값이 false로 되어있는데 true로 바꾸어준다.

80 : this 는 <a> 자기자신을 의미하며 download 속성에는 'ExportToExcel.xls'을

     href 속성에는 uri변수 ( jquery.battatech.excelexport 에서 처리 되고 나온 결과값 ) 이 반영된다.

     target 속성은 _blank (새창)


[ 직접 확인 ↓ http://www.serpiko.meximas.com/JAVASCRIPT/excel/04_libTableReturnUri.html ]




[ 결과 확인 ]


이제 모양과 파일 이름까지 잘 반영 된다.


마지막 단계에서 우리가 할 일은 날짜와 시간을 파일명에 반영하여 최종본으로 완성해 보겠다. 




   5. jquery.battatech.excelexport 라이브러리를 사용하여 파일이름 지정하기2 [최종]


jquery.battatech.excelexport 라이브러리 사용에서 파일명을 지정하고 실무에서 사용하기 위한 용도의 마지막 단계 설명이다.


[ code ]  demo.zip



<!DOCTYPE html>
<html lang="en">
<head>
	<meta name="Author" content="serpiko@hanmail.net" />
	<meta name="description" content="http://serpiko.tistory.com" />

	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
	<!--<meta name="viewport" content="width=device-width, initial-scale=1">-->
	<meta name="format-detection" content="telephone=no" />

	<link rel="styleesheet" type="text/css" href="" />
	<link rel="shortcut icon" href="" />
	<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
    <script type="text/javascript" src="js/jquery.battatech.excelexport.js"></script>
	<title>Document</title>
	<style>
		* {
			box-sizing: border-box;
			-moz-box-sizing: border-box;
			-webkit-box-sizing: border-box;
		}
		table{
			width: 650px;
			text-align: center;
			border: 1px solid black;
		}
	</style>
</head>
<body>
	<div id="wrap">
		<table id='tblExport'>
			<thead>
				<tr>
					<th>No</th>
					<th>Title</th>
					<th>Type</th>
					<th>Author</th>
					<th>URL</th>
				</tr>
			</thead>
			<tbody>
				<tr>
					<td>1</td>
					<td>SAP : Study And Programming</td>
					<td>Blog</td>
					<td style='background-color: LightBlue;'>Serpiko</td>
					<td>http://serpiko.tistory.com/</td>
				</tr>
				<tr>
					<td>2</td>
					<td>Twitter</td>
					<td>SNS</td>
					<td>Obvious, LLC</td>
					<td>https://www.twitter.com/</td>
				</tr>
				<tr>
					<td>3</td>
					<td>Instagram</td>
					<td>SNS</td>
					<td>Kevin Systrom, Mike Krieger</td>
					<td>https://instagram.com/</td>
				</tr>
			</tbody>
		</table>

		<a id="btnExport" href="#" download="">
			<button type='button'>Export</button>
		</a>
	</div>

	<script type="text/javascript">
    $(document).ready(function () {

		function itoStr($num)
		{
			$num < 10 ? $num = '0'+$num : $num;
			return $num.toString();
		}
		
		var btn = $('#btnExport');
		var tbl = 'tblExport';

        btn.on('click', function () {
			var dt = new Date();
			var year =	itoStr( dt.getFullYear() );
			var month = itoStr( dt.getMonth() + 1 );
			var day =	itoStr( dt.getDate() );
			var hour =	itoStr( dt.getHours() );
			var mins =	itoStr( dt.getMinutes() );

			var postfix = year + month + day + "_" + hour + mins;
			var fileName = "MyTable_"+ postfix + ".xls";

            var uri = $("#"+tbl).excelexportjs({
                containerid: tbl
                , datatype: 'table'
                , returnUri: true
            });

            $(this).attr('download', fileName).attr('href', uri).attr('target', '_blank');
        });
    });
	</script>
</body>
</html>


[ 직접 확인 ↓ http://www.serpiko.meximas.com/JAVASCRIPT/excel/05_libTableReturnUri_2.html  ]




[ 결과 확인 ]


1 ~ 5 단계를 통하여 Table에 대한 xls 저장과, 라이브러리를 통한 xls 내보내기에 대하여 살펴 보았다.







   의문점 


jquery.battatech.excelexport.js 의 엔진을 살펴보면 마지막 return 스트링에 아래와 같은 내용이 있다.


1. <head> ~ </head> 사이에 META 태그로 파일명을 넣을 수 있게 하면 편했을 텐데 왜 지원하지 않았을까?


META 태그에서는 <meta name="content-disposition" content="inline; filename=myExcel.xls"> 과 같이 파일명을 지정해 줄 수 있다.


실제로 서버사이드에서 Excel Export 를 할 경우 자주 쓰였던 방법이다.


해본 결과 일단 META 태그로는 파일명이 바뀌지 않는다.




2. 그렇다면 data:application/octet-stream;base64,SGVsbG8= 의 URI 속성에 파일명을 지정해 줄 수는 없을까?


역시 NO.


일단 data URI의 목적은 데이터 스트림이지 파일이 아니라는 점과 애초에 소스파일로서 취급되어 에이전트에서 핸들링 되지 


않는다는 것이다.


( The entire purpose is that it's a datastream, not a file. 


The data source should not have any knowledge of the user agent handling it as a file... and it doesn't. 


http://stackoverflow.com/questions/283956/is-there-any-way-to-specify-a-suggested-filename-when-using-data-uri )




3. 원인과 결과


HTML5는 <A> element의 "download" 속성을 발표했다. 보편적은(구형IE브라우저를 지원하지 못하지만) 아니지만 사용자가 


하이퍼 링크를 클릭 할 때 대상을 다운로드 하도록 지정하는 공식적인 기능이다.


Specifies that the target will be downloaded when a user clicks on the hyperlink. )


따라서 1~2번의 만들어진 DIV를 <A> element 통해 트리거한 이유가 여기에 있다.



2번 항목 참조 : http://www.kubilayerdogan.net/javascript-export-html-table-to-excel-with-custom-file-name/











댓글