From 03e8e649b540876a15457efb023f16f08d6a39d8 Mon Sep 17 00:00:00 2001 From: wantaek Date: Thu, 3 Sep 2026 13:59:16 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20DOM=20=EA=B2=80=EC=A6=9D=EA=B8=B0?= =?UTF-8?q?=EA=B0=80=20=EC=8A=A4=ED=82=A4=EB=A7=88=20=EB=93=B1=EB=A1=9D=20?= =?UTF-8?q?=EC=97=AC=EB=B6=80=EB=A5=BC=20XML=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=9C=A0=EB=AC=B4=EB=A1=9C=20=ED=8C=90=EB=8B=A8=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EgovDOMValidatorService.parse() 는 getXMLFile() 이 비어 있지 않으면 JAXP 의 schemaLanguage 를 XML Schema 로 바꾸고 schemaSource 에 getSCHEMAFile() 을 넣는다. 조건을 거는 프로퍼티와 값으로 쓰는 프로퍼티가 서로 다르다. 그래서 두 방향으로 어긋난다. 스키마 없이 XML 만 파일로 넘기면 schemaSource 가 null 인 채 스키마 모드가 켜져, parse(true) 가 "cvc-elt.1.a: 'person' 요소의 선언을 찾을 수 없습니다" 로 실패한다. 같은 XML 을 문자열로 넘기면 스키마 모드가 꺼져 있어 문법을 찾을 수 없다는 다른 결과가 나온다. 반대로 스키마를 줘도 XML 을 문자열로 넘기면 스키마가 등록되지 않아 setSCHEMAFile() 이 무시된다. XML 을 파일로 주는지 문자열로 주는지는 검증 방식을 정하는 조건이 아니다. 형제인 EgovSAXValidatorService 는 같은 자리에서 getSCHEMAFile() 이 null 인지 만 보고 스키마 검증 기능을 켠다. 그 조건에 맞췄다. XML 을 파일로 준 결과와 문자열로 준 결과가 같은지 확인하는 테스트를 더했다. 수정을 되돌리면 두 건 모두 실패한다. 모듈 테스트 5건 통과. --- .../rte/fdl/xml/EgovDOMValidatorService.java | 2 +- .../xml/EgovDOMValidatorSchemaSourceTest.java | 86 +++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 Foundation/org.egovframe.rte.fdl.xml/src/test/java/org/egovframe/rte/fdl/xml/EgovDOMValidatorSchemaSourceTest.java diff --git a/Foundation/org.egovframe.rte.fdl.xml/src/main/java/org/egovframe/rte/fdl/xml/EgovDOMValidatorService.java b/Foundation/org.egovframe.rte.fdl.xml/src/main/java/org/egovframe/rte/fdl/xml/EgovDOMValidatorService.java index a1d9dced..80007d1c 100755 --- a/Foundation/org.egovframe.rte.fdl.xml/src/main/java/org/egovframe/rte/fdl/xml/EgovDOMValidatorService.java +++ b/Foundation/org.egovframe.rte.fdl.xml/src/main/java/org/egovframe/rte/fdl/xml/EgovDOMValidatorService.java @@ -85,7 +85,7 @@ public boolean parse(boolean isValid) throws IOException, SAXException, Validato factory.setNamespaceAware(true); factory.setValidating(isValid); - if (!ObjectUtils.isEmpty(getXMLFile())) { + if (!ObjectUtils.isEmpty(getSCHEMAFile())) { factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema"); factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaSource", getSCHEMAFile()); } diff --git a/Foundation/org.egovframe.rte.fdl.xml/src/test/java/org/egovframe/rte/fdl/xml/EgovDOMValidatorSchemaSourceTest.java b/Foundation/org.egovframe.rte.fdl.xml/src/test/java/org/egovframe/rte/fdl/xml/EgovDOMValidatorSchemaSourceTest.java new file mode 100644 index 00000000..459266d5 --- /dev/null +++ b/Foundation/org.egovframe.rte.fdl.xml/src/test/java/org/egovframe/rte/fdl/xml/EgovDOMValidatorSchemaSourceTest.java @@ -0,0 +1,86 @@ +package org.egovframe.rte.fdl.xml; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +/** + * {@link EgovDOMValidatorService}가 스키마 등록 여부를 스키마 파일로 판단하는지 검증한다. + * + *

형제인 {@link EgovSAXValidatorService}는 {@code getSCHEMAFile()}이 있을 때만 스키마 검증을 + * 켠다. DOM 쪽은 같은 자리에서 {@code getXMLFile()}을 보므로, XML을 파일로 주면 스키마가 없어도 + * 스키마 모드가 켜지고 문자열로 주면 스키마를 줘도 등록되지 않는다. XML을 어떤 형태로 주는지는 + * 검증 방식을 바꾸는 조건이 아니므로, 두 입력 형태의 결과가 같은지로 확인한다.

+ */ +class EgovDOMValidatorSchemaSourceTest { + + private static final String XML = "x"; + + private static final String XSD = + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "\n"; + + /** + * parse(true) 결과를 비교 가능한 문자열로 만든다. 정상 종료면 반환값, 예외면 예외 타입과 메시지다. + */ + private String outcome(EgovDOMValidatorService validator) { + try { + return "returned " + validator.parse(true); + } catch (Exception e) { + return e.getClass().getName() + ": " + e.getMessage(); + } + } + + private Path write(Path dir, String name, String content) throws Exception { + Path path = dir.resolve(name); + Files.write(path, content.getBytes(StandardCharsets.UTF_8)); + return path; + } + + @Test + @DisplayName("스키마 파일이 없으면 XML을 파일로 줘도 스키마 검증이 켜지지 않는다") + void schemaModeStaysOffWithoutSchemaFile(@TempDir Path tempDir) throws Exception { + Path xmlFile = write(tempDir, "person.xml", XML); + + EgovDOMValidatorService fromFile = new EgovDOMValidatorService(); + fromFile.setXMLFile(xmlFile.toString()); + + EgovDOMValidatorService fromString = new EgovDOMValidatorService(); + fromString.setXML(XML); + + String fileOutcome = outcome(fromFile); + // cvc-* 는 XML Schema 검증 오류 코드다. 스키마를 준 적이 없으므로 나오면 안 된다. + assertFalse(fileOutcome.contains("cvc-"), "스키마 없이 스키마 검증이 수행되었다: " + fileOutcome); + assertEquals(outcome(fromString), fileOutcome); + } + + @Test + @DisplayName("스키마 파일을 주면 XML을 문자열로 줘도 스키마가 등록된다") + void schemaFileIsRegisteredForStringXml(@TempDir Path tempDir) throws Exception { + Path xmlFile = write(tempDir, "person.xml", XML); + Path schemaFile = write(tempDir, "person.xsd", XSD); + + EgovDOMValidatorService fromFile = new EgovDOMValidatorService(); + fromFile.setXMLFile(xmlFile.toString()); + fromFile.setSCHEMAFile(schemaFile.toString()); + + EgovDOMValidatorService fromString = new EgovDOMValidatorService(); + fromString.setXML(XML); + fromString.setSCHEMAFile(schemaFile.toString()); + + assertEquals(outcome(fromFile), outcome(fromString)); + } +}