JSON은 웹 API와 데이터 교환에서 사실상의 표준이 된 경량 데이터 형식입니다. 반면 Excel은 풍부한 데이터 모델과 계산 기능을 가진 스프레드시트 도구입니다. 이 글에서는 Java용 Spire.XLS for Java 라이브러리를 사용하여 Excel 파일을 JSON으로 변환하는 방법을 다룹니다. 특히 여러 시트를 가진 워크북을 처리하고, 데이터 간의 계층적 관계를 반영한 중첩(nested) JSON을 생성하는 방법에 초점을 맞춥니다.
프로젝트에서 Spire.XLS for Java를 사용하려면 Maven pom.xml 파일에 다음 리포지토리와 의존성을 추가합니다.
<repositories>
<repository>
<id>com.e-iceblue</id>
<name>e-iceblue</name>
<url>https://repo.e-iceblue.com/nexus/content/groups/public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.xls</artifactId>
<version>16.6.5</version>
</dependency>
</dependencies>
Maven을 사용하지 않는다면, JAR 파일을 직접 다운로드하여 프로젝트의 클래스패스에 추가할 수 있습니다. JSON 처리를 위해 Jackson 라이브러리(com.fasterxml.jackson.core:jackson-databind)도 함께 사용합니다.
가장 기본적인 사용 사례는 하나의 워크시트를 JSON 객체 배열로 변환하는 것입니다. 첫 번째 행을 헤더로 사용하여 각 데이터 행을 하나의 JSON 객체로 매핑합니다.
예제 코드:
import com.spire.xls.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.io.File;
import java.io.IOException;
public class ExcelToJsonConverter {
public static void main(String[] args) {
// Excel 워크북 로드
Workbook workbook = new Workbook();
workbook.loadFromFile("EmployeeData.xlsx");
// 첫 번째 워크시트 접근
Worksheet worksheet = workbook.getWorksheets().get(0);
// 첫 번째 행에서 열 헤더 읽기
int columnCount = worksheet.getLastColumn();
String[] headers = new String[columnCount];
for (int col = 1; col <= columnCount; col++) {
headers[col - 1] = worksheet.get(1, col).getValue();
}
// Jackson ObjectMapper 및 ArrayNode 생성
ObjectMapper mapper = new ObjectMapper();
ArrayNode arrayNode = mapper.createArrayNode();
// 각 데이터 행을 JSON 객체로 변환
for (int row = 2; row <= worksheet.getLastRow(); row++) {
ObjectNode record = mapper.createObjectNode();
for (int col = 1; col <= columnCount; col++) {
record.put(headers[col - 1], worksheet.get(row, col).getValue());
}
arrayNode.add(record);
}
// 예쁘게 포맷팅하여 JSON 파일로 출력
try {
mapper.writerWithDefaultPrettyPrinter().writeValue(new File("EmployeeData.json"), arrayNode);
System.out.println("Excel 데이터가 JSON으로 변환되었습니다.");
} catch (IOException e) {
System.err.println("JSON 파일 쓰기 오류: " + e.getMessage());
}
// 워크북 리소스 해제
workbook.dispose();
}
}
실제 업무용 Excel 파일은 여러 시트를 포함하는 경우가 많습니다. 이때는 각 시트를 별도의 JSON 배열로 구성하여 하나의 JSON 객체에 담을 수 있습니다. 객체의 키는 시트 이름, 값은 해당 시트의 데이터 배열이 됩니다.
예제 코드:
import com.spire.xls.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.io.File;
import java.io.IOException;
public class MultiSheetExcelToJson {
public static void main(String[] args) {
Workbook workbook = new Workbook();
workbook.loadFromFile("SalesReport.xlsx");
ObjectMapper mapper = new ObjectMapper();
ObjectNode fullReport = mapper.createObjectNode();
// 워크북의 모든 워크시트 순회
for (int s = 0; s < workbook.getWorksheets().getCount(); s++) {
Worksheet worksheet = workbook.getWorksheets().get(s);
String sheetName = worksheet.getName();
// 첫 번째 행에서 헤더 읽기
int columnCount = worksheet.getLastColumn();
String[] headers = new String[columnCount];
for (int col = 1; col <= columnCount; col++) {
headers[col - 1] = worksheet.get(1, col).getValue();
}
// 데이터 행을 JSON 객체로 변환
ArrayNode sheetData = mapper.createArrayNode();
for (int row = 2; row <= worksheet.getLastRow(); row++) {
ObjectNode record = mapper.createObjectNode();
for (int col = 1; col <= columnCount; col++) {
record.put(headers[col - 1], worksheet.get(row, col).getValue());
}
sheetData.add(record);
}
// 이 시트의 데이터를 최종 출력에 추가
fullReport.set(sheetName, sheetData);
}
// 결합된 JSON을 예쁘게 포맷팅하여 파일로 출력
try {
mapper.writerWithDefaultPrettyPrinter().writeValue(new File("SalesReport.json"), fullReport);
System.out.println("다중 시트 워크북이 JSON으로 변환되었습니다.");
} catch (IOException e) {
System.err.println("JSON 쓰기 오류: " + e.getMessage());
}
workbook.dispose();
}
}
때로는 평면적인 배열보다 데이터의 계층적 관계를 표현하는 중첩 JSON이 필요합니다. 예를 들어, 프로젝트와 그에 속한 작업(task)이 Excel 행에 나열되어 있다면, 프로젝트별로 작업을 그룹화할 수 있습니다.
예제 코드:
import com.spire.xls.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.util.LinkedHashMap;
import java.util.Map;
import java.io.File;
import java.io.IOException;
public class NestedExcelToJson {
public static void main(String[] args) {
Workbook workbook = new Workbook();
workbook.loadFromFile("ProjectTasks.xlsx");
Worksheet worksheet = workbook.getWorksheets().get(0);
ObjectMapper mapper = new ObjectMapper();
// 프로젝트 삽입 순서를 유지하기 위해 LinkedHashMap 사용
Map<String, ObjectNode> projectMap = new LinkedHashMap<>();
for (int row = 2; row <= worksheet.getLastRow(); row++) {
String projectName = worksheet.get(row, 1).getValue();
String taskName = worksheet.get(row, 2).getValue();
String assignee = worksheet.get(row, 3).getValue();
String status = worksheet.get(row, 4).getValue();
// 프로젝트가 처음 등장하면 새 객체 생성
if (!projectMap.containsKey(projectName)) {
ObjectNode project = mapper.createObjectNode();
project.put("name", projectName);
project.set("tasks", mapper.createArrayNode());
projectMap.put(projectName, project);
}
// 작업(task) 객체를 생성하여 해당 프로젝트의 tasks 배열에 추가
ObjectNode task = mapper.createObjectNode();
task.put("task", taskName);
task.put("assignee", assignee);
task.put("status", status);
((ArrayNode) projectMap.get(projectName).get("tasks")).add(task);
}
// 최종 JSON 배열 구성
ArrayNode projectsJson = mapper.createArrayNode();
for (ObjectNode project : projectMap.values()) {
projectsJson.add(project);
}
try {
mapper.writerWithDefaultPrettyPrinter()
.writeValue(new File("ProjectTasks.json"), projectsJson);
System.out.println("중첩 JSON 파일이 성공적으로 생성되었습니다.");
} catch (IOException e) {
System.err.println("JSON 파일 쓰기 오류: " + e.getMessage());
}
workbook.dispose();
}
}
실제 Excel 파일은 빈 셀이나 다양한 데이터 타입을 포함할 수 있습니다. 견고한 변환을 위해 다음 사항을 고려해야 합니다.
CellRange.getType()으로 셀 타입이 CellValueType.Empty인지 확인하고, 기본값(예: 빈 문자열 "")을 제공하여 JSON에 null이 포함되지 않도록 합니다.getValue()는 문자열을 반환하므로, 숫자 타입은 getNumberValue().doubleValue()를 사용하여 JSON에서 숫자 타입으로 유지합니다.getDateTimeValue()로 java.util.Date를 얻은 후 SimpleDateFormat을 사용하여 ISO 8601과 같은 표준 문자열 형식으로 변환합니다.workbook.save("output.json")과 같은 간결한 API를 제공합니다. Apache POI는 오픈소스이지만 더 많은 수동 코딩이 필요합니다.이 글에서는 Spire.XLS for Java를 사용하여 Excel 파일을 JSON으로 변환하는 방법을 살펴보았습니다. 단일 시트 변환을 시작으로, 다중 시트 처리 및 중첩 JSON 생성까지 다루었습니다. 또한 데이터 타입과 빈 셀 처리 등 실무에서 중요한 고려사항도 확인했습니다. 이 접근 방식은 Excel 데이터를 웹 API나 데이터 파이프라인에 통합해야 할 때 유용하게 사용될 수 있습니다. 프로젝트의 라이선스 요구사항과 필요 기능에 따라 오픈소스 대안과의 비교를 통해 가장 적합한 도구를 선택할 것을 권장합니다.