ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Vue] excel파일을 읽어서 json형식으로 파싱하기
    programing/Language 2019. 1. 5. 21:40

     

    안녕하세요, Einere입니다.

    (ADblock을 꺼주시면 감사하겠습니다.)


    오늘은 vue에서, 엑셀파일을 읽어서 json형식으로 파싱하는 방법에 대해 알아보겠습니다.

    엑셀 파일을 json형식으로 파싱해주는 라이브러리인 "js-xlsx"를 사용합니다.

     

     

     

    install js-xlsx

    js-xlsx의 repository에서는 4가지 방식을 설명하고 있습니다.

     

     

    local file을 이용하는 방법

    <script lang="javascript" src="dist/xlsx.full.min.js"></script>

     

    위와 같이 로컬 파일을 이용할 수 있습니다.

    대신, 해당 위치에 js-xlsx파일이 존재해야 합니다.

     

     

    CDN을 이용하는 방법

    <script lang="javascript" src="https://unpkg.com/xlsx/"></script>

     

    위와 같이 http프로토콜을 이용한 URI를 사용하여, 파일 제공 사이트로부터 얻어오는 방법이 있습니다.

    인터넷을 이용하므로, 인터넷이 가능해야 하며, 제공 사이트가 먹통이 되면 불가능한 방법입니다.

    다른 CDN사이트로는 아래와 같습니다.

    • https://jsdelivr.com/package/npm/xlsx
    • http://cdnjs.com/libraries/xlsx
    • https://bundle.run/xlsx@latest?name=XLSX
     
     

    npm을 이용하는 방법

    $ npm install xlsx

     

    만약 xlsx를 적용하고자 하는 vue 프로젝트가 vue-cli를 이용하여 생성한 프로젝트라면, npm을 사용하여 module로 설치할 수 있습니다.

    위의 명령어를 터미널에 입력하시면, 프로젝트 내의 node_modules폴더 내에 xlsx라는 폴더가 생긴 것을 확인할 수 있습니다.

     

     

    bower를 이용하는 방법

    $ bower install js-xlsx

     

    bower는 제가 사용해보지 않아서 잘 모르겠네요. ㅎㅎ

     

     

     

    coding vue file

    이제 필요한 라이브러리를 설치했으니, 실제로 읽고 파싱하는 코드를 가르쳐 드리겠습니다.
    (저는 npm을 이용해 설치했습니다.)
     
     
    <input type="file" @change="readFile" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet">
    readFile(event) {
        // get File object from input tag
        const file = event.target.files[0];
        const fileName = file.name;
    
        // declare FileReader, temp result
        const reader = new FileReader();
        let tmpResult = {};
    
        // if you use "this", don't use "function(e) {...}"
        reader.onload = (e) => {
            let data = e.target.result;
            data = new Uint8Array(data);
            // get excel file
            let excelFile = XLSX.read(data, { type: "array" });
    
            // get prased object
            excelFile.SheetNames.forEach(function(sheetName) {
                const roa = XLSX.utils.sheet_to_json(
                    excelFile.Sheets[sheetName],
                    { header: 1 }
                );
                if (roa.length) tmpResult[sheetName] = roa;
            });
            this.result = tmpResult.Sheet1;
        };
        reader.readAsArrayBuffer(file);
    }

    위의 코드는 script영역에 코딩하셔야 합니다. 만약 .vue형식의 파일이라면, vue인스턴스 내의 methods 내부에 작성하시면 됩니다.

     

    기본적으로 readFile()함수는 event handler입니다. 왜냐하면 브라우저에서는 기본적으로 파일 시스템에 접근하지 못하게 되어 있기 때문입니다.

    따라서 <input>태그를 이용하여 엑셀 파일을 선택하면 해당 엑셀 파일을 FileReader로 읽은 후, 읽은 데이터를 js-xlsx를 이용해 json형식으로 파싱합니다.

     

    위 코드 기준으로, 파싱된 데이터는 tmpResult에 저장됩니다.

     

    제 경우 excel파일의 시트명이 디폴트값이어서, tmpResult.Sheet1을 결과값으로 받았습니다.

    만약 시트가 여러개인 경우, console.log()를 통해 tmpResult를 출력해보시고, 알맞은 키값을 보고 수정하시면 됩니다.

     

    해당 기능을 구현하면서 제일 고생한 부분은 비동기함수라는 특성이었습니다.

    readAsArrayBuffer()를 실행한 뒤, 결과값을 익명함수(onload)내에서 외부변수에 저장해야 해야 합니다.

    처음엔 이를 위해 this.result라는 변수에 저장할려고 했으나, thisFileReader를 가리키게 되어 실패했습니다.(onload에 할당되는 callback함수에서 this는 FileReader객체를 가리킵니다.)

    그래서 저는 onload에 할당되는 callback함수를 일반 함수에서 화살표 함수로 바꾸었습니다.

    화살표 함수는 lexical scope이기 때문에, this키워드가 FileReader에 바인딩되지 않고, 전역 객체인 Vue Instance객체에 바인딩 됩니다.

    그러면 vue instance의 result에 값을 저장할 수 있게 됩니다.

    처음에 이 생각을 못해서 promise를 이용할려고 했으나 결국 펑펑 터져버려서.. 고생을 좀 했습니다.

    댓글

Designed by black7375.