diff --git a/000000_DIW_2504회_B형_채점결과_0점카운트.xlsx b/000000_DIW_2504회_B형_채점결과_0점카운트.xlsx deleted file mode 100644 index cdfa50d..0000000 Binary files a/000000_DIW_2504회_B형_채점결과_0점카운트.xlsx and /dev/null differ diff --git a/copy_all_hwp.py b/01_copy_all_hwp.py similarity index 87% rename from copy_all_hwp.py rename to 01_copy_all_hwp.py index 268f47e..e9fdae1 100644 --- a/copy_all_hwp.py +++ b/01_copy_all_hwp.py @@ -5,7 +5,7 @@ import unicodedata def copy_dic_subdirs(source_root, target_root_a, target_root_b, target_root_c, target_root_d, target_root_e): for root, dirs, files in os.walk(source_root): for dir_name in dirs: - if dir_name.lower() == 'diw': # DIC 디렉토리 탐색 + if dir_name.lower() == 'diw': # DIW 디렉토리 탐색 parent_dir = os.path.basename(os.path.dirname(os.path.join(root, dir_name))) target_root = None parent_dir = unicodedata.normalize('NFC', parent_dir) @@ -33,18 +33,16 @@ def copy_dic_subdirs(source_root, target_root_a, target_root_b, target_root_c, t test_folder_path = os.path.join(target_root, "TEST") os.makedirs(test_folder_path, exist_ok=True) - - test_folder_path = os.path.join(target_root, "TEST") - os.makedirs(test_folder_path, exist_ok=True) + else: print(f"Skipping {dir_name} under {parent_dir}, as it doesn't match '2교시' or '3교시'.") # 사용법 # exam_round = "2504_2" -exam_round = "2504" +exam_round = "2505" # source_directory = r"C:\Users\dra\project\data\제2504회 수시2(제주)\답안파일" # 원본 디렉토리 경로 -source_directory = r"C:\Users\dra\project\data\제2504회 정기\답안파일" # 원본 디렉토리 경로 +source_directory = r"C:\Users\dra\project\HWP\HWP-Scoring\회차별채점자료\2505\hwp_정답" # 원본 디렉토리 경로 target_directory_a = f".\\input\\{exam_round}\\A" # '1교시'의 타겟 경로 target_directory_b = f".\\input\\{exam_round}\\B" # '2교시'의 타겟 경로 diff --git a/conversion_hwp_to_xml.py b/02_conversion_hwp_to_xml.py similarity index 94% rename from conversion_hwp_to_xml.py rename to 02_conversion_hwp_to_xml.py index 051d7c6..0400137 100644 --- a/conversion_hwp_to_xml.py +++ b/02_conversion_hwp_to_xml.py @@ -61,7 +61,10 @@ def convert_hwp_to_xml(input_folder, output_folder): # 출력 폴더가 없으면 생성 os.makedirs(output_folder, exist_ok=True) - + + parent_folder = os.path.dirname(output_folder) + test_folder_path = os.path.join(parent_folder, "TEST") + os.makedirs(test_folder_path, exist_ok=True) # HWP 파일 검색 및 변환 input_path = Path(input_folder) @@ -131,7 +134,7 @@ def delete_gen_py(): if __name__ == "__main__": exam_rounds = [ - "2504", + "2505", # "2504_3" ] @@ -147,7 +150,7 @@ if __name__ == "__main__": (f"C:\\Users\\dra\\project\\HWP\\HWP-Scoring\\input\\{exam_round}\\A\\DIW",f"C:\\Users\\dra\\project\\HWP\\HWP-Scoring\\output\\{exam_round}\\A\\DIW"), (f"C:\\Users\\dra\\project\\HWP\\HWP-Scoring\\input\\{exam_round}\\B\\DIW",f"C:\\Users\\dra\\project\\HWP\\HWP-Scoring\\output\\{exam_round}\\B\\DIW"), (f"C:\\Users\\dra\\project\\HWP\\HWP-Scoring\\input\\{exam_round}\\C\\DIW",f"C:\\Users\\dra\\project\\HWP\\HWP-Scoring\\output\\{exam_round}\\C\\DIW"), - # (f"C:\\Users\\dra\\project\\HWP\\HWP-Scoring\\input\\{exam_round}\\D\\DIW",f"C:\\Users\\dra\\project\\HWP\\HWP-Scoring\\output\\{exam_round}\\D\\DIW"), + (f"C:\\Users\\dra\\project\\HWP\\HWP-Scoring\\input\\{exam_round}\\D\\DIW",f"C:\\Users\\dra\\project\\HWP\\HWP-Scoring\\output\\{exam_round}\\D\\DIW"), # (f"C:\\Users\\dra\\project\\HWP\\HWP-Scoring\\input\\{exam_round}\\E\\DIW",f"C:\\Users\\dra\\project\\HWP\\HWP-Scoring\\output\\{exam_round}\\E\\DIW"), ] diff --git a/250526_DIW_2505회_A형_TEST.xlsx b/250526_DIW_2505회_A형_TEST.xlsx new file mode 100644 index 0000000..bb80e7a Binary files /dev/null and b/250526_DIW_2505회_A형_TEST.xlsx differ diff --git a/250526_DIW_2505회_B형_TEST.xlsx b/250526_DIW_2505회_B형_TEST.xlsx new file mode 100644 index 0000000..a393c31 Binary files /dev/null and b/250526_DIW_2505회_B형_TEST.xlsx differ diff --git a/250526_DIW_2505회_C형_TEST.xlsx b/250526_DIW_2505회_C형_TEST.xlsx new file mode 100644 index 0000000..be780ff Binary files /dev/null and b/250526_DIW_2505회_C형_TEST.xlsx differ diff --git a/250526_DIW_2505회_D형_TEST.xlsx b/250526_DIW_2505회_D형_TEST.xlsx new file mode 100644 index 0000000..31db4e6 Binary files /dev/null and b/250526_DIW_2505회_D형_TEST.xlsx differ diff --git a/DIW_2504A.json b/DIW_2505A.json similarity index 76% rename from DIW_2504A.json rename to DIW_2505A.json index 0604868..2ad00b6 100644 --- a/DIW_2504A.json +++ b/DIW_2505A.json @@ -46,61 +46,61 @@ "1": { "1": { "path": "//TEXTART[@Text='{searchValue}']/TEXTARTSHAPE/@FontName", - "searchValue": "클라우드컴퓨팅컨퍼런스", + "searchValue": "천혜의비경철쭉", "value": "맑은 고딕", "points": 1, "category": "OneAnswer", - "item": "문구 (클라우드컴퓨팅컨퍼런스)/① 글씨체 (맑은 고딕)" + "item": "문구 (천혜의비경철쭉)/① 글씨체 (맑은 고딕)" }, "2": { "path": "//TEXTART[@Text='{searchValue}']/descendant::WINDOWBRUSH/@FaceColor", - "searchValue": "클라우드컴퓨팅컨퍼런스", + "searchValue": "천혜의비경철쭉", "value": "28,61,98", "points": 2, "category": "Color", - "item": "문구 (클라우드컴퓨팅컨퍼런스)/② 채우기 : 색상(RGB:100,170,92)" + "item": "문구 (천혜의비경철쭉)/② 채우기 : 색상(RGB:100,170,92)" }, "3": { "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Width", - "searchValue": "클라우드컴퓨팅컨퍼런스", + "searchValue": "천혜의비경철쭉", "value": "110", "tolerance": 1, "points": 2, "category": "mmSize", - "item": "문구 (클라우드컴퓨팅컨퍼런스)/③ 크기-너비 (110mm)" + "item": "문구 (천혜의비경철쭉)/③ 크기-너비 (110mm)" }, "4": { "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Height", - "searchValue": "클라우드컴퓨팅컨퍼런스", + "searchValue": "천혜의비경철쭉", "value": "20", "tolerance": 1, "points": 2, "category": "mmSize", - "item": "문구 (클라우드컴퓨팅컨퍼런스)/④ 크기-높이 (20mm)" + "item": "문구 (천혜의비경철쭉)/④ 크기-높이 (20mm)" }, "5": { "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/POSITION/@TreatAsChar", - "searchValue": "클라우드컴퓨팅컨퍼런스", + "searchValue": "천혜의비경철쭉", "value": "true", "points": 2, "category": "OneAnswer", - "item": "문구 (클라우드컴퓨팅컨퍼런스)/⑤ 위치 (글자처럼 취급)" + "item": "문구 (천혜의비경철쭉)/⑤ 위치 (글자처럼 취급)" }, "6": { "path":"//PARASHAPE[@Id=//P[.//TEXTART[@Text='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "클라우드컴퓨팅컨퍼런스", + "searchValue": "천혜의비경철쭉", "value": "Center", "points": 2, "category": "OneAnswer", - "item": "문구 (클라우드컴퓨팅컨퍼런스)/⑥ 정렬 (가운데 정렬)" + "item": "문구 (천혜의비경철쭉)/⑥ 정렬 (가운데 정렬)" }, "7": { "path": "//TEXTART[@Text='{searchValue}']", - "searchValue": "클라우드컴퓨팅컨퍼런스", + "searchValue": "천혜의비경철쭉", "value": true, "points": 2, "category": "Boolean", - "item": "문구 (클라우드컴퓨팅컨퍼런스)/⑦ 글맵시모양 (육안확인)" + "item": "문구 (천혜의비경철쭉)/⑦ 글맵시모양 (육안확인)" }, "8": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/SIZE", @@ -141,19 +141,19 @@ }, "12": { "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]", - "searchValue": "글로벌 클라우드 컴퓨팅 컨퍼런스", + "searchValue": "바래봉 해발 약 500m에서 시작해 점점 정상으로", "value": "BOLD", "points": 2, "category": "FontAttribute", - "item": "문구 (글로벌 클라우드 컴퓨팅 컨퍼런스)/① 진하게" + "item": "문구 (바래봉 해발 약 500m에서 시작해 점점 정상으로)/① 진하게" }, "13": { "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]", - "searchValue": "글로벌 클라우드 컴퓨팅 컨퍼런스", - "value": "UNDERLINE", + "searchValue": "바래봉 해발 약 500m에서 시작해 점점 정상으로", + "value": "ITALIC", "points": 2, "category": "FontAttribute", - "item": "문구 (글로벌 클라우드 컴퓨팅 컨퍼런스)/② 밑줄" + "item": "문구 (바래봉 해발 약 500m에서 시작해 점점 정상으로)/② 기울임" }, "14": { "path": "//CHAR[contains(text(),'{char1}')]", @@ -215,44 +215,44 @@ }, "20": { "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]/@Height", - "searchValue": "2025. 04. 26.", + "searchValue": "2025. 05. 24.", "value": "1400", "points": 1, "category": "OneAnswer", - "item": "문구 (2025. 04. 26.)/① 크기 (14pt)", + "item": "문구 (2025. 05. 24.)/① 크기 (14pt)", "desc": "1pt당 100" }, "21": { "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/@ParaShape]/@Align", - "searchValue": "2025. 04. 26.", + "searchValue": "2025. 05. 24.", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (2025. 04. 26.)/② 정렬 (가운데 정렬)" + "item": "문구 (2025. 05. 24.)/② 정렬 (가운데 정렬)" }, "22": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "글로벌멀티클라우드협의회", + "searchValue": "운봉바래봉철쭉제", "value": "궁서체", "points": 1, "category": "FontName", - "item": "문구 (글로벌멀티클라우드협의회)/① 글씨체 (궁서체)" + "item": "문구 (운봉바래봉철쭉제)/① 글씨체 (궁서체)" }, "23": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "글로벌멀티클라우드협의회", + "searchValue": "운봉바래봉철쭉제", "value": "2600", "points": 1, "category": "OneAnswer", - "item": "문구 (글로벌멀티클라우드협의회)/② 크기 (26pt)" + "item": "문구 (운봉바래봉철쭉제)/② 크기 (26pt)" }, "24": { "path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/ancestor::P/@ParaShape]/@Align", - "searchValue": "글로벌멀티클라우드협의회", + "searchValue": "운봉바래봉철쭉제", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (글로벌멀티클라우드협의회)/③ 정렬 (가운데 정렬)" + "item": "문구 (운봉바래봉철쭉제)/③ 정렬 (가운데 정렬)" }, "25": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", @@ -349,87 +349,87 @@ }, "4": { "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width", - "searchValue": "클라우드 컴퓨팅", - "value": "60", + "searchValue": "철쭉과 진달래", + "value": "50", "points": 2, "category": "mmSize", - "item": "문구 (클라우드 컴퓨팅)/① 크기-너비 (60mm)" + "item": "문구 (철쭉과 진달래)/① 크기-너비 (50 mm)" }, "5": { "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Height", - "searchValue": "클라우드 컴퓨팅", + "searchValue": "철쭉과 진달래", "value": "12", "points": 2, "category": "mmSize", - "item": "문구 (클라우드 컴퓨팅)/② 크기-높이 (12mm)" + "item": "문구 (철쭉과 진달래)/② 크기-높이 (12 mm)" }, "6": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE/@Style", "path2": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE/@Width", - "searchValue": "클라우드 컴퓨팅", + "searchValue": "철쭉과 진달래", "value": [ "DoubleSlim", "283" ], "points": 2, "category": "DoubleAnswer", - "item": "문구 (클라우드 컴퓨팅)/③ 테두리 : 이중 실선(1.00mm)", + "item": "문구 (철쭉과 진달래)/③ 테두리 : 이중 실선(1.00mm)", "desc": "1mm = 283pt" }, "7": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/@Ratio", - "searchValue": "클라우드 컴퓨팅", - "value": "50", + "searchValue": "철쭉과 진달래", + "value": "20", "points": 2, "category": "OneAnswer", - "item": "문구 (클라우드 컴퓨팅)/④ 글상자 모서리 (반원)", + "item": "문구 (철쭉과 진달래)/④ 글상자 모서리 (둥근모양)", "desc": "모서리 비율 50이면 반원 / 20이면 둥근모양" }, "8": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "클라우드 컴퓨팅", - "value": "202,86,167", + "searchValue": "철쭉과 진달래", + "value": "225,15,161", "points": 2, "category": "Color", - "item": "문구 (클라우드 컴퓨팅)/⑤ 채우기 : 색상(RGB:202,86,167)" + "item": "문구 (철쭉과 진달래)/⑤ 채우기 : 색상(RGB:225,15,161)" }, "9": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/POSITION/@TreatAsChar", - "searchValue": "클라우드 컴퓨팅", + "searchValue": "철쭉과 진달래", "value": "true", "points": 1, "category": "OneAnswer", - "item": "문구 (클라우드 컴퓨팅)/⑥ 글상자 위치 (글자처럼 취급)" + "item": "문구 (철쭉과 진달래)/⑥ 글상자 위치 (글자처럼 취급)" }, "10": { "path": "//PARASHAPE[@Id=//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::P[last()]/@ParaShape]/@Align", - "searchValue": "클라우드 컴퓨팅", + "searchValue": "철쭉과 진달래", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (클라우드 컴퓨팅)/⑦ 글상자 정렬 (가운데 정렬)" + "item": "문구 (철쭉과 진달래)/⑦ 글상자 정렬 (가운데 정렬)" }, "11": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "클라우드 컴퓨팅", - "value": "견고딕", + "searchValue": "철쭉과 진달래", + "value": "맑은고딕", "points": 1, "category": "FontName", - "item": "문구 (클라우드 컴퓨팅)/⑧ 글씨체 (견고딕)" + "item": "문구 (철쭉과 진달래)/⑧ 글씨체 (맑은고딕)" }, "12": { "path": "//CHARSHAPE[@Id=//RECTANGLE//TEXT[./CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "클라우드 컴퓨팅", - "value": "2000", + "searchValue": "철쭉과 진달래", + "value": "1800", "points": 1, "category": "OneAnswer", - "item": "문구 (클라우드 컴퓨팅)/⑨ 글씨크기 (20pt)", + "item": "문구 (철쭉과 진달래)/⑨ 글씨크기 (18 pt)", "desc":"1pt당 100" }, "13": { "path": "//PARASHAPE[@Id=//RECTANGLE//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "클라우드 컴퓨팅", + "searchValue": "철쭉과 진달래", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (클라우드 컴퓨팅)/⑩ 정렬 (가운데 정렬)" + "item": "문구 (철쭉과 진달래)/⑩ 정렬 (가운데 정렬)" }, "14": { "path": "boolean(//PICTURE//SHAPECOMMENT[contains(text(),'{searchValue}')])", @@ -441,17 +441,17 @@ }, "15": { "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/SIZE/@Width", - "value": "80", + "value": "85", "points": 2, "category": "mmSize", - "item": "② 크기-너비 (80 mm)" + "item": "② 크기-너비 (85 mm)" }, "16": { "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/SIZE/@Height", - "value": "45", + "value": "40", "points": 2, "category": "mmSize", - "item": "③ 크기-높이 (45 mm)" + "item": "③ 크기-높이 (40 mm)" }, "17": { "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/POSITION/@HorzOffset", @@ -462,91 +462,91 @@ }, "18": { "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/POSITION/@VertOffset", - "value": "24", + "value": "23", "points": 2, "category": "mmSize", - "item": "⑤ 위치 (어울림 : 세로-쪽의 위 24mm)" + "item": "⑤ 위치 (어울림 : 세로-쪽의 위 23 mm)" }, "19": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "1. 주목하는 최신 트렌드", + "searchValue": "1. 철쭉의 특징", "value": "굴림", "points": 1, "category": "FontName", - "item": "문구① (1. 주목하는 최신 트렌드)/① 글씨체 (굴림)" + "item": "문구① (1. 철쭉의 특징)/① 글씨체 (굴림)" }, "20": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "1. 주목하는 최신 트렌드", + "searchValue": "1. 철쭉의 특징", "value": "1200", "points": 1, "category": "OneAnswer", - "item": "문구① (1. 주목하는 최신 트렌드)/② 크기 (12pt)" + "item": "문구① (1. 철쭉의 특징)/② 크기 (12pt)" }, "21": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", - "searchValue": "1. 주목하는 최신 트렌드", + "searchValue": "1. 철쭉의 특징", "value": "BOLD", "points": 1, "category": "FontAttribute", - "item": "문구① (1. 주목하는 최신 트렌드)/③ 진하게" + "item": "문구① (1. 철쭉의 특징)/③ 진하게" }, "22": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "2. 기술의 경제적 가치", + "searchValue": "2. 봄의 전령 진달래", "value": "굴림", "points": 1, "category": "FontName", - "item": "문구② (2. 기술의 경제적 가치)/① 글씨체 (굴림)" + "item": "문구② (2. 봄의 전령 진달래)/① 글씨체 (굴림)" }, "23": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "2. 기술의 경제적 가치", + "searchValue": "2. 봄의 전령 진달래", "value": "1200", "points": 1, "category": "OneAnswer", - "item": "문구② (2. 기술의 경제적 가치)/② 크기 (12pt)" + "item": "문구② (2. 봄의 전령 진달래)/② 크기 (12pt)" }, "24": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", - "searchValue": "2. 기술의 경제적 가치", + "searchValue": "2. 봄의 전령 진달래", "value": "BOLD", "points": 1, "category": "FontAttribute", - "item": "문구② (2. 기술의 경제적 가치)/③ 진하게" + "item": "문구② (2. 봄의 전령 진달래)/③ 진하게" }, "25": { "path": "boolean(//TEXT[CHAR[contains(text(),'{option}')]]/FOOTNOTE)", "path2": "boolean(//CHAR[substring(., string-length(.) - string-length('{option}') + 1) = '{option}']/following-sibling::FOOTNOTE/descendant::CHAR)", - "option": "클라우드", + "option": "거름", "value": true, "points": 2, "category": "Boolean", - "item": "문구 (클라우드)/① 각주 설정 및 문구 입력" + "item": "문구 (거름)/① 각주 설정 및 문구 입력" }, "26": { "path": "//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape", - "searchValue": "인터넷을 통해 액세스할 수 있는 가상화된 서버에서 실행되는 프로그램과 데이터베이스를 제공하는 환경", - "value": "중고딕", + "searchValue": "땅을 기름지게 하는데 사용되는 유기물질", + "value": "궁서", "points": 1, "category": "FontName", - "item": "문구 (클라우드)/② 글씨체 (중고딕)" + "item": "문구 (거름)/② 글씨체 (궁서)" }, "27": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[contains(text(),'{searchValue}')]]/@CharShape]/@Height", - "searchValue": "인터넷을 통해 액세스할 수 있는 가상화된 서버에서 실행되는 프로그램과 데이터베이스를 제공하는 환경", + "searchValue": "땅을 기름지게 하는데 사용되는 유기물질", "value": "900", "points": 1, "category": "OneAnswer", - "item": "문구 (클라우드)/③ 크기 (9pt)" + "item": "문구 (거름)/③ 크기 (9pt)" }, "28": { "path": "//P[TEXT[CHAR[contains(text(), '{searchValue}')]]]//AUTONUMFORMAT/@Type", - "searchValue": "인터넷을 통해 액세스할 수 있는 가상화된 서버에서 실행되는 프로그램과 데이터베이스를 제공하는 환경", + "searchValue": "땅을 기름지게 하는데 사용되는 유기물질", "value": "Ideograph", "points": 2, "category": "OneAnswer", - "item": "문구 (클라우드)/④ 각주 번호모양", + "item": "문구 (거름)/④ 각주 번호모양", "desc": { "가,나,다":"HangulSyllable", "1,2,3":"Digit", @@ -561,81 +561,81 @@ } }, "29": { - "path": "boolean(//CHAR[contains(text(),'Digital')])", - "ignoreWord": "Digital", + "path": "boolean(//CHAR[contains(text(),'Breeding')])", + "ignoreWord": "Breeding", "value": true, "points": 3, "category": "Boolean", - "item": "Digital/영단어 미입력, 대소문자/오타 시 전체 감점", + "item": "Breeding/영단어 미입력, 대소문자/오타 시 전체 감점", "desc": "유사도 검사를 진행하지 않고 영단어가 모두 일치해야 하므로 xpath구문 내 단어도 수정필요" }, "30": { "path": "//CHAR[contains(text(),'{kor}')][contains(text(),'{chn}')]", "word":[ - ["전환", "轉換"], - ["핵심", "核心"], - ["확산", "擴散"], - ["보안", "保安"], - ["도입", "導入"] + ["생육", "生育"], + ["유년", "幼年"], + ["허기", "虛飢"], + ["풍류", "風流"], + ["식물", "植物"] ], "value": 10, "points": 10, "category": "Hanja", - "item": "① 전환(轉換), ② 핵심(核心), ③ 확산(擴散), ④ 보안(保安), ⑤ 도입(導入)" + "item": "① 생육(生育), ② 유년(幼年), ③ 허기(虛飢), ④ 풍류(風流), ⑤ 식물(植物)" }, "31": { - "path": "boolean(//CHAR[contains(translate(text(), ' ', ''),'션이발전')])", + "path": "boolean(//CHAR[contains(translate(text(), ' ', ''),'지를잘라')])", "value": true, "points": 3, "category": "Boolean", - "item": "문구 (…보안(保安) 솔루션은 발전하면서…)/\"은\" → \"이\" 글자바꿈" + "item": "문구 (…새로 나온 가지가 잘라…) 가 → 를 글자바꿈" }, "32": { - "path": "boolean(//CHAR[contains(translate(text(), ' ', ''),'이터유출')])", + "path": "boolean(//CHAR[contains(translate(text(), ' ', ''),'보다참꽃')])", "value": true, "points": 3, "category": "Boolean", - "item": "문구 (…유출과 데이터 사이버…)/\"유출과\" / \"데이터\" 순서바꿈" + "item": "문구 (…참꽃나무란 진달래보다 이름에 더…) 참꽃나무란 / 진달래보다 순서바꿈" }, "33": { "path": "//TEXT[CHAR[contains(text(),'{searchValue}')]]/@CharShape", - "searchValue": "클라우드 보안(단위: 백만 달러)", + "searchValue": "철쭉 관광객 현황(단위 : 천 명)", "value": "돋움", "points": 1, "category": "FontName", - "item": "제목 문구 (클라우드 보안(단위: 백만 달러))/① 글씨체 (돋움)" + "item": "제목 문구 (철쭉 관광객 현황(단위 : 천 명))/① 글씨체 (돋움)" }, "34": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "클라우드 보안(단위: 백만 달러)", + "searchValue": "철쭉 관광객 현황(단위 : 천 명)", "value": "1200", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (클라우드 보안(단위: 백만 달러))/② 크기 (12pt)" + "item": "제목 문구 (철쭉 관광객 현황(단위 : 천 명))/② 크기 (12pt)" }, "35": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", - "searchValue": "클라우드 보안(단위: 백만 달러)", + "searchValue": "철쭉 관광객 현황(단위 : 천 명)", "value": "BOLD", "points": 1, "category": "FontAttribute", - "item": "제목 문구 (클라우드 보안(단위: 백만 달러))/③ 진하게" + "item": "제목 문구 (철쭉 관광객 현황(단위 : 천 명))/③ 진하게" }, "36": { "path": "//PARASHAPE[@Id=//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "클라우드 보안(단위: 백만 달러)", + "searchValue": "철쭉 관광객 현황(단위 : 천 명)", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (클라우드 보안(단위: 백만 달러))/④ 정렬 (가운데 정렬)" + "item": "제목 문구 (철쭉 관광객 현황(단위 : 천 명))/④ 정렬 (가운데 정렬)" }, "37": { "path": "//BORDERFILL[@Id=//TABLE/ROW[1]/CELL/@BorderFill]/FILLBRUSH/WINDOWBRUSH/@FaceColor", "path2": "//BORDERFILL[@Id=//CELLZONE[@StartRowAddr='0' and @EndRowAddr='0' and @StartColAddr='0' and @EndColAddr=(ancestor::TABLE[1]/@ColCount)-1]/@BorderFill]/FILLBRUSH/WINDOWBRUSH/@FaceColor", - "value": "233,174,43", + "value": "140,249,62", "points": 2, "category": "Color", - "item": "위쪽 제목 셀/① 색상(RGB:233,174,43)" + "item": "위쪽 제목 셀/① 색상(RGB:140,249,62)" }, "38": { "path": "//CHARSHAPE[@Id=//TABLE/ROW[1]/descendant::TEXT/@CharShape]", @@ -687,7 +687,7 @@ }, "44": { "path": "boolean(//TABLE[1]/ROW[last()]/CELL[position()=last()]//FIELDBEGIN[starts-with(@Command, '={option}')]) and boolean(//TABLE[1]/ROW[last()]/CELL[position()=last()-1]//FIELDBEGIN[starts-with(@Command, '={option}')])", - "option": "SUM", + "option": "AVG", "value": true, "points": 4, "category": "Boolean", @@ -696,11 +696,11 @@ }, "45": { "chart_xpath": "", - "chart_type": "묶은세로막대형", + "chart_type": "누적세로막대형", "value": true, "points": 2, "category": "ChartType", - "item": "① 종류 (묶은 세로 막대형)", + "item": "① 종류 (누적세로막대형)", "desc": "chart_type을 입력받아 차트타입에 맞는 xml요소가 있는지 내부적으로 검사, chart_type만 한글로 입력해주면 된다. (공백무시)" }, "46": { @@ -735,28 +735,28 @@ }, "50": { "chart_xpath": "//a:t[text()='{searchValue}']/ancestor::a:r//a:ea/@typeface", - "searchValue": "클라우드 보안 투자", + "searchValue": "철쭉 관광객 현황", "value": "굴림", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (클라우드 보안 투자)/① 글씨체 (굴림)" + "item": "제목 문구 (철쭉 관광객 현황)/① 글씨체 (굴림)" }, "51": { "chart_xpath": "//a:t[text()='{searchValue}']/ancestor::a:r/a:rPr/@sz", - "searchValue": "클라우드 보안 투자", + "searchValue": "철쭉 관광객 현황", "value": "1300", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (클라우드 보안 투자)/② 크기 (13pt)" + "item": "제목 문구 (철쭉 관광객 현황)/② 크기 (13pt)" }, "52": { "chart_xpath": "//a:t[text()='{searchValue}']/ancestor::a:r/a:rPr/@{option}", "option": "b", - "searchValue": "클라우드 보안 투자", + "searchValue": "철쭉 관광객 현황", "value": "1", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (클라우드 보안 투자)/③ 진하게", + "item": "제목 문구 (철쭉 관광객 현황)/③ 진하게", "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" }, "53": { diff --git a/DIW_2504B.json b/DIW_2505B.json similarity index 72% rename from DIW_2504B.json rename to DIW_2505B.json index 2ac1a76..5a7444c 100644 --- a/DIW_2504B.json +++ b/DIW_2505B.json @@ -46,65 +46,65 @@ "1": { "1": { "path": "//TEXTART[@Text='{searchValue}']/TEXTARTSHAPE/@FontName", - "searchValue": "친환경에너지박람회", - "value": "궁서체", + "searchValue": "광양매실축제안내", + "value": "맑은 고딕", "points": 1, "category": "OneAnswer", - "item": "문구 (친환경에너지박람회)/① 글씨체 (궁서체)" + "item": "문구 (광양매실축제안내)/① 글씨체 (맑은 고딕)" }, "2": { "path": "//TEXTART[@Text='{searchValue}']/descendant::WINDOWBRUSH/@FaceColor", - "searchValue": "친환경에너지박람회", - "value": "199,82,82", + "searchValue": "광양매실축제안내", + "value": "199,80,124", "points": 2, "category": "Color", - "item": "문구 (친환경에너지박람회)/② 채우기 : 색상(RGB:199,82,82)" + "item": "문구 (광양매실축제안내)/② 채우기 : 색상(RGB:199,82,82)" }, "3": { "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Width", - "searchValue": "친환경에너지박람회", - "value": "110", + "searchValue": "광양매실축제안내", + "value": "100", "tolerance": 1, "points": 2, "category": "mmSize", - "item": "문구 (친환경에너지박람회)/③ 크기-너비 (110mm)" + "item": "문구 (광양매실축제안내)/③ 크기-너비 (100mm)" }, "4": { "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Height", - "searchValue": "친환경에너지박람회", + "searchValue": "광양매실축제안내", "value": "20", "tolerance": 1, "points": 2, "category": "mmSize", - "item": "문구 (친환경에너지박람회)/④ 크기-높이 (20mm)" + "item": "문구 (광양매실축제안내)/④ 크기-높이 (20 mm)" }, "5": { "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/POSITION/@TreatAsChar", - "searchValue": "친환경에너지박람회", + "searchValue": "광양매실축제안내", "value": "true", "points": 2, "category": "OneAnswer", - "item": "문구 (친환경에너지박람회)/⑤ 위치 (글자처럼 취급)" + "item": "문구 (광양매실축제안내)/⑤ 위치 (글자처럼 취급)" }, "6": { "path":"//PARASHAPE[@Id=//P[.//TEXTART[@Text='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "친환경에너지박람회", + "searchValue": "광양매실축제안내", "value": "Center", "points": 2, "category": "OneAnswer", - "item": "문구 (친환경에너지박람회)/⑥ 정렬 (가운데 정렬)" + "item": "문구 (광양매실축제안내)/⑥ 정렬 (가운데 정렬)" }, "7": { "path": "//TEXTART[@Text='{searchValue}']", - "searchValue": "친환경에너지박람회", + "searchValue": "광양매실축제안내", "value": true, "points": 2, "category": "Boolean", - "item": "문구 (친환경에너지박람회)/⑦ 글맵시모양 (육안확인)" + "item": "문구 (광양매실축제안내)/⑦ 글맵시모양 (육안확인)" }, "8": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/SIZE", - "searchValue": "지", + "searchValue": "올", "value": { "Height": 2800, "Width": 2800 @@ -112,147 +112,147 @@ "tolerance": 200, "points": 1, "category": "TwoLineSize", - "item": "지/① 모양 (2줄)" + "item": "올/① 모양 (2줄)" }, "9": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "지", - "value": "궁서", + "searchValue": "올", + "value": "궁서체", "points": 1, "category": "FontName", - "item": "지/② 글씨체 (궁서)" + "item": "올/② 글씨체 (궁서체)" }, "10": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "지", - "value": "58,220,255", + "searchValue": "올", + "value": "186,255,26", "points": 2, "category": "Color", - "item": "지/③ 면색 : 색상(RGB:58,220,255)" + "item": "올/③ 면색 : 색상(RGB:186,255,26)" }, "11": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//OUTSIDEMARGIN/@Right", - "searchValue": "지", + "searchValue": "올", "value": "3.0", "tolerance": 1, "points": 2, "category": "mmSize", - "item": "지/④ 본문과의 간격 : 3.0mm" + "item": "올/④ 본문과의 간격 : 3.0mm" }, "12": { "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]", - "searchValue": "태양광, 풍력, 수소에너지 등 신재생 에너지 기술", - "value": "BOLD", + "searchValue": "봄 매화, 여름 매실로 우리 함께 힐링합시다!", + "value": "ITALIC", "points": 2, "category": "FontAttribute", - "item": "문구 (태양광, 풍력, 수소에너지 등 신재생 에너지 기술)/① 진하게" + "item": "문구 (봄 매화, 여름 매실로 우리 함께 힐링합시다!)/① 기울임" }, "13": { "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]", - "searchValue": "태양광, 풍력, 수소에너지 등 신재생 에너지 기술", - "value": "UNDERLINE", + "searchValue": "봄 매화, 여름 매실로 우리 함께 힐링합시다!", + "value": "ITALIC", "points": 2, "category": "FontAttribute", - "item": "문구 (태양광, 풍력, 수소에너지 등 신재생 에너지 기술)/② 밑줄" + "item": "문구 (봄 매화, 여름 매실로 우리 함께 힐링합시다!)/② 기울임" }, "14": { "path": "//CHAR[contains(text(),'{char1}')]", "path2": "//CHAR[contains(text(),'{char2}')]", "path3": "//CHAR[contains(text(),'{char3}')]", - "char1": "▶", - "char2": "◀", + "char1": "→", + "char2": "←", "char3": "※", "value": 3, "points": 3, "category": "SpecialChar", - "item": "① ▶, ② ◀, ③ ※" + "item": "① → , ② ← , ③ ※" }, "15": { "path": "//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape", - "searchValue": "행사안내", - "value": "중고딕", + "searchValue": "축제안내", + "value": "굴림체", "points": 1, "category": "FontName", - "item": "문구 (▶ 행사안내 ◀)/① 글씨체 (중고딕)" + "item": "문구 (→ 축제안내 ←)/① 글씨체 (굴림체)" }, "16": { "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/@ParaShape]/@Align", - "searchValue": "행사안내", + "searchValue": "축제안내", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (▶ 행사안내 ◀)/② 정렬 (가운데 정렬)" + "item": "문구 (→ 축제안내 ←)/② 정렬 (가운데 정렬)" }, "17": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", "hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]", - "searchValue": "블로그(http://www.ihd.or.kr) 참조하여 온라인으로 등록", + "searchValue": "광양매실축제 홈페이지(http://www.ihd.or.kr)", "value": "BOLD", "points": 1, "category": "FontAttribute", - "item": "문구 (블로그(http://www.ihd.or.kr) 참조하여 온라인으로 등록)/① 진하게" + "item": "문구 (광양매실축제 홈페이지(http://www.ihd.or.kr))/① 진하게" }, "18": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", "hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]", - "searchValue": "블로그(http://www.ihd.or.kr) 참조하여 온라인으로 등록", + "searchValue": "광양매실축제 홈페이지(http://www.ihd.or.kr)", "value": "ITALIC", "points": 1, "category": "FontAttribute", - "item": "문구 (블로그(http://www.ihd.or.kr) 참조하여 온라인으로 등록)/② 기울임" + "item": "문구 (광양매실축제 홈페이지(http://www.ihd.or.kr))/② 기울임" }, "19": { "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/following-sibling::P[1]/@ParaShape]/PARAMARGIN", "searchValue": "기타사항", "value": { - "Left": 10, + "Left": 15, "Indent": 12 }, "points": 2, "category": "ParaShape", - "item": "문구 (※ 기타… 이하 문단)/왼쪽여백 (10pt), 내어쓰기 (12pt)", + "item": "문구 (※ 기타… 이하 문단)/왼쪽여백 (15pt), 내어쓰기 (12pt)", "desc": "내부적으로 내어쓰기는 음수값 / JSON value값은 양수로 입력" }, "20": { "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]/@Height", - "searchValue": "2025. 04. 26.", - "value": "1300", + "searchValue": "2025. 05. 24.", + "value": "1400", "points": 1, "category": "OneAnswer", - "item": "문구 (2025. 04. 26.)/① 크기 (14pt)", + "item": "문구 (2025. 05. 24.)/① 크기 (14pt)", "desc": "1pt당 100" }, "21": { "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/@ParaShape]/@Align", - "searchValue": "2025. 04. 26.", + "searchValue": "2025. 05. 24.", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (2025. 04. 26.)/② 정렬 (가운데 정렬)" + "item": "문구 (2025. 05. 24.)/② 정렬 (가운데 정렬)" }, "22": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "친환경에너지발전협의회", - "value": "돋움", + "searchValue": "광양매실축제위원회", + "value": "견고딕", "points": 1, "category": "FontName", - "item": "문구 (친환경에너지발전협의회)/① 글씨체 (돋움)" + "item": "문구 (광양매실축제위원회)/① 글씨체 (견고딕)" }, "23": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "친환경에너지발전협의회", - "value": "2700", + "searchValue": "광양매실축제위원회", + "value": "2600", "points": 1, "category": "OneAnswer", - "item": "문구 (친환경에너지발전협의회)/② 크기 (27pt)" + "item": "문구 (광양매실축제위원회)/② 크기 (26pt)" }, "24": { "path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/ancestor::P/@ParaShape]/@Align", - "searchValue": "친환경에너지발전협의회", + "searchValue": "광양매실축제위원회", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (친환경에너지발전협의회)/③ 정렬 (가운데 정렬)" + "item": "문구 (광양매실축제위원회)/③ 정렬 (가운데 정렬)" }, "25": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", @@ -280,16 +280,18 @@ }, "28": { "path": "//PAGENUM/@FormatType", - "value": "HangulSyllable", + "value": "CircledDigit", "points": 2, "category": "PageNumber", "item": "① 쪽 번호 매기기 (A,B,C 순으로)", "desc1": { - "가,나,다":"HangulSyllable", "1,2,3":"Digit", - "갑,을,병":"DecagonCircle", - "A,B,C":"LatinCapital", "①,②,③":"CircledDigit", + "가,나,다":"HangulSyllable", + "㉮,㉯,㉰":"CircledHangulSyllable", + "A,B,C":"LatinCapital", + "Ⓐ,Ⓑ,Ⓒ":"CircledLatinCapital", + "갑,을,병":"DecagonCircle", "一,二,三":"Ideograph", "㉠,㉡,㉢":"CircledHangulJamo", "ⓐ,ⓑ,ⓒ":"CircledLatinSmall", @@ -349,87 +351,87 @@ }, "4": { "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width", - "searchValue": "친환경 에너지", - "value": "50", + "searchValue": "매화와 매실", + "value": "55", "points": 2, "category": "mmSize", - "item": "문구 (친환경 에너지)/① 크기-너비 (50mm)" + "item": "문구 (매화와 매실)/① 크기-너비 (55 mm)" }, "5": { "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Height", - "searchValue": "친환경 에너지", + "searchValue": "매화와 매실", "value": "12", "points": 2, "category": "mmSize", - "item": "문구 (친환경 에너지)/② 크기-높이 (12mm)" + "item": "문구 (매화와 매실)/② 크기-높이 (12 mm)" }, "6": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE/@Style", "path2": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE/@Width", - "searchValue": "친환경 에너지", + "searchValue": "매화와 매실", "value": [ "DoubleSlim", "283" ], "points": 2, "category": "DoubleAnswer", - "item": "문구 (친환경 에너지)/③ 테두리 : 이중 실선(1.00mm)", + "item": "문구 (매화와 매실)/③ 테두리 : 이중 실선(1.00mm)", "desc": "1mm = 283pt" }, "7": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/@Ratio", - "searchValue": "친환경 에너지", + "searchValue": "매화와 매실", "value": "20", "points": 2, "category": "OneAnswer", - "item": "문구 (친환경 에너지)/④ 글상자 모서리 (둥근모양)", + "item": "문구 (매화와 매실)/④ 글상자 모서리 (둥근모양)", "desc": "모서리 비율 50이면 반원 / 20이면 둥근모양" }, "8": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "친환경 에너지", - "value": "53,135,145", + "searchValue": "매화와 매실", + "value": "122,179,64", "points": 2, "category": "Color", - "item": "문구 (친환경 에너지)/⑤ 채우기 : 색상(RGB:53,135,145)" + "item": "문구 (매화와 매실)/⑤ 채우기 : 색상(RGB:122,179,64)" }, "9": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/POSITION/@TreatAsChar", - "searchValue": "친환경 에너지", + "searchValue": "매화와 매실", "value": "true", "points": 1, "category": "OneAnswer", - "item": "문구 (친환경 에너지)/⑥ 글상자 위치 (글자처럼 취급)" + "item": "문구 (매화와 매실)/⑥ 글상자 위치 (글자처럼 취급)" }, "10": { "path": "//PARASHAPE[@Id=//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::P[last()]/@ParaShape]/@Align", - "searchValue": "친환경 에너지", + "searchValue": "매화와 매실", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (친환경 에너지)/⑦ 글상자 정렬 (가운데 정렬)" + "item": "문구 (매화와 매실)/⑦ 글상자 정렬 (가운데 정렬)" }, "11": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "친환경 에너지", - "value": "궁서체", + "searchValue": "매화와 매실", + "value": "중고딕", "points": 1, "category": "FontName", - "item": "문구 (친환경 에너지)/⑧ 글씨체 (궁서체)" + "item": "문구 (매화와 매실)/⑧ 글씨체 (중고딕)" }, "12": { "path": "//CHARSHAPE[@Id=//RECTANGLE//TEXT[./CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "친환경 에너지", + "searchValue": "매화와 매실", "value": "2000", "points": 1, "category": "OneAnswer", - "item": "문구 (친환경 에너지)/⑨ 글씨크기 (20pt)", + "item": "문구 (매화와 매실)/⑨ 글씨크기 (20 pt)", "desc":"1pt당 100" }, "13": { "path": "//PARASHAPE[@Id=//RECTANGLE//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "친환경 에너지", + "searchValue": "매화와 매실", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (친환경 에너지)/⑩ 정렬 (가운데 정렬)" + "item": "문구 (매화와 매실)/⑩ 정렬 (가운데 정렬)" }, "14": { "path": "boolean(//PICTURE//SHAPECOMMENT[contains(text(),'{searchValue}')])", @@ -467,92 +469,98 @@ "category": "mmSize", "item": "⑤ 위치 (어울림 : 세로-쪽의 위 24mm)" }, + "19": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "1. 친환경 에너지 개요", + "searchValue": "1. 매화의 특징", "value": "돋움", "points": 1, "category": "FontName", - "item": "문구① (1. 친환경 에너지 개요)/① 글씨체 (돋움)" + "item": "문구① (1. 매화의 특징)/① 글씨체 (돋움)" }, "20": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "1. 친환경 에너지 개요", + "searchValue": "1. 매화의 특징", "value": "1200", "points": 1, "category": "OneAnswer", - "item": "문구① (1. 친환경 에너지 개요)/② 크기 (12pt)" + "item": "문구① (1. 매화의 특징)/② 크기 (12pt)" }, "21": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", - "searchValue": "1. 친환경 에너지 개요", + "searchValue": "1. 매화의 특징", "value": "BOLD", "points": 1, "category": "FontAttribute", - "item": "문구① (1. 친환경 에너지 개요)/③ 진하게" + "item": "문구① (1. 매화의 특징)/③ 진하게" }, + "22": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "2. 신재생 에너지", + "searchValue": "2. 매실의 효능", "value": "돋움", "points": 1, "category": "FontName", - "item": "문구② (2. 신재생 에너지)/① 글씨체 (돋움)" + "item": "문구② (2. 매실의 효능)/① 글씨체 (돋움)" }, "23": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "2. 신재생 에너지", + "searchValue": "2. 매실의 효능", "value": "1200", "points": 1, "category": "OneAnswer", - "item": "문구② (2. 신재생 에너지)/② 크기 (12pt)" + "item": "문구② (2. 매실의 효능)/② 크기 (12pt)" }, "24": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", - "searchValue": "2. 신재생 에너지", + "searchValue": "2. 매실의 효능", "value": "BOLD", "points": 1, "category": "FontAttribute", - "item": "문구② (2. 신재생 에너지)/③ 진하게" + "item": "문구② (2. 매실의 효능)/③ 진하게" }, + "25": { "path": "boolean(//TEXT[CHAR[contains(text(),'{option}')]]/FOOTNOTE)", "path2": "boolean(//CHAR[substring(., string-length(.) - string-length('{option}') + 1) = '{option}']/following-sibling::FOOTNOTE/descendant::CHAR)", - "option": "태양전지", + "option": "문인화", "value": true, "points": 2, "category": "Boolean", - "item": "문구 (태양전지)/① 각주 설정 및 문구 입력" + "item": "문구 (문인화)/① 각주 설정 및 문구 입력" }, "26": { "path": "//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape", - "searchValue": "태양의 빛에너지를 전기에너지로 변환시켜 전기를 발생하는 장치로 친환경 방식으로 알려져 있음", - "value": "굴림", + "searchValue": "그림을 직업으로 하지 않는 선비나 사대부들이 여흥으로 자신들의 심중을 표현하여 그린 그림", + "value": "돋움체", "points": 1, "category": "FontName", - "item": "문구 (태양전지)/② 글씨체 (굴림)" + "item": "문구 (문인화)/② 글씨체 (돋움체)" }, "27": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[contains(text(),'{searchValue}')]]/@CharShape]/@Height", - "searchValue": "태양의 빛에너지를 전기에너지로 변환시켜 전기를 발생하는 장치로 친환경 방식으로 알려져 있음", + "searchValue": "그림을 직업으로 하지 않는 선비나 사대부들이 여흥으로 자신들의 심중을 표현하여 그린 그림", "value": "900", "points": 1, "category": "OneAnswer", - "item": "문구 (태양전지)/③ 크기 (9pt)" + "item": "문구 (문인화)/③ 크기 (9pt)" }, + "28": { "path": "//P[TEXT[CHAR[contains(text(), '{searchValue}')]]]//AUTONUMFORMAT/@Type", - "searchValue": "태양의 빛에너지를 전기에너지로 변환시켜 전기를 발생하는 장치로 친환경 방식으로 알려져 있음", - "value": "CircledHangulJamo", + "searchValue": "그림을 직업으로 하지 않는 선비나 사대부들이 여흥으로 자신들의 심중을 표현하여 그린 그림", + "value": "CircledHangulSyllable", "points": 2, "category": "OneAnswer", - "item": "문구 (태양전지)/④ 각주 번호모양", + "item": "문구 (문인화)/④ 각주 번호모양", "desc": { - "가,나,다":"HangulSyllable", "1,2,3":"Digit", - "갑,을,병":"DecagonCircle", - "A,B,C":"LatinCapital", "①,②,③":"CircledDigit", + "가,나,다":"HangulSyllable", + "㉮,㉯,㉰":"CircledHangulSyllable", + "A,B,C":"LatinCapital", + "Ⓐ,Ⓑ,Ⓒ":"CircledLatinCapital", + "갑,을,병":"DecagonCircle", "一,二,三":"Ideograph", "㉠,㉡,㉢":"CircledHangulJamo", "ⓐ,ⓑ,ⓒ":"CircledLatinSmall", @@ -560,82 +568,83 @@ "정답에 맞는 값 value에 입력":"" } }, + "29": { - "path": "boolean(//CHAR[contains(text(),'Campaign')])", - "ignoreWord": "Campaign", + "path": "boolean(//CHAR[contains(text(),'Vitamin')])", + "ignoreWord": "Vitamin", "value": true, "points": 3, "category": "Boolean", - "item": "Campaign/영단어 미입력, 대소문자/오타 시 전체 감점", + "item": "Vitamin/영단어 미입력, 대소문자/오타 시 전체 감점", "desc": "유사도 검사를 진행하지 않고 영단어가 모두 일치해야 하므로 xpath구문 내 단어도 수정필요" }, "30": { "path": "//CHAR[contains(text(),'{kor}')][contains(text(),'{chn}')]", "word":[ - ["저감", "低減"], - ["화석", "化石"], - ["투자", "投資"], - ["달성", "達成"], - ["세금", "稅金"] + ["매향", "梅香"], + ["불의", "不義"], + ["국화", "菊花"], + ["매실", "梅實"], + ["해독", "解讀"] ], "value": 10, "points": 10, "category": "Hanja", - "item": "① 저감(低減), ② 화석(化石), ③ 투자(投資), ④ 달성(達成), ⑤ 세금(稅金)" + "item": "① 매향(梅香), ② 불의(不義), ③ 국화(菊花), ④ 매실(梅實), ⑤ 해독(解讀)" }, "31": { - "path": "boolean(//CHAR[contains(translate(text(), ' ', ''),'택을제공')])", + "path": "boolean(//CHAR[contains(translate(text(), ' ', ''),'흰색,분홍')])", "value": true, "points": 3, "category": "Boolean", - "item": "문구 (…세금 혜택이 제공하고 있으며…)/\"이\" → \"을\" 글자바꿈" + "item": "문구 (청색, 분홍색, 붉은색 등 다양한 색을…)/청 → 흰 글자바꿈" }, "32": { - "path": "boolean(//CHAR[contains(translate(text(), ' ', ''),'탄소배출')])", + "path": "boolean(//CHAR[contains(translate(text(), ' ', ''),'킨과폴리')])", "value": true, "points": 3, "category": "Boolean", - "item": "문구 (…배출 탄소 규제가 강화되면서…)/\"배출\" / \"탄소\" 순서바꿈" + "item": "문구 (항산화 성분인 폴리페놀은 카테킨과 해독(解讀)과…)/ 폴리페놀은 / 카테킨과 순서바꿈" }, "33": { "path": "//TEXT[CHAR[contains(text(),'{searchValue}')]]/@CharShape", - "searchValue": "친환경 에너지 성장률(단위: %)", - "value": "돋움", + "searchValue": "광양매실축제 만족도(단위 : %)", + "value": "굴림체", "points": 1, "category": "FontName", - "item": "제목 문구 (친환경 에너지 성장률(단위: %))/① 글씨체 (돋움)" + "item": "제목 문구 (광양매실축제 만족도(단위 : %))/① 글씨체 (굴림체)" }, "34": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "친환경 에너지 성장률(단위: %)", + "searchValue": "광양매실축제 만족도(단위 : %)", "value": "1200", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (친환경 에너지 성장률(단위: %))/② 크기 (12pt)" + "item": "제목 문구 (광양매실축제 만족도(단위 : %))/② 크기 (12pt)" }, "35": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", - "searchValue": "친환경 에너지 성장률(단위: %)", + "searchValue": "광양매실축제 만족도(단위 : %)", "value": "BOLD", "points": 1, "category": "FontAttribute", - "item": "제목 문구 (친환경 에너지 성장률(단위: %))/③ 진하게" + "item": "제목 문구 (광양매실축제 만족도(단위 : %))/③ 진하게" }, "36": { "path": "//PARASHAPE[@Id=//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "친환경 에너지 성장률(단위: %)", + "searchValue": "광양매실축제 만족도(단위 : %)", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (친환경 에너지 성장률(단위: %))/④ 정렬 (가운데 정렬)" + "item": "제목 문구 (광양매실축제 만족도(단위 : %))/④ 정렬 (가운데 정렬)" }, "37": { "path": "//BORDERFILL[@Id=//TABLE/ROW[1]/CELL/@BorderFill]/FILLBRUSH/WINDOWBRUSH/@FaceColor", "path2": "//BORDERFILL[@Id=//CELLZONE[@StartRowAddr='0' and @EndRowAddr='0' and @StartColAddr='0' and @EndColAddr=(ancestor::TABLE[1]/@ColCount)-1]/@BorderFill]/FILLBRUSH/WINDOWBRUSH/@FaceColor", - "value": "202,86,167", + "value": "233,174,43", "points": 2, "category": "Color", - "item": "위쪽 제목 셀/① 색상(RGB:202,86,167)" + "item": "위쪽 제목 셀/① 색상(RGB:233,174,43)" }, "38": { "path": "//CHARSHAPE[@Id=//TABLE/ROW[1]/descendant::TEXT/@CharShape]", @@ -664,11 +673,11 @@ "41": { "path": "//TABLE//TEXT/@CharShape", "path2": "//FONTFACE[@Lang='Hangul']/FONT[@Id=//CHARSHAPE[@Id=//TABLE/ROW/descendant::TEXT/@CharShape]/FONTID/@Hangul]/@Name", - "value": "중고딕", + "value": "돋움", "points": 1, "category": "TableFontName", "category_tmp": "FontName", - "item": "글자모양/① 글씨체 (중고딕)", + "item": "글자모양/① 글씨체 (돋움)", "desc": "테이블 폰트명 문항은 테이블의 모든 셀이 정답폰트와 일치해야 함, 하나만 일치해도 정답으로 채점할 경우 category값을 FontName으로 변경" }, "42": { @@ -696,11 +705,11 @@ }, "45": { "chart_xpath": "", - "chart_type": "꺾은선형", + "chart_type": "묶은세로막대형", "value": true, "points": 2, "category": "ChartType", - "item": "① 종류 (꺾은선형)", + "item": "① 종류 (묶은세로막대형)", "desc": "chart_type을 입력받아 차트타입에 맞는 xml요소가 있는지 내부적으로 검사, chart_type만 한글로 입력해주면 된다. (공백무시)" }, "46": { @@ -720,10 +729,10 @@ }, "48": { "path": "//OLE[@BinItem=//BINITEM[@Format='OLE']/@BinData]//SIZE/@Height", - "value": "80", + "value": "90", "points": 2, "category": "mmSize", - "item": "④ 크기-높이 (80 mm)" + "item": "④ 크기-높이 (90 mm)" }, "49": { "chart_xpath": "boolean(//c:chart and not(//c:pt[not(ancestor::c:tx)]/c:v[text()='합계' or text()='평균']))", @@ -735,42 +744,42 @@ }, "50": { "chart_xpath": "//a:t[text()='{searchValue}']/ancestor::a:r//a:ea/@typeface", - "searchValue": "친환경 에너지 성장률", + "searchValue": "광양매실축제 만족도", "value": "궁서체", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (친환경 에너지 성장률)/① 글씨체 (궁서체)" + "item": "제목 문구 (광양매실축제 만족도)/① 글씨체 (궁서체)" }, "51": { "chart_xpath": "//a:t[text()='{searchValue}']/ancestor::a:r/a:rPr/@sz", - "searchValue": "친환경 에너지 성장률", + "searchValue": "광양매실축제 만족도", "value": "1300", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (친환경 에너지 성장률)/② 크기 (13pt)" + "item": "제목 문구 (광양매실축제 만족도)/② 크기 (13pt)" }, "52": { "chart_xpath": "//a:t[text()='{searchValue}']/ancestor::a:r/a:rPr/@{option}", "option": "b", - "searchValue": "친환경 에너지 성장률", + "searchValue": "광양매실축제 만족도", "value": "1", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (친환경 에너지 성장률)/③ 진하게", + "item": "제목 문구 (광양매실축제 만족도)/③ 진하게", "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" }, "53": { "chart_xpath": "//c:catAx/c:txPr//a:ea/@typeface", "value": "바탕", "points": 1, - "category": "OneAnswer", + "category": "ChartOneAnswer", "item": "X축/① 글꼴 (바탕)" }, "54": { "chart_xpath": "//c:catAx/c:txPr//a:defRPr/@sz", "value": "900", "points": 1, - "category": "OneAnswer", + "category": "ChartOneAnswer", "item": "X축/② 크기 (9pt)" }, "55": { @@ -778,7 +787,7 @@ "option": "i", "value": "1", "points": 1, - "category": "OneAnswer", + "category": "ChartOneAnswer", "item": "X축/③ 기울임", "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" }, @@ -786,14 +795,14 @@ "chart_xpath": "//c:valAx/c:txPr//a:ea/@typeface", "value": "바탕", "points": 1, - "category": "OneAnswer", + "category": "ChartOneAnswer", "item": "Y축/① 글꼴 (바탕)" }, "57": { "chart_xpath": "//c:valAx/c:txPr//a:defRPr/@sz", "value": "900", "points": 1, - "category": "OneAnswer", + "category": "ChartOneAnswer", "item": "Y축/② 크기 (9pt)" }, "58": { @@ -801,7 +810,7 @@ "option": "i", "value": "1", "points": 1, - "category": "OneAnswer", + "category": "ChartOneAnswer", "item": "Y축/③ 기울임", "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" }, diff --git a/DIW_2504C.json b/DIW_2505C.json similarity index 71% rename from DIW_2504C.json rename to DIW_2505C.json index 0cf3fff..fd15754 100644 --- a/DIW_2504C.json +++ b/DIW_2505C.json @@ -46,65 +46,65 @@ "1": { "1": { "path": "//TEXTART[@Text='{searchValue}']/TEXTARTSHAPE/@FontName", - "searchValue": "서울국제도서박람회", - "value": "돋움", + "searchValue": "별사랑천문대캠프안내", + "value": "궁서체", "points": 1, "category": "OneAnswer", - "item": "문구 (서울국제도서박람회)/① 글씨체 (돋움)" + "item": "문구 (별사랑천문대캠프안내)/① 글씨체 (궁서체)" }, "2": { "path": "//TEXTART[@Text='{searchValue}']/descendant::WINDOWBRUSH/@FaceColor", - "searchValue": "서울국제도서박람회", - "value": "28,61,98", + "searchValue": "별사랑천문대캠프안내", + "value": "53,164,78", "points": 2, "category": "Color", - "item": "문구 (서울국제도서박람회)/② 채우기 : 색상(RGB:100,170,92)" + "item": "문구 (별사랑천문대캠프안내)/② 채우기 : 색상(RGB:53,164,78)" }, "3": { "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Width", - "searchValue": "서울국제도서박람회", - "value": "100", + "searchValue": "별사랑천문대캠프안내", + "value": "120", "tolerance": 1, "points": 2, "category": "mmSize", - "item": "문구 (서울국제도서박람회)/③ 크기-너비 (100mm)" + "item": "문구 (별사랑천문대캠프안내)/③ 크기-너비 (120 mm)" }, "4": { "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Height", - "searchValue": "서울국제도서박람회", + "searchValue": "별사랑천문대캠프안내", "value": "20", "tolerance": 1, "points": 2, "category": "mmSize", - "item": "문구 (서울국제도서박람회)/④ 크기-높이 (20mm)" + "item": "문구 (별사랑천문대캠프안내)/④ 크기-높이 (20 mm)" }, "5": { "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/POSITION/@TreatAsChar", - "searchValue": "서울국제도서박람회", + "searchValue": "별사랑천문대캠프안내", "value": "true", "points": 2, "category": "OneAnswer", - "item": "문구 (서울국제도서박람회)/⑤ 위치 (글자처럼 취급)" + "item": "문구 (별사랑천문대캠프안내)/⑤ 위치 (글자처럼 취급)" }, "6": { "path":"//PARASHAPE[@Id=//P[.//TEXTART[@Text='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "서울국제도서박람회", + "searchValue": "별사랑천문대캠프안내", "value": "Center", "points": 2, "category": "OneAnswer", - "item": "문구 (서울국제도서박람회)/⑥ 정렬 (가운데 정렬)" + "item": "문구 (별사랑천문대캠프안내)/⑥ 정렬 (가운데 정렬)" }, "7": { "path": "//TEXTART[@Text='{searchValue}']", - "searchValue": "서울국제도서박람회", + "searchValue": "별사랑천문대캠프안내", "value": true, "points": 2, "category": "Boolean", - "item": "문구 (서울국제도서박람회)/⑦ 글맵시모양 (육안확인)" + "item": "문구 (별사랑천문대캠프안내)/⑦ 글맵시모양 (육안확인)" }, "8": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/SIZE", - "searchValue": "책", + "searchValue": "별", "value": { "Height": 2800, "Width": 2800 @@ -112,155 +112,155 @@ "tolerance": 200, "points": 1, "category": "TwoLineSize", - "item": "책/① 모양 (2줄)" + "item": "별/① 모양 (2줄)" }, "9": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "책", - "value": "돋움", + "searchValue": "별", + "value": "굴림체", "points": 1, "category": "FontName", - "item": "책/② 글씨체 (돋움)" + "item": "별/② 글씨체 (굴림체)" }, "10": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "책", - "value": "206,166,29", + "searchValue": "별", + "value": "211,202,24", "points": 2, "category": "Color", - "item": "책/③ 면색 : 색상(RGB:206,166,29)" + "item": "별/③ 면색 : 색상(RGB:211,202,24)" }, "11": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//OUTSIDEMARGIN/@Right", - "searchValue": "책", + "searchValue": "별", "value": "3.0", "tolerance": 1, "points": 2, "category": "mmSize", - "item": "책/④ 본문과의 간격 : 3.0mm" + "item": "별/④ 본문과의 간격 : 3.0mm" }, "12": { "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]", - "searchValue": "문학, 인문학, 어린이/청소년 도서, 전자책, 독립 출판", + "searchValue": "천문우주과학 체험학습", "value": "BOLD", "points": 2, "category": "FontAttribute", - "item": "문구 (문학, 인문학, 어린이/청소년 도서, 전자책, 독립 출판)/① 진하게" + "item": "문구 (천문우주과학 체험학습)/① 진하게" }, "13": { "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]", - "searchValue": "문학, 인문학, 어린이/청소년 도서, 전자책, 독립 출판", - "value": "ITALIC", + "searchValue": "천문우주과학 체험학습", + "value": "UNDERLINE", "points": 2, "category": "FontAttribute", - "item": "문구 (문학, 인문학, 어린이/청소년 도서, 전자책, 독립 출판)/② 기울임" + "item": "문구 (천문우주과학 체험학습)/② 밑줄" }, "14": { "path": "//CHAR[contains(text(),'{char1}')]", "path2": "//CHAR[contains(text(),'{char2}')]", "path3": "//CHAR[contains(text(),'{char3}')]", - "char1": "◆", - "char2": "◆", + "char1": "●", + "char2": "●", "char3": "※", "value": 3, "points": 3, "category": "SpecialChar", - "item": "① ◆, ② ◆, ③ ※" + "item": "① ● , ② ● , ③ ※" }, "15": { "path": "//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape", - "searchValue": "행사안내", - "value": "궁서", + "searchValue": "참가안내", + "value": "굴림", "points": 1, "category": "FontName", - "item": "문구 (◆ 행사안내 ◆)/① 글씨체 (궁서)" + "item": "문구 (● 참가안내 ●)/① 글씨체 (굴림)" }, "16": { "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/@ParaShape]/@Align", - "searchValue": "행사안내", + "searchValue": "참가안내", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (◆ 행사안내 ◆)/② 정렬 (가운데 정렬)" + "item": "문구 (● 참가안내 ●)/② 정렬 (가운데 정렬)" }, "17": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", "hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]", - "searchValue": "서울 국제 도서 박람회 홈페이지(http://www.ihd.or.kr) 참조", + "searchValue": "그룹별 20명(선착순 마감)", "value": "ITALIC", "points": 1, "category": "FontAttribute", - "item": "문구 (서울 국제 도서 박람회 홈페이지(http://www.ihd.or.kr) 참조)/① 기울임" + "item": "문구 (그룹별 20명(선착순 마감))/① 기울임" }, "18": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", "hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]", - "searchValue": "서울 국제 도서 박람회 홈페이지(http://www.ihd.or.kr) 참조", + "searchValue": "그룹별 20명(선착순 마감)", "value": "UNDERLINE", "points": 1, "category": "FontAttribute", - "item": "문구 (서울 국제 도서 박람회 홈페이지(http://www.ihd.or.kr) 참조)/② 밑줄" + "item": "문구 (그룹별 20명(선착순 마감))/② 밑줄" }, "19": { "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/following-sibling::P[1]/@ParaShape]/PARAMARGIN", "searchValue": "기타사항", "value": { "Left": 15, - "Indent": 12 + "Indent": 14 }, "points": 2, "category": "ParaShape", - "item": "문구 (※ 기타… 이하 문단)/왼쪽여백 (10pt), 내어쓰기 (12pt)", + "item": "문구 (※ 기타… 이하 문단)/왼쪽여백 (15pt), 내어쓰기 (14pt)", "desc": "내부적으로 내어쓰기는 음수값 / JSON value값은 양수로 입력" }, "20": { "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]/@Height", - "searchValue": "2025. 04. 26.", - "value": "1300", + "searchValue": "2025. 05. 24.", + "value": "1400", "points": 1, "category": "OneAnswer", - "item": "문구 (2025. 04. 26.)/① 크기 (14pt)", + "item": "문구 (2025. 05. 24.)/① 크기 (14pt)", "desc": "1pt당 100" }, "21": { "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/@ParaShape]/@Align", - "searchValue": "2025. 04. 26.", + "searchValue": "2025. 05. 24.", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (2025. 04. 26.)/② 정렬 (가운데 정렬)" + "item": "문구 (2025. 05. 24.)/② 정렬 (가운데 정렬)" }, "22": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "서울국제도서박람회", + "searchValue": "별사랑천문대", "value": "견고딕", "points": 1, "category": "FontName", - "item": "문구 (서울국제도서박람회)/① 글씨체 (견고딕)" + "item": "문구 (별사랑천문대)/① 글씨체 (견고딕)" }, "23": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "서울국제도서박람회", - "value": "2500", + "searchValue": "별사랑천문대", + "value": "2600", "points": 1, "category": "OneAnswer", - "item": "문구 (서울국제도서박람회)/② 크기 (25pt)" + "item": "문구 (별사랑천문대)/② 크기 (26pt)" }, "24": { "path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/ancestor::P/@ParaShape]/@Align", - "searchValue": "서울국제도서박람회", + "searchValue": "별사랑천문대", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (서울국제도서박람회)/③ 정렬 (가운데 정렬)" + "item": "문구 (별사랑천문대)/③ 정렬 (가운데 정렬)" }, "25": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", "searchValue": "DIAT", - "value": "중고딕", + "value": "돋움", "points": 1, "category": "FontName", - "item": "문구 (DIAT)/① 글꼴 (중고딕)" + "item": "문구 (DIAT)/① 글꼴 (돋움)" }, "26": { "path": "//CHARSHAPE[@Id=//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", @@ -280,16 +280,18 @@ }, "28": { "path": "//PAGENUM/@FormatType", - "value": "RomanSmall", + "value": "LatinCapital", "points": 2, "category": "PageNumber", "item": "① 쪽 번호 매기기 (A,B,C 순으로)", "desc1": { - "가,나,다":"HangulSyllable", "1,2,3":"Digit", - "갑,을,병":"DecagonCircle", - "A,B,C":"LatinCapital", "①,②,③":"CircledDigit", + "가,나,다":"HangulSyllable", + "㉮,㉯,㉰":"CircledHangulSyllable", + "A,B,C":"LatinCapital", + "Ⓐ,Ⓑ,Ⓒ":"CircledLatinCapital", + "갑,을,병":"DecagonCircle", "一,二,三":"Ideograph", "㉠,㉡,㉢":"CircledHangulJamo", "ⓐ,ⓑ,ⓒ":"CircledLatinSmall", @@ -300,7 +302,7 @@ }, "29": { "path": "//PAGENUM/@Pos", - "value": "BottomRight", + "value": "BottomCenter", "points": 2, "category": "PageNumber", "item": "가운데 아래", @@ -349,88 +351,87 @@ }, "4": { "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width", - "searchValue": "출판 산업 트렌드", - "value": "70", + "searchValue": "별자리", + "value": "60", "points": 2, "category": "mmSize", - "item": "문구 (출판 산업 트렌드)/① 크기-너비 (70mm)" + "item": "문구 (별자리)/① 크기-너비 (60 mm)" }, "5": { "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Height", - "searchValue": "출판 산업 트렌드", + "searchValue": "별자리", "value": "12", "points": 2, "category": "mmSize", - "item": "문구 (출판 산업 트렌드)/② 크기-높이 (12mm)" + "item": "문구 (별자리)/② 크기-높이 (12mm)" }, "6": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE/@Style", "path2": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE/@Width", - "searchValue": "출판 산업 트렌드", + "searchValue": "별자리", "value": [ "DoubleSlim", "283" ], "points": 2, "category": "DoubleAnswer", - "item": "문구 (출판 산업 트렌드)/③ 테두리 : 이중 실선(1.00mm)", + "item": "문구 (별자리)/③ 테두리 : 이중 실선(1.00mm)", "desc": "1mm = 283pt" }, "7": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/@Ratio", - "searchValue": "출판 산업 트렌드", - "value": "50", + "searchValue": "별자리", + "value": "20", "points": 2, "category": "OneAnswer", - "item": "문구 (출판 산업 트렌드)/④ 글상자 모서리 (반원)", + "item": "문구 (별자리)/④ 글상자 모서리 (반원)", "desc": "모서리 비율 50이면 반원 / 20이면 둥근모양" }, "8": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "출판 산업 트렌드", - "value": "106,82,82", + "searchValue": "별자리", + "value": "191,179,233", "points": 2, "category": "Color", - "item": "문구 (출판 산업 트렌드)/⑤ 채우기 : 색상(RGB:106,82,82)" + "item": "문구 (별자리)/⑤ 채우기 : 색상(RGB:191,179,233)" }, "9": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/POSITION/@TreatAsChar", - "searchValue": "출판 산업 트렌드", + "searchValue": "별자리", "value": "true", "points": 1, "category": "OneAnswer", - "item": "문구 (출판 산업 트렌드)/⑥ 글상자 위치 (글자처럼 취급)" + "item": "문구 (별자리)/⑥ 글상자 위치 (글자처럼 취급)" }, "10": { "path": "//PARASHAPE[@Id=//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::P[last()]/@ParaShape]/@Align", - "searchValue": "출판 산업 트렌드", + "searchValue": "별자리", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (출판 산업 트렌드)/⑦ 글상자 정렬 (가운데 정렬)" + "item": "문구 (별자리)/⑦ 글상자 정렬 (가운데 정렬)" }, "11": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "출판 산업 트렌드", - "value": "휴먼옛체", + "searchValue": "별자리", + "value": "중고딕", "points": 1, "category": "FontName", - "item": "문구 (출판 산업 트렌드)/⑧ 글씨체 (휴먼옛체)", - "desc": "폰트 '견고딕'과 '중고딕'은 한글프로그램 내부적으로 '한양견고딕', '한양중고딕'처리 되어서 프로그램 내부에서 수험자 답변에서 '한양'을 제거하는 과정을 거침" + "item": "문구 (별자리)/⑧ 글씨체 (중고딕)" }, "12": { "path": "//CHARSHAPE[@Id=//RECTANGLE//TEXT[./CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "출판 산업 트렌드", - "value": "2000", + "searchValue": "별자리", + "value": "1600", "points": 1, "category": "OneAnswer", - "item": "문구 (출판 산업 트렌드)/⑨ 글씨크기 (20pt)", + "item": "문구 (별자리)/⑨ 글씨크기 (16pt)", "desc":"1pt당 100" }, "13": { "path": "//PARASHAPE[@Id=//RECTANGLE//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "출판 산업 트렌드", + "searchValue": "별자리", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (출판 산업 트렌드)/⑩ 정렬 (가운데 정렬)" + "item": "문구 (별자리)/⑩ 정렬 (가운데 정렬)" }, "14": { "path": "boolean(//PICTURE//SHAPECOMMENT[contains(text(),'{searchValue}')])", @@ -468,92 +469,98 @@ "category": "mmSize", "item": "⑤ 위치 (어울림 : 세로-쪽의 위 24mm)" }, + "19": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "1. 출판 산업의 확장", - "value": "굴림", + "searchValue": "1. 별자리란", + "value": "돋움체", "points": 1, "category": "FontName", - "item": "문구① (1. 출판 산업의 확장)/① 글씨체 (굴림)" + "item": "문구① (1. 별자리란)/① 글씨체 (돋움체)" }, "20": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "1. 출판 산업의 확장", + "searchValue": "1. 별자리란", "value": "1200", "points": 1, "category": "OneAnswer", - "item": "문구① (1. 출판 산업의 확장)/② 크기 (12pt)" + "item": "문구① (1. 별자리란)/② 크기 (12pt)" }, "21": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", - "searchValue": "1. 출판 산업의 확장", + "searchValue": "1. 별자리란", "value": "BOLD", "points": 1, "category": "FontAttribute", - "item": "문구① (1. 출판 산업의 확장)/③ 진하게" + "item": "문구① (1. 별자리란)/③ 진하게" }, + "22": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "2. 도서 박람회의 가치", - "value": "굴림", + "searchValue": "2. 우리나라 계절별 별자리", + "value": "돋움체", "points": 1, "category": "FontName", - "item": "문구② (2. 도서 박람회의 가치)/① 글씨체 (굴림)" + "item": "문구② (2. 우리나라 계절별 별자리)/① 글씨체 (돋움체)" }, "23": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "2. 도서 박람회의 가치", + "searchValue": "2. 우리나라 계절별 별자리", "value": "1200", "points": 1, "category": "OneAnswer", - "item": "문구② (2. 도서 박람회의 가치)/② 크기 (12pt)" + "item": "문구② (2. 우리나라 계절별 별자리)/② 크기 (12pt)" }, "24": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", - "searchValue": "2. 도서 박람회의 가치", + "searchValue": "2. 우리나라 계절별 별자리", "value": "BOLD", "points": 1, "category": "FontAttribute", - "item": "문구② (2. 도서 박람회의 가치)/③ 진하게" + "item": "문구② (2. 우리나라 계절별 별자리)/③ 진하게" }, + "25": { "path": "boolean(//TEXT[CHAR[contains(text(),'{option}')]]/FOOTNOTE)", "path2": "boolean(//CHAR[substring(., string-length(.) - string-length('{option}') + 1) = '{option}']/following-sibling::FOOTNOTE/descendant::CHAR)", - "option": "오디오북", + "option": "북두칠성", "value": true, "points": 2, "category": "Boolean", - "item": "문구 (오디오북)/① 각주 설정 및 문구 입력" + "item": "문구 (북두칠성)/① 각주 설정 및 문구 입력" }, "26": { "path": "//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape", - "searchValue": "눈으로 읽는 대신 귀로 들을 수 있게 책의 내용(문자)을 음성으로 녹음하여 기록한 것을 의미함", - "value": "궁서", + "searchValue": "큰곰자리의 꼬리에 해당하는 7개의 별", + "value": "굴림", "points": 1, "category": "FontName", - "item": "문구 (오디오북)/② 글씨체 (궁서)" + "item": "문구 (북두칠성)/② 글씨체 (굴림)" }, "27": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[contains(text(),'{searchValue}')]]/@CharShape]/@Height", - "searchValue": "눈으로 읽는 대신 귀로 들을 수 있게 책의 내용(문자)을 음성으로 녹음하여 기록한 것을 의미함", + "searchValue": "큰곰자리의 꼬리에 해당하는 7개의 별", "value": "900", "points": 1, "category": "OneAnswer", - "item": "문구 (오디오북)/③ 크기 (9pt)" + "item": "문구 (북두칠성)/③ 크기 (9pt)" }, + "28": { "path": "//P[TEXT[CHAR[contains(text(), '{searchValue}')]]]//AUTONUMFORMAT/@Type", - "searchValue": "눈으로 읽는 대신 귀로 들을 수 있게 책의 내용(문자)을 음성으로 녹음하여 기록한 것을 의미함", - "value": "CircledLatinSmall", + "searchValue": "큰곰자리의 꼬리에 해당하는 7개의 별", + "value": "CircledLatinCapital", "points": 2, "category": "OneAnswer", - "item": "문구 (오디오북)/④ 각주 번호모양", + "item": "문구 (북두칠성)/④ 각주 번호모양", "desc": { - "가,나,다":"HangulSyllable", "1,2,3":"Digit", - "갑,을,병":"DecagonCircle", - "A,B,C":"LatinCapital", "①,②,③":"CircledDigit", + "가,나,다":"HangulSyllable", + "㉮,㉯,㉰":"CircledHangulSyllable", + "A,B,C":"LatinCapital", + "Ⓐ,Ⓑ,Ⓒ":"CircledLatinCapital", + "갑,을,병":"DecagonCircle", "一,二,三":"Ideograph", "㉠,㉡,㉢":"CircledHangulJamo", "ⓐ,ⓑ,ⓒ":"CircledLatinSmall", @@ -561,82 +568,83 @@ "정답에 맞는 값 value에 입력":"" } }, + "29": { - "path": "boolean(//CHAR[contains(text(),'Platform')])", - "ignoreWord": "Platform", + "path": "boolean(//CHAR[contains(text(),'Babylonia')])", + "ignoreWord": "Babylonia", "value": true, "points": 3, "category": "Boolean", - "item": "Platform/영단어 미입력, 대소문자/오타 시 전체 감점", + "item": "Babylonia/영단어 미입력, 대소문자/오타 시 전체 감점", "desc": "유사도 검사를 진행하지 않고 영단어가 모두 일치해야 하므로 xpath구문 내 단어도 수정필요" }, "30": { "path": "//CHAR[contains(text(),'{kor}')][contains(text(),'{chn}')]", "word":[ - ["출판", "出版"], - ["독자", "讀者"], - ["박람회", "博覽會"], - ["교류", "交流"], - ["증가", "增加"] + ["성좌", "星座"], + ["유래", "由來"], + ["표석", "標石"], + ["천구", "天球"], + ["계절", "季節"] ], "value": 10, "points": 10, "category": "Hanja", - "item": "① 출판(出版), ② 독자(讀者), ③ 박람회(博覽會), ④ 교류(交流), ⑤ 증가(增加)" + "item": "① 성좌(星座), ② 유래(由來), ③ 표석(標石), ④ 천구(天球), ⑤ 계절(季節)" }, "31": { - "path": "boolean(//CHAR[contains(translate(text(), ' ', ''),'래도점점')])", + "path": "boolean(//CHAR[contains(translate(text(), ' ', ''),'역에해당')])", "value": true, "points": 3, "category": "Boolean", - "item": "문구 (…콘텐츠 거래는 점점…)/\"는\" → \"도\" 글자바꿈" + "item": "문구 (…지역이 해당하는 티그리스강과…)/이 → 에 글자바꿈" }, "32": { - "path": "boolean(//CHAR[contains(translate(text(), ' ', ''),'양한산업')])", + "path": "boolean(//CHAR[contains(translate(text(), ' ', ''),'나는반드')])", "value": true, "points": 3, "category": "Boolean", - "item": "문구 (…요식업 등의 산업과 다양한 연계되며…)/\"산업과\" / \"다양한\" 순서바꿈" + "item": "문구 (…둘 중 반드시 하나는…)/반드시 / 하나는 순서바꿈" }, "33": { "path": "//TEXT[CHAR[contains(text(),'{searchValue}')]]/@CharShape", - "searchValue": "출판 산업 성장률(단위: %)", - "value": "돋움", + "searchValue": "지역별 천문대 수", + "value": "돋움체", "points": 1, "category": "FontName", - "item": "제목 문구 (출판 산업 성장률(단위: %))/① 글씨체 (돋움)" + "item": "제목 문구 (지역별 천문대 수)/① 글씨체 (돋움체)" }, "34": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "출판 산업 성장률(단위: %)", + "searchValue": "지역별 천문대 수", "value": "1200", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (출판 산업 성장률(단위: %))/② 크기 (12pt)" + "item": "제목 문구 (지역별 천문대 수)/② 크기 (12pt)" }, "35": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", - "searchValue": "출판 산업 성장률(단위: %)", + "searchValue": "지역별 천문대 수", "value": "BOLD", "points": 1, "category": "FontAttribute", - "item": "제목 문구 (출판 산업 성장률(단위: %))/③ 진하게" + "item": "제목 문구 (지역별 천문대 수)/③ 진하게" }, "36": { "path": "//PARASHAPE[@Id=//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "출판 산업 성장률(단위: %)", + "searchValue": "지역별 천문대 수", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (출판 산업 성장률(단위: %))/④ 정렬 (가운데 정렬)" + "item": "제목 문구 (지역별 천문대 수)/④ 정렬 (가운데 정렬)" }, "37": { "path": "//BORDERFILL[@Id=//TABLE/ROW[1]/CELL/@BorderFill]/FILLBRUSH/WINDOWBRUSH/@FaceColor", "path2": "//BORDERFILL[@Id=//CELLZONE[@StartRowAddr='0' and @EndRowAddr='0' and @StartColAddr='0' and @EndColAddr=(ancestor::TABLE[1]/@ColCount)-1]/@BorderFill]/FILLBRUSH/WINDOWBRUSH/@FaceColor", - "value": "233,174,212", + "value": "255,164,95", "points": 2, "category": "Color", - "item": "위쪽 제목 셀/① 색상(RGB:233,174,212)" + "item": "위쪽 제목 셀/① 색상(RGB:255,164,95)" }, "38": { "path": "//CHARSHAPE[@Id=//TABLE/ROW[1]/descendant::TEXT/@CharShape]", @@ -665,11 +673,11 @@ "41": { "path": "//TABLE//TEXT/@CharShape", "path2": "//FONTFACE[@Lang='Hangul']/FONT[@Id=//CHARSHAPE[@Id=//TABLE/ROW/descendant::TEXT/@CharShape]/FONTID/@Hangul]/@Name", - "value": "중고딕", + "value": "궁서", "points": 1, "category": "TableFontName", "category_tmp": "FontName", - "item": "글자모양/① 글씨체 (중고딕)", + "item": "글자모양/① 글씨체 (궁서)", "desc": "테이블 폰트명 문항은 테이블의 모든 셀이 정답폰트와 일치해야 함, 하나만 일치해도 정답으로 채점할 경우 category값을 FontName으로 변경" }, "42": { @@ -688,7 +696,7 @@ }, "44": { "path": "boolean(//TABLE[1]/ROW[last()]/CELL[position()=last()]//FIELDBEGIN[starts-with(@Command, '={option}')]) and boolean(//TABLE[1]/ROW[last()]/CELL[position()=last()-1]//FIELDBEGIN[starts-with(@Command, '={option}')])", - "option": "AVG", + "option": "SUM", "value": true, "points": 4, "category": "Boolean", @@ -721,10 +729,10 @@ }, "48": { "path": "//OLE[@BinItem=//BINITEM[@Format='OLE']/@BinData]//SIZE/@Height", - "value": "80", + "value": "90", "points": 2, "category": "mmSize", - "item": "④ 크기-높이 (80 mm)" + "item": "④ 크기-높이 (90 mm)" }, "49": { "chart_xpath": "boolean(//c:chart and not(//c:pt[not(ancestor::c:tx)]/c:v[text()='합계' or text()='평균']))", @@ -736,36 +744,36 @@ }, "50": { "chart_xpath": "//a:t[text()='{searchValue}']/ancestor::a:r//a:ea/@typeface", - "searchValue": "출판 산업 성장률", - "value": "바탕", + "searchValue": "지역별 천문대 수", + "value": "맑은 고딕", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (출판 산업 성장률)/① 글씨체 (바탕)" + "item": "제목 문구 (지역별 천문대 수)/① 글씨체 (맑은 고딕)" }, "51": { "chart_xpath": "//a:t[text()='{searchValue}']/ancestor::a:r/a:rPr/@sz", - "searchValue": "출판 산업 성장률", - "value": "1200", + "searchValue": "지역별 천문대 수", + "value": "1400", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (출판 산업 성장률)/② 크기 (12pt)" + "item": "제목 문구 (지역별 천문대 수)/② 크기 (14pt)" }, "52": { "chart_xpath": "//a:t[text()='{searchValue}']/ancestor::a:r/a:rPr/@{option}", "option": "b", - "searchValue": "출판 산업 성장률", + "searchValue": "지역별 천문대 수", "value": "1", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (출판 산업 성장률)/③ 진하게", + "item": "제목 문구 (지역별 천문대 수)/③ 진하게", "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" }, "53": { "chart_xpath": "//c:catAx/c:txPr//a:ea/@typeface", - "value": "돋움", + "value": "바탕", "points": 1, "category": "OneAnswer", - "item": "X축/① 글꼴 (돋움)" + "item": "X축/① 글꼴 (바탕)" }, "54": { "chart_xpath": "//c:catAx/c:txPr//a:defRPr/@sz", @@ -785,10 +793,10 @@ }, "56": { "chart_xpath": "//c:valAx/c:txPr//a:ea/@typeface", - "value": "돋움", + "value": "바탕", "points": 1, "category": "OneAnswer", - "item": "Y축/① 글꼴 (돋움)" + "item": "Y축/① 글꼴 (바탕)" }, "57": { "chart_xpath": "//c:valAx/c:txPr//a:defRPr/@sz", @@ -808,10 +816,10 @@ }, "59": { "chart_xpath": "//c:legend//a:ea/@typeface", - "value": "돋움", + "value": "바탕", "points": 1, "category": "OneAnswer", - "item": "범례/① 글꼴 (돋움)" + "item": "범례/① 글꼴 (바탕)" }, "60": { "chart_xpath": "//c:legend//a:defRPr/@sz", diff --git a/DIW_2505D.json b/DIW_2505D.json new file mode 100644 index 0000000..d8d8f7e --- /dev/null +++ b/DIW_2505D.json @@ -0,0 +1,841 @@ +{ + "0": { + "0": { + "path": "", + "path2": "", + "points": 0, + "category": "파일저장", + "item": "파일명 (수검번호.hwp/hwpx)" + }, + "1": { + "path": "//PAGEMARGIN", + "value": { + "Top": 20, + "Bottom": 20, + "Left": 20, + "Right": 20, + "Header": 10, + "Footer": 10, + "Gutter": 0 + }, + "tolerance": 1, + "points": 4, + "category": "PageSetting", + "item": "A4용지, 왼쪽/오른쪽/위쪽/아래쪽 (각20mm), 머리말/꼬리말 (10mm), 제본(0mm)" + }, + "2": { + "path": "", + "value": { + "FontName": "바탕", + "FontSize": "1000", + "Alignment": "Justify", + "LineSpacing": "160" + }, + "points": 4, + "category": "BasicSetting", + "item": "글꼴 (바탕, 10pt), 양쪽정렬, 줄간격 (160%)" + }, + "3": { + "path": "", + "value": null, + "points": 40, + "category": "오타감점", + "item": "오타 1개 -1점 / 2503회부터 오타 1개 -1점으로 변경" + } + }, + "1": { + "1": { + "path": "//TEXTART[@Text='{searchValue}']/TEXTARTSHAPE/@FontName", + "searchValue": "여름방학특집해양스포츠체험교실", + "value": "궁서체", + "points": 1, + "category": "OneAnswer", + "item": "문구 (여름방학특집해양스포츠체험교실)/① 글씨체 (궁서체)" + }, + "2": { + "path": "//TEXTART[@Text='{searchValue}']/descendant::WINDOWBRUSH/@FaceColor", + "searchValue": "여름방학특집해양스포츠체험교실", + "value": "49,95,151", + "points": 2, + "category": "Color", + "item": "문구 (여름방학특집해양스포츠체험교실)/② 채우기 : 색상(RGB:49,95,151)" + }, + "3": { + "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Width", + "searchValue": "여름방학특집해양스포츠체험교실", + "value": "120", + "tolerance": 1, + "points": 2, + "category": "mmSize", + "item": "문구 (여름방학특집해양스포츠체험교실)/③ 크기-너비 (120 mm)" + }, + "4": { + "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Height", + "searchValue": "여름방학특집해양스포츠체험교실", + "value": "20", + "tolerance": 1, + "points": 2, + "category": "mmSize", + "item": "문구 (여름방학특집해양스포츠체험교실)/④ 크기-높이 (20 mm)" + }, + "5": { + "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/POSITION/@TreatAsChar", + "searchValue": "여름방학특집해양스포츠체험교실", + "value": "true", + "points": 2, + "category": "OneAnswer", + "item": "문구 (여름방학특집해양스포츠체험교실)/⑤ 위치 (글자처럼 취급)" + }, + "6": { + "path":"//PARASHAPE[@Id=//P[.//TEXTART[@Text='{searchValue}']]/@ParaShape]/@Align", + "searchValue": "여름방학특집해양스포츠체험교실", + "value": "Center", + "points": 2, + "category": "OneAnswer", + "item": "문구 (여름방학특집해양스포츠체험교실)/⑥ 정렬 (가운데 정렬)" + }, + "7": { + "path": "//TEXTART[@Text='{searchValue}']", + "searchValue": "여름방학특집해양스포츠체험교실", + "value": true, + "points": 2, + "category": "Boolean", + "item": "문구 (여름방학특집해양스포츠체험교실)/⑦ 글맵시모양 (육안확인)" + }, + "8": { + "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/SIZE", + "searchValue": "여", + "value": { + "Height": 2800, + "Width": 2800 + }, + "tolerance": 200, + "points": 1, + "category": "TwoLineSize", + "item": "여/① 모양 (2줄)" + }, + "9": { + "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", + "searchValue": "여", + "value": "굴림체", + "points": 1, + "category": "FontName", + "item": "여/② 글씨체 (굴림체)" + }, + "10": { + "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", + "searchValue": "여", + "value": "144,231,51", + "points": 2, + "category": "Color", + "item": "여/③ 면색 : 색상(RGB:144,231,51)" + }, + "11": { + "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//OUTSIDEMARGIN/@Right", + "searchValue": "여", + "value": "3.0", + "tolerance": 1, + "points": 2, + "category": "mmSize", + "item": "여/④ 본문과의 간격 : 3.0mm" + }, + "12": { + "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]", + "searchValue": "시원한 바다와 함께하는 해양 스포츠 체험 교실", + "value": "BOLD", + "points": 2, + "category": "FontAttribute", + "item": "문구 (시원한 바다와 함께하는 해양 스포츠 체험 교실)/① 진하게" + }, + "13": { + "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]", + "searchValue": "시원한 바다와 함께하는 해양 스포츠 체험 교실", + "value": "UNDERLINE", + "points": 2, + "category": "FontAttribute", + "item": "문구 (시원한 바다와 함께하는 해양 스포츠 체험 교실)/② 밑줄" + }, + "14": { + "path": "//CHAR[contains(text(),'{char1}')]", + "path2": "//CHAR[contains(text(),'{char2}')]", + "path3": "//CHAR[contains(text(),'{char3}')]", + "char1": "◐", + "char2": "◑", + "char3": "※", + "value": 3, + "points": 3, + "category": "SpecialChar", + "item": "① ◐ , ② ◑ , ③ ※" + }, + "15": { + "path": "//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape", + "searchValue": "참가안내", + "value": "돋움", + "points": 1, + "category": "FontName", + "item": "문구 (◐ 참가안내 ◑)/① 글씨체 (돋움)" + }, + "16": { + "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/@ParaShape]/@Align", + "searchValue": "참가안내", + "value": "Center", + "points": 1, + "category": "OneAnswer", + "item": "문구 (◐ 참가안내 ◑)/② 정렬 (가운데 정렬)" + }, + "17": { + "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", + "hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]", + "searchValue": "해양소년단 연맹 홈페이지(http://www.ihd.or.kr)", + "value": "ITALIC", + "points": 1, + "category": "FontAttribute", + "item": "문구 (해양소년단 연맹 홈페이지(http://www.ihd.or.kr))/① 기울임" + }, + "18": { + "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", + "hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]", + "searchValue": "해양소년단 연맹 홈페이지(http://www.ihd.or.kr)", + "value": "UNDERLINE", + "points": 1, + "category": "FontAttribute", + "item": "문구 (해양소년단 연맹 홈페이지(http://www.ihd.or.kr))/② 밑줄" + }, + "19": { + "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/following-sibling::P[1]/@ParaShape]/PARAMARGIN", + "searchValue": "기타사항", + "value": { + "Left": 10, + "Indent": 12 + }, + "points": 2, + "category": "ParaShape", + "item": "문구 (※ 기타… 이하 문단)/왼쪽여백 (10pt), 내어쓰기 (12pt)", + "desc": "내부적으로 내어쓰기는 음수값 / JSON value값은 양수로 입력" + }, + "20": { + "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]/@Height", + "searchValue": "2025. 05. 24.", + "value": "1400", + "points": 1, + "category": "OneAnswer", + "item": "문구 (2025. 05. 24.)/① 크기 (14pt)", + "desc": "1pt당 100" + }, + "21": { + "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/@ParaShape]/@Align", + "searchValue": "2025. 05. 24.", + "value": "Center", + "points": 1, + "category": "OneAnswer", + "item": "문구 (2025. 05. 24.)/② 정렬 (가운데 정렬)" + }, + "22": { + "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", + "searchValue": "해양스포츠홍보위원회", + "value": "견고딕", + "points": 1, + "category": "FontName", + "item": "문구 (해양스포츠홍보위원회)/① 글씨체 (견고딕)" + }, + "23": { + "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", + "searchValue": "해양스포츠홍보위원회", + "value": "2600", + "points": 1, + "category": "OneAnswer", + "item": "문구 (해양스포츠홍보위원회)/② 크기 (26pt)" + }, + "24": { + "path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/ancestor::P/@ParaShape]/@Align", + "searchValue": "해양스포츠홍보위원회", + "value": "Center", + "points": 1, + "category": "OneAnswer", + "item": "문구 (해양스포츠홍보위원회)/③ 정렬 (가운데 정렬)" + }, + "25": { + "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", + "searchValue": "DIAT", + "value": "굴림", + "points": 1, + "category": "FontName", + "item": "문구 (DIAT)/① 글꼴 (굴림)" + }, + "26": { + "path": "//CHARSHAPE[@Id=//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", + "searchValue": "DIAT", + "value": "900", + "points": 1, + "category": "OneAnswer", + "item": "문구 (DIAT)/② 크기 (9pt)" + }, + "27": { + "path": "//PARASHAPE[@Id=//SECTION[1]//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align", + "searchValue": "DIAT", + "value": "Right", + "points": 1, + "category": "OneAnswer", + "item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)" + }, + "28": { + "path": "//PAGENUM/@FormatType", + "value": "CircledDigit", + "points": 2, + "category": "PageNumber", + "item": "① 쪽 번호 매기기 (A,B,C 순으로)", + "desc1": { + "1,2,3":"Digit", + "①,②,③":"CircledDigit", + "가,나,다":"HangulSyllable", + "㉮,㉯,㉰":"CircledHangulSyllable", + "A,B,C":"LatinCapital", + "Ⓐ,Ⓑ,Ⓒ":"CircledLatinCapital", + "갑,을,병":"DecagonCircle", + "一,二,三":"Ideograph", + "㉠,㉡,㉢":"CircledHangulJamo", + "ⓐ,ⓑ,ⓒ":"CircledLatinSmall", + "i,ii,iii":"RomanSmall", + "정답에 맞는 값 value에 입력":"" + }, + "desc2": "1, 2페이지 모두 정답이어야 점수 부여" + }, + "29": { + "path": "//PAGENUM/@Pos", + "value": "BottomRight", + "points": 2, + "category": "PageNumber", + "item": "가운데 아래", + "desc": "1, 2페이지 모두 정답이어야 점수 부여", + "desc2": { + "가운데 아래": "BottomCenter", + "오른쪽 아래": "BottomRight" + } + }, + "30": { + "path": "not(//PARASHAPE[@Id=//SECTION[1]/P/@ParaShape]/PARAMARGIN[@LineSpacing!='{option}'])", + "option": "180", + "value": true, + "points": 2, + "category": "Boolean", + "item": "문제 1 줄간격 180% 설정", + "desc": "1페이지 문단의 줄간격이 정답이 아닌 문단이 있으면 False(감점)" + } + }, + "2": { + "1": { + "path": "//PAGEBORDERFILL[@Type='Both' or @Type='Even']/@HeaderInside", + "path2": "//BORDERFILL[@Id=//PAGEBORDERFILL[@Type='Both' or @Type='Even']/@BorferFill]", + "value": { + "header_inside": true, + "all_double_slim": true + }, + "points": 4, + "category": "PageBorder", + "item": "문제2 쪽테두리(이중 실선, 머리말 포함) 설정" + }, + "2": { + "path": "count(//SECTION)>1", + "value": true, + "points": 3, + "category": "Boolean", + "item": "① 구역나누기", + "desc": "섹션이 1개 이상이면 점수부여" + }, + "3": { + "path": "//COLDEF/@Count", + "value": "2", + "points": 3, + "category": "OneAnswer", + "item": "② 다단 2단" + }, + "4": { + "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width", + "searchValue": "해양 스포츠의 세계", + "value": "60", + "points": 2, + "category": "mmSize", + "item": "문구 (해양 스포츠의 세계)/① 크기-너비 (60 mm)" + }, + "5": { + "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Height", + "searchValue": "해양 스포츠의 세계", + "value": "12", + "points": 2, + "category": "mmSize", + "item": "문구 (해양 스포츠의 세계)/② 크기-높이 (12mm)" + }, + "6": { + "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE/@Style", + "path2": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE/@Width", + "searchValue": "해양 스포츠의 세계", + "value": [ "DoubleSlim", "283" ], + "points": 2, + "category": "DoubleAnswer", + "item": "문구 (해양 스포츠의 세계)/③ 테두리 : 이중 실선(1.00mm)", + "desc": "1mm = 283pt" + }, + "7": { + "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/@Ratio", + "searchValue": "해양 스포츠의 세계", + "value": "20", + "points": 2, + "category": "OneAnswer", + "item": "문구 (해양 스포츠의 세계)/④ 글상자 모서리 (반원)", + "desc": "모서리 비율 50이면 반원 / 20이면 둥근모양" + }, + "8": { + "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", + "searchValue": "해양 스포츠의 세계", + "value": "248,231,130", + "points": 2, + "category": "Color", + "item": "문구 (해양 스포츠의 세계)/⑤ 채우기 : 색상(RGB:248,231,130)" + }, + "9": { + "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/POSITION/@TreatAsChar", + "searchValue": "해양 스포츠의 세계", + "value": "true", + "points": 1, + "category": "OneAnswer", + "item": "문구 (해양 스포츠의 세계)/⑥ 글상자 위치 (글자처럼 취급)" + }, + "10": { + "path": "//PARASHAPE[@Id=//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::P[last()]/@ParaShape]/@Align", + "searchValue": "해양 스포츠의 세계", + "value": "Center", + "points": 1, + "category": "OneAnswer", + "item": "문구 (해양 스포츠의 세계)/⑦ 글상자 정렬 (가운데 정렬)" + }, + "11": { + "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", + "searchValue": "해양 스포츠의 세계", + "value": "궁서", + "points": 1, + "category": "FontName", + "item": "문구 (해양 스포츠의 세계)/⑧ 글씨체 (궁서)" + }, + "12": { + "path": "//CHARSHAPE[@Id=//RECTANGLE//TEXT[./CHAR[text()='{searchValue}']]/@CharShape]/@Height", + "searchValue": "해양 스포츠의 세계", + "value": "1800", + "points": 1, + "category": "OneAnswer", + "item": "문구 (해양 스포츠의 세계)/⑨ 글씨크기 (18pt)", + "desc":"1pt당 100" + }, + "13": { + "path": "//PARASHAPE[@Id=//RECTANGLE//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", + "searchValue": "해양 스포츠의 세계", + "value": "Center", + "points": 1, + "category": "OneAnswer", + "item": "문구 (해양 스포츠의 세계)/⑩ 정렬 (가운데 정렬)" + }, + "14": { + "path": "boolean(//PICTURE//SHAPECOMMENT[contains(text(),'{searchValue}')])", + "searchValue": "원본 그림의 이름: 그림", + "value": true, + "points": 2, + "category": "Boolean", + "item": "① 파일명 \"그림D.jpg\" 삽입" + }, + "15": { + "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/SIZE/@Width", + "value": "80", + "points": 2, + "category": "mmSize", + "item": "② 크기-너비 (80 mm)" + }, + "16": { + "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/SIZE/@Height", + "value": "40", + "points": 2, + "category": "mmSize", + "item": "③ 크기-높이 (40 mm)" + }, + "17": { + "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/POSITION/@HorzOffset", + "value": "0", + "points": 2, + "category": "mmSize", + "item": "④ 위치 (어울림 : 가로-쪽의 왼쪽 0.0mm)" + }, + "18": { + "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/POSITION/@VertOffset", + "value": "24", + "points": 2, + "category": "mmSize", + "item": "⑤ 위치 (어울림 : 세로-쪽의 위 24mm)" + }, + + "19": { + "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", + "searchValue": "1. 국립해양박물관", + "value": "돋움체", + "points": 1, + "category": "FontName", + "item": "문구① (1. 국립해양박물관)/① 글씨체 (돋움체)" + }, + "20": { + "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", + "searchValue": "1. 국립해양박물관", + "value": "1200", + "points": 1, + "category": "OneAnswer", + "item": "문구① (1. 국립해양박물관)/② 크기 (12pt)" + }, + "21": { + "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", + "searchValue": "1. 국립해양박물관", + "value": "BOLD", + "points": 1, + "category": "FontAttribute", + "item": "문구① (1. 국립해양박물관)/③ 진하게" + }, + + "22": { + "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", + "searchValue": "2. 윈드 서핑", + "value": "돋움체", + "points": 1, + "category": "FontName", + "item": "문구② (2. 윈드 서핑)/① 글씨체 (돋움체)" + }, + "23": { + "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", + "searchValue": "2. 윈드 서핑", + "value": "1200", + "points": 1, + "category": "OneAnswer", + "item": "문구② (2. 윈드 서핑)/② 크기 (12pt)" + }, + "24": { + "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", + "searchValue": "2. 윈드 서핑", + "value": "BOLD", + "points": 1, + "category": "FontAttribute", + "item": "문구② (2. 윈드 서핑)/③ 진하게" + }, + + "25": { + "path": "boolean(//TEXT[CHAR[contains(text(),'{option}')]]/FOOTNOTE)", + "path2": "boolean(//CHAR[substring(., string-length(.) - string-length('{option}') + 1) = '{option}']/following-sibling::FOOTNOTE/descendant::CHAR)", + "option": "마스트", + "value": true, + "points": 2, + "category": "Boolean", + "item": "문구 (마스트)/① 각주 설정 및 문구 입력" + }, + "26": { + "path": "//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape", + "searchValue": "선체의 갑판 위에 세워진 기둥", + "value": "바탕체", + "points": 1, + "category": "FontName", + "item": "문구 (마스트)/② 글씨체 (바탕체)" + }, + "27": { + "path": "//CHARSHAPE[@Id=//TEXT[CHAR[contains(text(),'{searchValue}')]]/@CharShape]/@Height", + "searchValue": "선체의 갑판 위에 세워진 기둥", + "value": "900", + "points": 1, + "category": "OneAnswer", + "item": "문구 (마스트)/③ 크기 (9pt)" + }, + + "28": { + "path": "//P[TEXT[CHAR[contains(text(), '{searchValue}')]]]//AUTONUMFORMAT/@Type", + "searchValue": "선체의 갑판 위에 세워진 기둥", + "value": "CircledDigit", + "points": 2, + "category": "OneAnswer", + "item": "문구 (마스트)/④ 각주 번호모양", + "desc": { + "1,2,3":"Digit", + "①,②,③":"CircledDigit", + "가,나,다":"HangulSyllable", + "㉮,㉯,㉰":"CircledHangulSyllable", + "A,B,C":"LatinCapital", + "Ⓐ,Ⓑ,Ⓒ":"CircledLatinCapital", + "갑,을,병":"DecagonCircle", + "一,二,三":"Ideograph", + "㉠,㉡,㉢":"CircledHangulJamo", + "ⓐ,ⓑ,ⓒ":"CircledLatinSmall", + "i,ii,iii":"RomanSmall", + "정답에 맞는 값 value에 입력":"" + } + }, + + "29": { + "path": "boolean(//CHAR[contains(text(),'Display')])", + "ignoreWord": "Display", + "value": true, + "points": 3, + "category": "Boolean", + "item": "Display/영단어 미입력, 대소문자/오타 시 전체 감점", + "desc": "유사도 검사를 진행하지 않고 영단어가 모두 일치해야 하므로 xpath구문 내 단어도 수정필요" + }, + "30": { + "path": "//CHAR[contains(text(),'{kor}')][contains(text(),'{chn}')]", + "word":[ + ["유물", "遺物"], + ["상설", "常設"], + ["체험", "體驗"], + ["해양", "海洋"], + ["기교", "技巧"] + ], + "value": 10, + "points": 10, + "category": "Hanja", + "item": "① 유물(遺物), ② 상설(常設), ③ 체험(體驗), ④ 해양(海洋), ⑤ 기교(技巧)" + }, + "31": { + "path": "boolean(//CHAR[contains(translate(text(), ' ', ''),'을헤치는')])", + "value": true, + "points": 3, + "category": "Boolean", + "item": "문구 (…물살을 헤치은…)/ 은 → 는 글자바꿈" + }, + "32": { + "path": "boolean(//CHAR[contains(translate(text(), ' ', ''),'연의바람')])", + "value": true, + "points": 3, + "category": "Boolean", + "item": "문구 (…바람을 자연의 이용하여…)/바람을 / 자연의 순서바꿈" + }, + "33": { + "path": "//TEXT[CHAR[contains(text(),'{searchValue}')]]/@CharShape", + "searchValue": "종목별 해양 스포츠 참가자 수", + "value": "중고딕", + "points": 1, + "category": "FontName", + "item": "제목 문구 (종목별 해양 스포츠 참가자 수)/① 글씨체 (중고딕)" + }, + "34": { + "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height", + "searchValue": "종목별 해양 스포츠 참가자 수", + "value": "1200", + "points": 1, + "category": "OneAnswer", + "item": "제목 문구 (종목별 해양 스포츠 참가자 수)/② 크기 (12pt)" + }, + "35": { + "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", + "searchValue": "종목별 해양 스포츠 참가자 수", + "value": "BOLD", + "points": 1, + "category": "FontAttribute", + "item": "제목 문구 (종목별 해양 스포츠 참가자 수)/③ 진하게" + }, + "36": { + "path": "//PARASHAPE[@Id=//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", + "searchValue": "종목별 해양 스포츠 참가자 수", + "value": "Center", + "points": 1, + "category": "OneAnswer", + "item": "제목 문구 (종목별 해양 스포츠 참가자 수)/④ 정렬 (가운데 정렬)" + }, + "37": { + "path": "//BORDERFILL[@Id=//TABLE/ROW[1]/CELL/@BorderFill]/FILLBRUSH/WINDOWBRUSH/@FaceColor", + "path2": "//BORDERFILL[@Id=//CELLZONE[@StartRowAddr='0' and @EndRowAddr='0' and @StartColAddr='0' and @EndColAddr=(ancestor::TABLE[1]/@ColCount)-1]/@BorderFill]/FILLBRUSH/WINDOWBRUSH/@FaceColor", + "value": "233,162,149", + "points": 2, + "category": "Color", + "item": "위쪽 제목 셀/① 색상(RGB:233,162,149)" + }, + "38": { + "path": "//CHARSHAPE[@Id=//TABLE/ROW[1]/descendant::TEXT/@CharShape]", + "value": "BOLD", + "points": 1, + "category": "FontAttribute", + "item": "위쪽 제목 셀/② 진하게", + "desc": "글자 속성이라 CELLZONE으로 적용 되지 않음" + }, + "39": { + "path": "//BORDERFILL[@Id=//TABLE/ROW[1]/CELL/@BorderFill]/BOTTOMBORDER/@Type", + "path2": "//BORDERFILL[@Id=//CELLZONE[@StartRowAddr='0' and @EndRowAddr='0' and @StartColAddr='0' and @EndColAddr=(ancestor::TABLE[1]/@ColCount)-1]/@BorderFill]/BOTTOMBORDER/@Type", + "value": "DoubleSlim", + "points": 2, + "category": "TableAnswer", + "item": "제목 셀 아래선/① 이중실선" + }, + "40": { + "path": "//BORDERFILL[@Id=//TABLE/ROW[1]/CELL/@BorderFill]/BOTTOMBORDER/@Width", + "path2": "//BORDERFILL[@Id=//CELLZONE[@StartRowAddr='0' and @EndRowAddr='0' and @StartColAddr='0' and @EndColAddr=(ancestor::TABLE[1]/@ColCount)-1]/@BorderFill]/BOTTOMBORDER/@Width", + "value": "0.5mm", + "points": 2, + "category": "TableAnswer", + "item": "제목 셀 아래선/② 0.5mm" + }, + "41": { + "path": "//TABLE//TEXT/@CharShape", + "path2": "//FONTFACE[@Lang='Hangul']/FONT[@Id=//CHARSHAPE[@Id=//TABLE/ROW/descendant::TEXT/@CharShape]/FONTID/@Hangul]/@Name", + "value": "굴림체", + "points": 1, + "category": "TableFontName", + "category_tmp": "FontName", + "item": "글자모양/① 글씨체 (굴림체)", + "desc": "테이블 폰트명 문항은 테이블의 모든 셀이 정답폰트와 일치해야 함, 하나만 일치해도 정답으로 채점할 경우 category값을 FontName으로 변경" + }, + "42": { + "path": "//CHARSHAPE[@Id=//TABLE//TEXT/@CharShape]/@Height", + "value": "1000", + "points": 1, + "category": "TableAnswer", + "item": "글자모양/② 크기 (10pt)" + }, + "43": { + "path": "//PARASHAPE[@Id=//TABLE/ROW//P/@ParaShape]/@Align", + "value": "Center", + "points": 1, + "category": "TableAnswer", + "item": "글자모양/③ 정렬 (가운데 정렬)" + }, + "44": { + "path": "boolean(//TABLE[1]/ROW[last()]/CELL[position()=last()]//FIELDBEGIN[starts-with(@Command, '={option}')]) and boolean(//TABLE[1]/ROW[last()]/CELL[position()=last()-1]//FIELDBEGIN[starts-with(@Command, '={option}')])", + "option": "SUM", + "value": true, + "points": 4, + "category": "Boolean", + "item": "블록 계산식/합계", + "desc": "option값에 합계는 SUM / 평균은 AVG" + }, + "45": { + "chart_xpath": "", + "chart_type": "묶은세로막대형", + "value": true, + "points": 2, + "category": "ChartType", + "item": "① 종류 (묶은세로막대형)", + "desc": "chart_type을 입력받아 차트타입에 맞는 xml요소가 있는지 내부적으로 검사, chart_type만 한글로 입력해주면 된다. (공백무시)" + }, + "46": { + "chart_xpath": "//c:valAx/c:majorTickMark/@val", + "value": "out", + "points": 2, + "category": "OneAnswer", + "item": "② 값 축 주 눈금선", + "desc": "chart xml파일에서 답안을 가져오는 문항은 path키값 대신 chart_xpath키값을 이용해 xapth구문을 작성한다" + }, + "47": { + "path": "//OLE[@BinItem=//BINITEM[@Format='OLE']/@BinData]//SIZE/@Width", + "value": "80", + "points": 2, + "category": "mmSize", + "item": "③ 크기-너비 (80 mm)" + }, + "48": { + "path": "//OLE[@BinItem=//BINITEM[@Format='OLE']/@BinData]//SIZE/@Height", + "value": "90", + "points": 2, + "category": "mmSize", + "item": "④ 크기-높이 (90 mm)" + }, + "49": { + "chart_xpath": "boolean(//c:chart and not(//c:pt[not(ancestor::c:tx)]/c:v[text()='합계' or text()='평균']))", + "value": true, + "points": 2, + "category": "Boolean", + "item": "⑤ 차트 데이터(표에서 블록계산식을 제외한 나머지 값만 이용)", + "desc": "차트가 존재하고 블록계산식(합계, 평균) 데이터가 없는 경우 정답 처리" + }, + "50": { + "chart_xpath": "//a:t[text()='{searchValue}']/ancestor::a:r//a:ea/@typeface", + "searchValue": "종목별 해양 스포츠 참가자 수", + "value": "궁서체", + "points": 1, + "category": "OneAnswer", + "item": "제목 문구 (종목별 해양 스포츠 참가자 수)/① 글씨체 (궁서체)" + }, + "51": { + "chart_xpath": "//a:t[text()='{searchValue}']/ancestor::a:r/a:rPr/@sz", + "searchValue": "종목별 해양 스포츠 참가자 수", + "value": "1300", + "points": 1, + "category": "OneAnswer", + "item": "제목 문구 (종목별 해양 스포츠 참가자 수)/② 크기 (13pt)" + }, + "52": { + "chart_xpath": "//a:t[text()='{searchValue}']/ancestor::a:r/a:rPr/@{option}", + "option": "b", + "searchValue": "종목별 해양 스포츠 참가자 수", + "value": "1", + "points": 1, + "category": "OneAnswer", + "item": "제목 문구 (종목별 해양 스포츠 참가자 수)/③ 진하게", + "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" + }, + "53": { + "chart_xpath": "//c:catAx/c:txPr//a:ea/@typeface", + "value": "맑은 고딕", + "points": 1, + "category": "OneAnswer", + "item": "X축/① 글꼴 (맑은 고딕)" + }, + "54": { + "chart_xpath": "//c:catAx/c:txPr//a:defRPr/@sz", + "value": "900", + "points": 1, + "category": "OneAnswer", + "item": "X축/② 크기 (9pt)" + }, + "55": { + "chart_xpath": "//c:catAx/c:txPr//a:defRPr/@{option}", + "option": "i", + "value": "1", + "points": 1, + "category": "OneAnswer", + "item": "X축/③ 기울임", + "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" + }, + "56": { + "chart_xpath": "//c:valAx/c:txPr//a:ea/@typeface", + "value": "맑은 고딕", + "points": 1, + "category": "OneAnswer", + "item": "Y축/① 글꼴 (맑은 고딕)" + }, + "57": { + "chart_xpath": "//c:valAx/c:txPr//a:defRPr/@sz", + "value": "900", + "points": 1, + "category": "OneAnswer", + "item": "Y축/② 크기 (9pt)" + }, + "58": { + "chart_xpath": "//c:valAx/c:txPr//a:defRPr/@{option}", + "option": "i", + "value": "1", + "points": 1, + "category": "OneAnswer", + "item": "Y축/③ 기울임", + "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" + }, + "59": { + "chart_xpath": "//c:legend//a:ea/@typeface", + "value": "맑은고딕", + "points": 1, + "category": "OneAnswer", + "item": "범례/① 글꼴 (맑은고딕)" + }, + "60": { + "chart_xpath": "//c:legend//a:defRPr/@sz", + "value": "900", + "points": 1, + "category": "OneAnswer", + "item": "범례/② 크기 (9pt)" + }, + "61": { + "chart_xpath": "//c:legend//a:defRPr/@{option}", + "option": "i", + "value": "1", + "points": 1, + "category": "OneAnswer", + "item": "범례/③ 기울임", + "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" + } + } +} \ No newline at end of file diff --git a/diwScoring2.py b/diwScoring2.py index ff17d01..e2955c0 100644 --- a/diwScoring2.py +++ b/diwScoring2.py @@ -339,16 +339,17 @@ class XMLScorer: # 가로 차트일 경우에만 x축과 y축을 바꿔줌 # 세로, 꺾은선, 원형 차트의 경우 그대로 사용 if "가로" in chart_type: - chart_xpath = chart_xpath.replace("catAx", "valAx") - chart_xpath = chart_xpath.replace("valAx", "catAx") - - + if "catAx" in chart_xpath: + chart_xpath = chart_xpath.replace("catAx", "valAx") + if "valAx" in chart_xpath: + chart_xpath = chart_xpath.replace("valAx", "catAx") chart_items = chart_tree.xpath(chart_xpath, namespaces=namespaces) if chart_xpath else [] for item in chain(items, items2, chart_items): - user_answer = item - + user_answer = item.replace(" ", "") if isinstance(item, str) else item + right_answer = right_answer.replace(" ", "") + self.evaluate_answer(scoring, user_answer, right_answer, points) if scoring['points'] > 0: @@ -475,11 +476,12 @@ class XMLScorer: continue font_name = root.xpath(f"//FONTFACE[@Lang='Hangul']/FONT[@Id='{font_id[0]}']/@Name") + if not font_name: all_match = False continue - user_answer = font_name[0] + user_answer = font_name[0].replace(" ", "") # 공백 제거 # 접두어 제거 if right_answer in ["견고딕", "중고딕"]: @@ -508,18 +510,22 @@ class XMLScorer: # hyperlink가 아닌 경우(일반적인 텍스트 일 경우) if not has_hyperlink_ptag: - charshape = root.xpath(xpath) - if not charshape: + charshape_list = root.xpath(xpath) + if not charshape_list: charshape = None user_answer = None else: - font_attribute = charshape[0].find(right_answer) - if font_attribute is not None: - user_answer = font_attribute.tag - else: - user_answer = None + for charshape in charshape_list: + font_attribute = charshape.find(right_answer) + if font_attribute is not None: + user_answer = font_attribute.tag + else: + user_answer = None - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") + self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") + + if scoring['points'] > 0: + break # 하이퍼링크인 경우 elif has_hyperlink_ptag: @@ -709,7 +715,9 @@ class XMLScorer: chart_type_list = { '꺾은선형': "//c:lineChart[c:grouping[@val='standard']]", '묶은가로막대형': "//c:barChart[c:barDir[@val='bar'] and c:grouping[@val='clustered']]", + '누적가로막대형': "//c:barChart[c:barDir[@val='bar'] and c:grouping[@val='stacked']]", '묶은세로막대형': "//c:barChart[c:barDir[@val='col'] and c:grouping[@val='clustered']]", + '누적세로막대형': "//c:barChart[c:barDir[@val='col'] and c:grouping[@val='stacked']]", '원형': "//c:pieChart", '분산형': "//c:scatterChart" } @@ -1024,17 +1032,18 @@ class XMLScorer: def main(): # 시험회차 및 유형 - exam_round = '2504' + exam_round = '2505' # 채점하고자 하는 유형은 주석 해제 exam_types = [ - 'A', - 'B', - 'C', + # 'A', + # 'B', + # 'C', + 'D', ] - test_mode = False - # test_mode = True #/TEST 폴더 채점시 + # test_mode = False + test_mode = True #/TEST 폴더 채점시 output_excel_paths = [] for exam_type in exam_types: diff --git a/filtered_score_diff.py b/filtered_score_diff.py deleted file mode 100644 index cf70d97..0000000 --- a/filtered_score_diff.py +++ /dev/null @@ -1,25 +0,0 @@ -import pandas as pd - -# 엑셀 파일 경로 -file_path = "./diff.xlsx" - -# 엑셀 파일 읽기 -df = pd.read_excel(file_path) - -# 데이터 미리 보기 -df.head() - -# '총점' 컬럼 기준으로 점수가 다른 경우만 남기기 -filtered_df = df.groupby("Unnamed: 0").filter(lambda x: x["총점"].nunique() > 1) - -# 결과 확인 -filtered_df.head() - -# 점수가 다른 경우만 남기는 필터링 -filtered_df = df.groupby("Unnamed: 0").filter(lambda x: x["총점"].nunique() > 1) - -# 결과 저장 -output_path = "./filtered_score_diff.xlsx" -filtered_df.to_excel(output_path, index=False) - -output_path \ No newline at end of file diff --git a/filtered_score_diff.xlsx b/filtered_score_diff.xlsx deleted file mode 100644 index 206c472..0000000 Binary files a/filtered_score_diff.xlsx and /dev/null differ diff --git a/hwp_conversion.log b/hwp_conversion.log index 544050c..61be2cd 100644 --- a/hwp_conversion.log +++ b/hwp_conversion.log @@ -14819,3 +14819,33 @@ 2025-05-01 15:44:21,157 - INFO - 변환 성공: 워드(한글)-002494-윤요한.hwpx -> 워드(한글)-002494-윤요한.hml 2025-05-01 15:44:21,758 - INFO - 변환 성공: 워드(한글)-2504-000156 유지연.hwpx -> 워드(한글)-2504-000156 유지연.hml 2025-05-01 15:44:22,061 - INFO - 폴더 변환 완료: C:\Users\dra\project\HWP\HWP-Scoring\input\2504\C\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2504\C\DIW +2025-05-26 15:07:50,038 - INFO - 폴더 변환 시작: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\A\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\A\DIW +2025-05-26 15:07:56,898 - INFO - 변환 성공: DIW2505A.hwpx -> DIW2505A.hml +2025-05-26 15:07:57,380 - INFO - 폴더 변환 완료: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\A\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\A\DIW +2025-05-26 15:07:57,881 - INFO - 폴더 변환 시작: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\B\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\B\DIW +2025-05-26 15:08:00,725 - INFO - 변환 성공: DIW2505B.hwpx -> DIW2505B.hml +2025-05-26 15:08:01,155 - INFO - 폴더 변환 완료: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\B\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\B\DIW +2025-05-26 15:08:01,657 - INFO - 폴더 변환 시작: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\C\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\C\DIW +2025-05-26 15:08:04,140 - INFO - 변환 성공: DIW2505C.hwpx -> DIW2505C.hml +2025-05-26 15:08:04,529 - INFO - 폴더 변환 완료: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\C\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\C\DIW +2025-05-26 15:15:47,294 - INFO - 폴더 변환 시작: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\A\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\A\DIW +2025-05-26 15:15:50,425 - INFO - 변환 성공: DIW2505A.hwpx -> DIW2505A.hml +2025-05-26 15:15:50,848 - INFO - 폴더 변환 완료: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\A\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\A\DIW +2025-05-26 15:15:51,349 - INFO - 폴더 변환 시작: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\B\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\B\DIW +2025-05-26 15:15:53,969 - INFO - 변환 성공: DIW2505B.hwpx -> DIW2505B.hml +2025-05-26 15:15:54,401 - INFO - 폴더 변환 완료: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\B\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\B\DIW +2025-05-26 15:15:54,901 - INFO - 폴더 변환 시작: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\C\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\C\DIW +2025-05-26 15:15:57,190 - INFO - 변환 성공: DIW2505C.hwpx -> DIW2505C.hml +2025-05-26 15:15:57,577 - INFO - 폴더 변환 완료: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\C\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\C\DIW +2025-05-26 15:16:15,271 - INFO - 폴더 변환 시작: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\A\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\A\DIW +2025-05-26 15:16:18,622 - INFO - 변환 성공: DIW2505A.hwpx -> DIW2505A.hml +2025-05-26 15:16:19,034 - INFO - 폴더 변환 완료: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\A\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\A\DIW +2025-05-26 15:16:19,535 - INFO - 폴더 변환 시작: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\B\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\B\DIW +2025-05-26 15:16:22,096 - INFO - 변환 성공: DIW2505B.hwpx -> DIW2505B.hml +2025-05-26 15:16:22,518 - INFO - 폴더 변환 완료: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\B\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\B\DIW +2025-05-26 15:16:23,019 - INFO - 폴더 변환 시작: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\C\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\C\DIW +2025-05-26 15:16:25,439 - INFO - 변환 성공: DIW2505C.hwpx -> DIW2505C.hml +2025-05-26 15:16:25,819 - INFO - 폴더 변환 완료: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\C\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\C\DIW +2025-05-26 15:16:26,320 - INFO - 폴더 변환 시작: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\D\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\D\DIW +2025-05-26 15:16:28,759 - INFO - 변환 성공: DIW2505D.hwpx -> DIW2505D.hml +2025-05-26 15:16:29,195 - INFO - 폴더 변환 완료: C:\Users\dra\project\HWP\HWP-Scoring\input\2505\D\DIW -> C:\Users\dra\project\HWP\HWP-Scoring\output\2505\D\DIW diff --git a/score.py b/score.py deleted file mode 100644 index acc99e6..0000000 --- a/score.py +++ /dev/null @@ -1,227 +0,0 @@ -import json -import xml.etree.ElementTree as ET -import os -from pathlib import Path -import pandas as pd -from datetime import datetime - -class XMLScorer: - def __init__(self, scoring_criteria_path): - """ - 채점 기준표 JSON 파일을 로드하여 초기화합니다. - - Args: - scoring_criteria_path (str): 채점 기준표 JSON 파일 경로 - """ - self.scoring_criteria = self._load_scoring_criteria(scoring_criteria_path) - - def _load_scoring_criteria(self, file_path): - """ - JSON 채점 기준표를 로드합니다. - - Args: - file_path (str): JSON 파일 경로 - - Returns: - dict: 채점 기준표 데이터 - """ - with open(file_path, 'r', encoding='utf-8') as f: - return json.load(f) - - def _find_element_value(self, root, element_name, attribute_name): - """ - XML에서 특정 요소와 속성값을 찾습니다. - - Args: - root (Element): XML 루트 요소 - element_name (str): 찾을 요소 이름 - attribute_name (str): 찾을 속성 이름 - - Returns: - str: 찾은 속성값 또는 None - """ - element = root.find(f".//{element_name}") - if element is not None: - return element.get(attribute_name) - return None - - def score_xml_file(self, xml_path): - """ - 단일 XML 파일을 채점합니다. - - Args: - xml_path (str): XML 파일 경로 - - Returns: - dict: 채점 결과 - """ - try: - tree = ET.parse(xml_path) - root = tree.getroot() - - total_score = 0 - results = { - 'filename': os.path.basename(xml_path), - 'criteria_matches': [], - 'total_score': 0 - } - - # 각 채점 기준에 대해 검사 - for criterion_id, criterion in self.scoring_criteria.items(): - element_name = criterion['ele'] - attribute_name = criterion['arg'] - expected_value = criterion['value'] - points = criterion['points'] - - actual_value = self._find_element_value(root, element_name, attribute_name) - - match = { - 'criterion': f"{element_name}.{attribute_name}", - 'expected': expected_value, - 'actual': actual_value, - 'points': 0 - } - - # 값이 일치하면 점수 부여 - if actual_value == expected_value: - total_score += points - match['points'] = points - - results['criteria_matches'].append(match) - - results['total_score'] = total_score - return results - - except ET.ParseError as e: - return { - 'filename': os.path.basename(xml_path), - 'error': f"XML 파싱 오류: {str(e)}", - 'total_score': 0 - } - - def export_to_excel(self, results, output_path=None): - """ - 채점 결과를 엑셀 파일로 저장합니다. - - Args: - results (list): 채점 결과 리스트 - output_path (str, optional): 출력 파일 경로. - None이면 현재 시간으로 파일명 생성 - - Returns: - str: 저장된 엑셀 파일 경로 - """ - if output_path is None: - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - output_path = f"scoring_results_{timestamp}.xlsx" - - # 요약 시트용 데이터 준비 - summary_data = [] - detail_data = [] - - for result in results: - # 요약 정보 - summary_row = { - '파일명': result['filename'], - '총점': result.get('total_score', 0) - } - if 'error' in result: - summary_row['오류'] = result['error'] - summary_data.append(summary_row) - - # 상세 정보 - if 'criteria_matches' in result: - for match in result['criteria_matches']: - detail_row = { - '파일명': result['filename'], - '채점항목': match['criterion'], - '기대값': match['expected'], - '실제값': match['actual'], - '획득점수': match['points'] - } - detail_data.append(detail_row) - - # DataFrame 생성 - summary_df = pd.DataFrame(summary_data) - detail_df = pd.DataFrame(detail_data) - - # ExcelWriter 객체 생성 - with pd.ExcelWriter(output_path, engine='openpyxl') as writer: - # 요약 시트 작성 - summary_df.to_excel(writer, sheet_name='채점결과요약', index=False) - - # 상세 시트 작성 - detail_df.to_excel(writer, sheet_name='채점상세내역', index=False) - - # 열 너비 자동 조정 - for sheet_name in writer.sheets: - worksheet = writer.sheets[sheet_name] - for column in worksheet.columns: - max_length = 0 - column = [cell for cell in column] - for cell in column: - try: - if len(str(cell.value)) > max_length: - max_length = len(str(cell.value)) - except: - pass - adjusted_width = (max_length + 2) - worksheet.column_dimensions[column[0].column_letter].width = adjusted_width - - return output_path - - - def score_directory(self, xml_directory): - """ - 디렉토리 내의 모든 XML 파일을 채점합니다. - - Args: - xml_directory (str): XML 파일들이 있는 디렉토리 경로 - - Returns: - list: 모든 파일의 채점 결과 - """ - results = [] - xml_files = Path(xml_directory).glob('*.xml') - - for xml_file in xml_files: - result = self.score_xml_file(str(xml_file)) - results.append(result) - - return results - -# 사용 예시 -def main(): - # 채점기준표 파일 경로 - scoring_criteria_path = "scoring_criteria.json" - # XML 파일들이 있는 디렉토리 경로 - xml_directory = r"C:\Users\gzero-ser7-win11\Documents\hwpTest\Output" - - # 채점기 초기화 - scorer = XMLScorer(scoring_criteria_path) - - # 디렉토리 내 모든 XML 파일 채점 - results = scorer.score_directory(xml_directory) - - # 결과 출력 - for result in results: - print(f"\n파일: {result['filename']}") - if 'error' in result: - print(f"오류: {result['error']}") - continue - - print(f"총점: {result['total_score']}") - print("\n채점 세부사항:") - for match in result['criteria_matches']: - print(f"기준: {match['criterion']}") - print(f"기대값: {match['expected']}") - print(f"실제값: {match['actual']}") - print(f"획득 점수: {match['points']}") - print("---") - - # 결과를 엑셀 파일로 저장 - excel_path = scorer.export_to_excel(results) - print(f"\n채점 결과가 다음 경로에 저장되었습니다: {excel_path}") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/score2.py b/score2.py deleted file mode 100644 index 65b82df..0000000 --- a/score2.py +++ /dev/null @@ -1,327 +0,0 @@ -import json -import xml.etree.ElementTree as ET -import os -from pathlib import Path -import pandas as pd -from datetime import datetime -from Levenshtein import distance as levenshtein_distance - -class XMLScorer: - def __init__(self, scoring_criteria_path): - """ - 채점 기준표 JSON 파일을 로드하여 초기화합니다. - - Args: - scoring_criteria_path (str): 채점 기준표 JSON 파일 경로 - """ - self.scoring_criteria = self._load_scoring_criteria(scoring_criteria_path) - # 오탈자 감점 설정 - self.typo_penalties = { - 'slight': 0.9, # 90% 점수 (약간의 오탈자) - 'moderate': 0.7, # 70% 점수 (중간 정도의 오탈자) - 'severe': 0.0 # 0% 점수 (심각한 오탈자) - } - - def _load_scoring_criteria(self, file_path): - """ - JSON 채점 기준표를 로드합니다. - - Args: - file_path (str): JSON 파일 경로 - - Returns: - dict: 채점 기준표 데이터 - """ - with open(file_path, 'r', encoding='utf-8') as f: - return json.load(f) - - def _calculate_similarity_score(self, str1, str2): - """ - 두 문자열 간의 유사도를 계산합니다. - - Args: - str1 (str): 첫 번째 문자열 - str2 (str): 두 번째 문자열 - - Returns: - float: 유사도 점수 (0.0 ~ 1.0) - """ - if str1 is None or str2 is None: - return 0.0 - - max_len = max(len(str1), len(str2)) - if max_len == 0: - return 1.0 - - distance = levenshtein_distance(str1, str2) - similarity = 1 - (distance / max_len) - return similarity - - def _get_penalty_factor(self, similarity): - """ - 유사도에 따른 감점 계수를 반환합니다. - - Args: - similarity (float): 유사도 점수 - - Returns: - float: 감점 계수 - """ - if similarity >= 0.9: - return self.typo_penalties['slight'] - elif similarity >= 0.7: - return self.typo_penalties['moderate'] - else: - return self.typo_penalties['severe'] - - def _find_best_matching_element(self, root, target_element): - """ - 가장 유사한 요소를 찾습니다. - - Args: - root (Element): XML 루트 요소 - target_element (str): 찾고자 하는 요소 이름 - - Returns: - tuple: (가장 유사한 요소, 유사도 점수) - """ - best_match = None - best_similarity = 0.0 - - for element in root.iter(): - similarity = self._calculate_similarity_score(element.tag, target_element) - if similarity > best_similarity: - best_similarity = similarity - best_match = element - - return best_match, best_similarity - - def _find_element_value(self, root, element_name, attribute_name): - """ - XML에서 특정 요소와 속성값을 찾습니다. 오탈자를 고려합니다. - - Args: - root (Element): XML 루트 요소 - element_name (str): 찾을 요소 이름 - attribute_name (str): 찾을 속성 이름 - - Returns: - tuple: (속성값, 요소 유사도, 속성 유사도) - """ - element, element_similarity = self._find_best_matching_element(root, element_name) - - if element is not None: - # 속성 중 가장 유사한 것을 찾음 - best_attr_value = None - best_attr_similarity = 0.0 - - for attr_name, attr_value in element.attrib.items(): - attr_similarity = self._calculate_similarity_score(attr_name, attribute_name) - if attr_similarity > best_attr_similarity: - best_attr_similarity = attr_similarity - best_attr_value = attr_value - - return best_attr_value, element_similarity, best_attr_similarity - - return None, 0.0, 0.0 - - def score_xml_file(self, xml_path): - """ - 단일 XML 파일을 채점합니다. - - Args: - xml_path (str): XML 파일 경로 - - Returns: - dict: 채점 결과 - """ - try: - tree = ET.parse(xml_path) - root = tree.getroot() - - total_score = 0 - results = { - 'filename': os.path.basename(xml_path), - 'criteria_matches': [], - 'total_score': 0 - } - - # 각 채점 기준에 대해 검사 - for criterion_id, criterion in self.scoring_criteria.items(): - element_name = criterion['ele'] - attribute_name = criterion['arg'] - expected_value = criterion['value'] - points = criterion['points'] - - # 오탈자를 고려하여 값을 찾음 - actual_value, element_similarity, attr_similarity = self._find_element_value( - root, element_name, attribute_name) - - # 값 유사도 계산 - value_similarity = self._calculate_similarity_score(str(actual_value), str(expected_value)) - - # 전체 유사도 계산 (요소, 속성, 값의 유사도를 종합) - total_similarity = (element_similarity + attr_similarity + value_similarity) / 3 - - # 감점 계수 계산 - penalty_factor = self._get_penalty_factor(total_similarity) - - match = { - 'criterion': f"{element_name}.{attribute_name}", - 'expected': expected_value, - 'actual': actual_value, - 'element_similarity': round(element_similarity, 3), - 'attribute_similarity': round(attr_similarity, 3), - 'value_similarity': round(value_similarity, 3), - 'total_similarity': round(total_similarity, 3), - 'penalty_factor': penalty_factor, - 'points': round(points * penalty_factor, 2) - } - - total_score += match['points'] - results['criteria_matches'].append(match) - - results['total_score'] = round(total_score, 2) - return results - - except ET.ParseError as e: - return { - 'filename': os.path.basename(xml_path), - 'error': f"XML 파싱 오류: {str(e)}", - 'total_score': 0 - } - - def score_directory(self, xml_directory): - """ - 디렉토리 내의 모든 XML 파일을 채점합니다. - - Args: - xml_directory (str): XML 파일들이 있는 디렉토리 경로 - - Returns: - list: 모든 파일의 채점 결과 - """ - results = [] - xml_files = Path(xml_directory).glob('*.xml') - - for xml_file in xml_files: - result = self.score_xml_file(str(xml_file)) - results.append(result) - - return results - - def export_to_excel(self, results, output_path=None): - """ - 채점 결과를 엑셀 파일로 저장합니다. - - Args: - results (list): 채점 결과 리스트 - output_path (str, optional): 출력 파일 경로 - """ - if output_path is None: - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - output_path = f"scoring_results_{timestamp}.xlsx" - - # 요약 시트용 데이터 준비 - summary_data = [] - detail_data = [] - - for result in results: - # 요약 정보 - summary_row = { - '파일명': result['filename'], - '총점': result.get('total_score', 0) - } - if 'error' in result: - summary_row['오류'] = result['error'] - summary_data.append(summary_row) - - # 상세 정보 - if 'criteria_matches' in result: - for match in result['criteria_matches']: - detail_row = { - '파일명': result['filename'], - '채점항목': match['criterion'], - '기대값': match['expected'], - '실제값': match['actual'], - '요소유사도': match['element_similarity'], - '속성유사도': match['attribute_similarity'], - '값유사도': match['value_similarity'], - '전체유사도': match['total_similarity'], - '감점계수': match['penalty_factor'], - '획득점수': match['points'] - } - detail_data.append(detail_row) - - # DataFrame 생성 - summary_df = pd.DataFrame(summary_data) - detail_df = pd.DataFrame(detail_data) - - # ExcelWriter 객체 생성 - with pd.ExcelWriter(output_path, engine='openpyxl') as writer: - summary_df.to_excel(writer, sheet_name='채점결과요약', index=False) - detail_df.to_excel(writer, sheet_name='채점상세내역', index=False) - - # 열 너비 자동 조정 - for sheet_name in writer.sheets: - worksheet = writer.sheets[sheet_name] - for column in worksheet.columns: - max_length = 0 - column = [cell for cell in column] - for cell in column: - try: - if len(str(cell.value)) > max_length: - max_length = len(str(cell.value)) - except: - pass - adjusted_width = (max_length + 2) - worksheet.column_dimensions[column[0].column_letter].width = adjusted_width - - return output_path - -# 메인 함수는 이전과 동일 - -# 사용 예시 -def main(): - # 채점기준표 파일 경로 - scoring_criteria_path = "scoring_criteria.json" - # XML 파일들이 있는 디렉토리 경로 - xml_directory = r"C:\Users\gzero-ser7-win11\Documents\hwpTest\Output" - - # 채점기 초기화 - scorer = XMLScorer(scoring_criteria_path) - - # 디렉토리 내 모든 XML 파일 채점 - results = scorer.score_directory(xml_directory) - - # 결과 출력 - for result in results: - print(f"\n파일: {result['filename']}") - if 'error' in result: - print(f"오류: {result['error']}") - continue - - print(f"총점: {result['total_score']}") - print("\n채점 세부사항:") - for match in result['criteria_matches']: - print(f"기준: {match['criterion']}") - print(f"기대값: {match['expected']}") - print(f"실제값: {match['actual']}") - print(f"획득 점수: {match['points']}") - print("---") - - # 결과를 엑셀 파일로 저장 - excel_path = scorer.export_to_excel(results) - print(f"\n채점 결과가 다음 경로에 저장되었습니다: {excel_path}") - -if __name__ == "__main__": - main() - - - - - - - - - diff --git a/score3.py b/score3.py deleted file mode 100644 index aed92be..0000000 --- a/score3.py +++ /dev/null @@ -1,304 +0,0 @@ -import json -import xml.etree.ElementTree as ET -import os -from pathlib import Path -import pandas as pd -from datetime import datetime -from difflib import SequenceMatcher -import re - - -class XMLScorer: - # 채점 기준 경로 초기화 - def __init__(self, scoring_criteria_path): - # 채점 기준 로드 - self.scoring_criteria = self._load_scoring_criteria(scoring_criteria_path) - print(self.scoring_criteria) - - # 채점 기준파일 로드(JSON 파일) - def _load_scoring_criteria(self, file_path): - with open(file_path, 'r', encoding='utf-8') as f: - return json.load(f) - - def _calculate_string_similarity(self, str1, str2): - """ - 두 문자열 간의 유사도를 계산합니다. - - Args: - str1 (str): 첫 번째 문자열 - str2 (str): 두 번째 문자열 - - Returns: - float: 유사도 (0~1 사이의 값) - """ - return SequenceMatcher(None, str1, str2).ratio() - - def _count_differences(self, str1, str2): - """ - 두 문자열 간의 차이(오탈자, 띄어쓰기)를 계산합니다. - - Args: - str1 (str): 첫 번째 문자열 (기준값) - str2 (str): 두 번째 문자열 (비교값) - - Returns: - tuple: (전체 차이 개수, 띄어쓰기 차이 개수) - """ - # 띄어쓰기 차이 계산 - space_diff = abs(str1.count(' ') - str2.count(' ')) - - # 전체 글자 차이 계산 (Levenshtein 거리 기반) - total_diff = 0 - m, n = len(str1), len(str2) - dp = [[0] * (n + 1) for _ in range(m + 1)] - - for i in range(m + 1): - dp[i][0] = i - for j in range(n + 1): - dp[0][j] = j - - for i in range(1, m + 1): - for j in range(1, n + 1): - if str1[i-1] == str2[j-1]: - dp[i][j] = dp[i-1][j-1] - else: - dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1 - - total_diff = dp[m][n] - - return total_diff, space_diff - - def _find_similar_element(self, root, target_element): - """ - 유사한 요소를 찾습니다. 완전 일치하지 않더라도 비슷한 이름의 요소를 찾습니다. - - Args: - root (Element): XML 루트 요소 - target_element (str): 찾고자 하는 요소 이름 - - Returns: - Element: 가장 유사한 요소 또는 None - """ - best_match = None - best_similarity = 0.7 # 최소 유사도 임계값 - - for element in root.iter(): - similarity = self._calculate_string_similarity(element.tag, target_element) - if similarity > best_similarity: - best_similarity = similarity - best_match = element - - return best_match - - def _find_element_value(self, root, element_name, attribute_name): - """ - XML에서 특정 요소와 속성값을 찾습니다. 유사한 요소도 고려합니다. - - Args: - root (Element): XML 루트 요소 - element_name (str): 찾을 요소 이름 - attribute_name (str): 찾을 속성 이름 - - Returns: - tuple: (찾은 속성값 또는 None, 요소 이름 오탈자 여부) - """ - # 정확한 요소 찾기 - element = root.find(f".//{element_name}") - - # 정확한 요소가 없으면 유사한 요소 찾기 - if element is None: - element = self._find_similar_element(root, element_name) - - if element is not None: - # 속성값 찾기 - value = element.get(attribute_name) - # 요소 이름이 정확히 일치하는지 확인 - has_typo = element.tag != element_name - return value, has_typo - - return None, False - - # XML 파일 채점 - def score_xml_file(self, xml_path): - try: - tree = ET.parse(xml_path) - root = tree.getroot() - - total_score = 0 - # 결과값을 Dictionary로 저장 - results = { - 'filename': os.path.basename(xml_path), - 'criteria_matches': [], # 채점 항목별 결과 - 'total_score': 0, - 'deductions': [] # 감점 상세 내역 추가 - } - - for criterion_id, criterion in self.scoring_criteria.items(): - element_name = criterion['ele'] - attribute_name = criterion['arg'] - expected_value = criterion['value'] - points = criterion['points'] - - actual_value, has_element_typo = self._find_element_value( - root, element_name, attribute_name) - - # 채점 결과 저장 - match = { - 'criterion': f"{element_name}.{attribute_name}", # 채점 항목 - 'expected': expected_value, # 기대값 - 'actual': actual_value, # 실제값 - 'points': 0, # 획득 점수 - 'deductions': [] # 각 기준별 감점 내역 - } - - if actual_value is not None: - # 기본 점수 부여 - match['points'] = points - - # 요소 이름에 오탈자가 있는 경우 - if has_element_typo: - deduction = 1 - match['points'] -= deduction - match['deductions'].append( - f"요소 이름 오탈자 감점: -{deduction}점") - - # 속성값 비교 및 차이 계산 - if actual_value != expected_value: - total_diff, space_diff = self._count_differences( - expected_value, actual_value) - - # 띄어쓰기 차이당 1점 감점 - if space_diff > 0: - match['points'] -= space_diff - match['deductions'].append( - f"띄어쓰기 오류 감점: -{space_diff}점") - - # 나머지 차이(오탈자)당 1점 감점 - char_diff = total_diff - space_diff - if char_diff > 0: - match['points'] -= char_diff - match['deductions'].append( - f"글자 오류 감점: -{char_diff}점") - - # 음수 점수 방지 - match['points'] = max(0, match['points']) - - results['criteria_matches'].append(match) - total_score += match['points'] - - results['total_score'] = total_score - return results - - except ET.ParseError as e: - return { - 'filename': os.path.basename(xml_path), - 'error': f"XML 파싱 오류: {str(e)}", - 'total_score': 0 - } - - def export_to_excel(self, results, output_path=None): - if output_path is None: - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - output_path = f"scoring_results_{timestamp}.xlsx" - - summary_data = [] - detail_data = [] - - for result in results: - # 요약 정보 - summary_row = { - '파일명': result['filename'], - '총점': result.get('total_score', 0) - } - if 'error' in result: - summary_row['오류'] = result['error'] - summary_data.append(summary_row) - - # 상세 정보 - if 'criteria_matches' in result: - for match in result['criteria_matches']: - detail_row = { - '파일명': result['filename'], - '채점항목': match['criterion'], - '기대값': match['expected'], - '실제값': match['actual'], - '획득점수': match['points'], - '감점내역': '; '.join(match.get('deductions', [])) - } - detail_data.append(detail_row) - - # DataFrame 생성 - summary_df = pd.DataFrame(summary_data) - detail_df = pd.DataFrame(detail_data) - - # ExcelWriter 객체 생성 - with pd.ExcelWriter(output_path, engine='openpyxl') as writer: - summary_df.to_excel(writer, sheet_name='채점결과요약', index=False) - detail_df.to_excel(writer, sheet_name='채점상세내역', index=False) - - # 열 너비 자동 조정 - for sheet_name in writer.sheets: - worksheet = writer.sheets[sheet_name] - for column in worksheet.columns: - max_length = 0 - column = [cell for cell in column] - for cell in column: - try: - if len(str(cell.value)) > max_length: - max_length = len(str(cell.value)) - except: - pass - adjusted_width = (max_length + 2) - worksheet.column_dimensions[column[0].column_letter].width = adjusted_width - - return output_path - - def score_directory(self, xml_directory): - results = [] - # xml_files = Path(xml_directory).glob('*.xml') - xml_files = Path(xml_directory).glob('*.hml') - - for xml_file in xml_files: - result = self.score_xml_file(str(xml_file)) - results.append(result) - - return results - -# 사용 예시 -def main(): - # 채점기준표 파일 경로 - scoring_criteria_path = "scoring_criteria.json" - # XML 파일들이 있는 디렉토리 경로 - # xml_directory = r"C:\Users\gzero-ser7-win11\Documents\hwpTest\Output" - xml_directory = r"C:\Users\dra\project\HWP-Scoring\output" - - # 채점기 초기화 - scorer = XMLScorer(scoring_criteria_path) - - # 디렉토리 내 모든 XML 파일 채점 - results = scorer.score_directory(xml_directory) - - # 결과 출력 - for result in results: - print(f"\n파일: {result['filename']}") - if 'error' in result: - print(f"오류: {result['error']}") - continue - - print(f"총점: {result['total_score']}") - print("\n채점 세부사항:") - for match in result['criteria_matches']: - print(f"기준: {match['criterion']}") - print(f"기대값: {match['expected']}") - print(f"실제값: {match['actual']}") - print(f"획득 점수: {match['points']}") - print("---") - - # 결과를 엑셀 파일로 저장 - excel_path = scorer.export_to_excel(results) - print(f"\n채점 결과가 다음 경로에 저장되었습니다: {excel_path}") - -if __name__ == "__main__": - main() - - diff --git a/score4.py b/score4.py deleted file mode 100644 index 1bf6b89..0000000 --- a/score4.py +++ /dev/null @@ -1,50 +0,0 @@ -from lxml import etree -from difflib import SequenceMatcher - -def get_all_text_xml_file(root): - # all_text = root.xpath("//CHAR/text() | //TEXTART/@Text") - all_text = root.xpath("//CHAR/text()") - print(f'all_text length: {len(all_text)}') - return all_text - -def find_typos_and_spaces(original, target): - typos = [] - spaces = [] - space_differences = 0 - - for text in original: - # 오타 검사 - words = text.split() - for word in words: - if not any(SequenceMatcher(None, word, target_word).ratio() >= 0.9 for target_word in target): - typos.append(word) - - # 공백 차이 검사 - for orig_text, targ_text in zip(original, target): - min_length = min(len(orig_text), len(targ_text)) - orig_text = orig_text[:min_length] - targ_text = targ_text[:min_length] - orig_spaces = orig_text.count(' ') - targ_spaces = targ_text.count(' ') - space_differences += abs(orig_spaces - targ_spaces) - - print(f'space_differences : {space_differences}') - - return typos, spaces - -# XML 파일 파싱 -original_file = r"C:\Users\dra\project\HWP-Scoring\output\워드(한글)-010128-윤빈.hml" -target_file = r"C:\Users\dra\project\HWP-Scoring\output\워드(한글)-009939-이준.hml" -# target_file = r"C:\Users\dra\project\HWP-Scoring\output\원본 copy.hml" - -tree = etree.parse(original_file) -root = tree.getroot() -original_text = get_all_text_xml_file(root) - -tree = etree.parse(target_file) -root = tree.getroot() -target_text = get_all_text_xml_file(root) - -typos, spaces = find_typos_and_spaces(original_text, target_text) -# print(f'Typos: {typos}') -# print(f'Spaces: {spaces}') \ No newline at end of file diff --git a/score5.py b/score5.py deleted file mode 100644 index df65cc2..0000000 --- a/score5.py +++ /dev/null @@ -1,580 +0,0 @@ -import tkinter as tk -from tkinter import filedialog, messagebox -from datetime import datetime -import difflib -import json -from pathlib import Path -import os -from lxml import etree as ET -import re -from difflib import SequenceMatcher -import pandas as pd -import base64 -# from xpathSearch import XMLPathHandler - -class XMLScorer: - # 채점 기준 경로 초기화 - def __init__(self, scoring_criteria_path): - # 채점 기준 로드 - self.scoring_criteria = self._load_scoring_criteria(scoring_criteria_path) - - def set_typo_score(self, score): - self.typo_score = score - - def get_typo_score(self): - return self.typo_score - - # 채점 기준파일 로드(JSON 파일) - def _load_scoring_criteria(self, file_path): - with open(file_path, 'r', encoding='utf-8') as f: - return json.load(f) - - # XML 파일에서 element의 값을 찾아 반환 - def query_xml(self, root, *args): - first_xpath = args[0] - second_xpath = args[1] - points = args[2] - category = args[3] - - if ("특수문자" in category) and (second_xpath is not None): - try: - result = root.xpath(first_xpath) - # 결과값이 리스트형인데 내부에 정보가 없는경우 - # 결과값이 없음 - if type(result) is list and len(result) == 0: - return None - elif result < points: - result = root.xpath(second_xpath) - return result - else: - return result - - except ET.XPathEvalError as e: - return None - - elif second_xpath is not None: - try: - result1 = root.xpath(first_xpath) - result2 = root.xpath(second_xpath) - if (type(result1) is list and len(result1) == 0) and (type(result2) is list and len(result2) == 0): - return None - return result1 if result1 else result2 - - except ET.XPathEvalError as e: - return None - - else: - try: - result = root.xpath(first_xpath) - if type(result) is list and len(result) == 0: - return None - return result - except ET.XPathEvalError as e: - return None - - def chart_query_xml(self, tree, xpath, namespaces): - - result = tree.xpath(xpath, namespaces=namespaces) - if type(result) is list and len(result) == 0: - return None - - return result - - - # 유사한 텍스트 찾기 - def find_similar_text(self, root, target_text, threshold=0.7): - """ - 전체 문서에서 유사한 텍스트를 찾아 반환 - - Args: - root (_type_): xml root element 객체 - target_text (_type_): 찾을 텍스트 - threshold (float, optional): 유사도 설정 Defaults to 0.3. - - Returns: - str: 유사도 기준을 만족하는 텍스트 - """ - # 전체 텍스트 추출 - # all_text = root.xpath(f"//CHAR/text()") - # all_text.append(root.xpath(f"//TEXTART/@text")) - - namespaces = { - 'a': 'http://schemas.openxmlformats.org/drawingml/2006/main', - 'c': 'http://schemas.openxmlformats.org/drawingml/2006/chart' - } - - all_text = root.xpath(f"//BODY//text() | //TEXTART/@Text | //c:chart//text()", namespaces=namespaces) - - # 유사도 비교 - max_score = 0 - similar_text = '' - - for text in all_text: - score = SequenceMatcher(None, target_text, text).ratio() - - if score > max_score: - max_score = score - similar_text = text - - if max_score >= threshold: - return similar_text - else: - return None - - # 하나의 XML 파일 채점 - def _score_xml_file(self, xml_path, chart_xml): - try: - tree = ET.parse(xml_path) - root = tree.getroot() - - # 네임스페이스 정의 - namespaces = { - 'a': 'http://schemas.openxmlformats.org/drawingml/2006/main', - 'c': 'http://schemas.openxmlformats.org/drawingml/2006/chart' - } - - # 차트 XML 파일이 없는 경우 0점 채점을 위헤 빈 XML 생성 - if chart_xml is None: - chart_tree = ET.fromstring('') - else: - chart_tree = ET.fromstring(chart_xml) - - total_score = 0 - partial_score = 0 - previous_first_digit = None - - # 결과값을 Dictionary로 저장 - results = { - 'filename': os.path.basename(xml_path), - 'score_results': [], - 'total_score': 0, - 'partial_scores': [] - } - - print(f"File name: {results['filename']}") - - for criterion_id, criterion in self.scoring_criteria.items(): - - # 키값의 첫 숫자를 확인 - first_digit = criterion_id.split('-')[0] - if (previous_first_digit is not None) and (first_digit != previous_first_digit): - results['partial_scores'].append({ - 'section': previous_first_digit, - 'score': partial_score - }) - partial_score = 0 - - previous_first_digit = first_digit - - id = criterion_id - xpath = criterion['path'] if 'path' in criterion else None - xpath2 = criterion['path2'] if 'path2' in criterion else None - search_value = criterion['searchValue'] if 'searchValue' in criterion else None - right_answer = criterion['value'] if 'value' in criterion else None - points = criterion['points'] if 'points' in criterion else None - category = criterion['category'] - item = criterion['item'] - similar_text = None - - # chart xml 파일에서 채점하는 경우 - if "chart_xml" in category: - if search_value is not None: - similar_text = self.find_similar_text(chart_tree, search_value) - if similar_text is None: - xpath = xpath.replace('{searchValue}', search_value) - else: - xpath = xpath.replace('{searchValue}', similar_text) - - result = self.chart_query_xml(chart_tree, xpath, namespaces) - - # 그 외의 hml 파일에서 채점하는 경우 - else: - if search_value is not None: - similar_text = self.find_similar_text(root, search_value) - if similar_text is None: - xpath = xpath.replace('{searchValue}', search_value) - else: - xpath = xpath.replace('{searchValue}', similar_text) - - result = self.query_xml(root, xpath, xpath2, points, category) - - # [ boolean 타입 ] - # 1. 이텔릭체, 굵게, 밑줄 등 효과가 적용 여부에 따라 - # [ITALIC] [BOLD] [UNDERLINE] 태그가 있거나 없을 수 있으므로 - # 존재 유무에 따라 True, False로 판단 - # 2. 두 가지 이상의 조건을 모두 만족해야 하는 경우 and 연산자로 연결되어 - # 반환값 True/False로 판단 - # [ float 타입 ] - # 1. 부분점수의 합산으로 반환되는 경우 float 타입으로 반환 - if type(result) is not list: - if type(result) is float and (result > points): - actual_answer = float(points) - else: - actual_answer = result - else: - if type(right_answer) is int: - actual_answer = int(result[0]) - else: - actual_answer = result[0] - - if "오타감점" in category: - points = self.get_typo_score() - - scoring = { - 'id': id, - 'category': category, # 채점 분류 - 'item': item, # 채점 항목 - 'right_answer': right_answer, # 정답 - 'actual_answer': actual_answer, # 실제 작성 답안 - 'points': points, - 'deductions': [] # 각 기준별 감점 내역 - } - - # 점수 차감 조건 - # 1. 정답이 실수형으로 반환받은 경우는 채점항목의 부분점수 합산 결과이므로 - # 반환받은 값 그대로를 점수로 사용 - # 2. 정답이 정수형(사이즈 비교)의 경우 오차범위를 넘는다면 감점 - # 3. 그 외의 경우 정답과 실제 작성 답안이 다른 경우 점수 차감 - if type(actual_answer) is float: - scoring['points'] = actual_answer - - elif type(actual_answer) is int: - # 오차범위 3 이상이면 감점 - if abs(actual_answer - right_answer) > 3: - scoring['points'] -= points - else: - # right_answer(JSON파일 내 valuer값) null일 경우 점수감점 없이 진행 - if right_answer != actual_answer: - scoring['points'] -= points - - - # 점수 차감 이유 작성 (개발중) - results['score_results'].append(scoring) - total_score += scoring['points'] - partial_score += scoring['points'] - - print(f'scoring: {scoring}') - - results['total_score'] = total_score - - if previous_first_digit is not None: - results['partial_scores'].append({ - 'section': previous_first_digit, - 'score': partial_score - }) - - return results - - except ET.ParseError as e: - return { - 'filename': os.path.basename(xml_path), - 'error': f"XML 파싱 오류: {str(e)}", - 'total_score': 0 - } - - def binary_to_chartxml(self, xml_path): - tree = ET.parse(xml_path) - root = tree.getroot() - - binary_data = root.xpath('//BINDATA[@Id=//BINITEM[@Format="OLE"]/@BinData]/text()') - if not binary_data: - return None - binary_data = binary_data[0].encode('utf-8') - - # 태그와 그 내부 내용을 삭제합니다. - encoded_data = re.sub(b'', b'', binary_data) - encoded_data = encoded_data.replace(b'', b'') - encoded_data = encoded_data.replace(b'\r\n', b'') - - # base64 디코딩을 수행합니다. - decoded_data = base64.b64decode(encoded_data+b'==') - - # 디코딩된 데이터 내용 중 xml 형식만 추출할 때 , 사이의 데이터만 추출. - start = decoded_data.find(b'') - print(end) - xml_data = decoded_data[start:end+len(b'')] - - # xml 데이터가 없는 경우 None을 반환합니다. - if -1 in [start, end]: - return None - - # 디코딩된 데이터를 파일로 저장합니다. - base_filename = os.path.splitext(xml_path)[0] - new_filename = f'{base_filename}.xml' - with open(new_filename, 'wb') as file: - file.write(xml_data) - - return xml_data - - def typo_check(self, correct_answer_file, user_answer_file): - user_answer_tree = ET.parse(user_answer_file) - user_answer_root = user_answer_tree.getroot() - correct_answer_tree = ET.parse(correct_answer_file) - correct_answer_root = correct_answer_tree.getroot() - - # xpath로 바이너리 부분추출 - user_input_text = user_answer_root.xpath('//CHAR//text()[not(ancestor::HEADER) and not(ancestor::TABLE)]') - user_table_text = user_answer_root.xpath('//TABLE//CHAR//text()') - user_input_text += user_table_text - - correct_input_text = correct_answer_root.xpath('//CHAR//text()[not(ancestor::HEADER) and not(ancestor::TABLE)]') - correct_table_text = correct_answer_root.xpath('//TABLE//CHAR//text()') - correct_input_text += correct_table_text - - # 각 요소에서 공백 제거 - user_input_text = [text.replace(' ', '') for text in user_input_text] - correct_input_text = [text.replace(' ', '') for text in correct_input_text] - - - # 숫자와 특정 형식 제거 (예: 1., 2., 3., -) - user_input_text = [re.sub(r'\d+\.\s*|-', '', text) for text in user_input_text] - correct_input_text = [re.sub(r'\d+\.\s*|-', '', text) for text in correct_input_text] - - ignore_word = self.scoring_criteria["2-29"]['path'].split("'")[1] - print(f"ignore_word: {ignore_word}") - # 특정 단어 제거 - # 오타와 누락의 경우만 판단하면 정상작동하지만 - # 추가 된 단어의 경우를 채점기준에 추가하면 정확하게 채점 되지 않을 수 있음 - # [정답] Hybrid [실제작성] - user_input_text = [text.replace(ignore_word, '') for text in user_input_text] - correct_input_text = [text.replace(ignore_word, '') for text in correct_input_text] - - # 리스트를 하나의 문자열로 변경 - user_input_text_str = ''.join(user_input_text) - currect_input_text_str = ''.join(correct_input_text) - - print("user_input_text as string:") - print(user_input_text_str) - print("\ncurrect_input_text_answer as string:") - print(currect_input_text_str) - - - # 문자열의 차이를 비교 - diff = difflib.ndiff(currect_input_text_str, user_input_text_str) - diff_list = list(diff) - - # 차이점을 정리하여 result_diff에 저장 - result_diff = [] - - # 누락 된 단어만 따로 리스트로 저장 - missing_list = [] - - # 오타와 누락된 단어 리스트 저장 - error_missing_list = [] - - skip_next = False - - for i, line in enumerate(diff_list): - if skip_next: - skip_next = False - continue - # diff_list의 line 시작이 '-'이면서 다음 line이 '+'이면 두 line을 붙여서 맞춤법이 틀린 단어로 판단 - if line.startswith('- '): - # 오타 - if i + 1 < len(diff_list) and diff_list[i + 1].startswith('+ '): - line = line.replace('- ', '-') - next = diff_list[i + 1].replace('+ ', '') - result_diff.append(line+'=>'+next) - error_missing_list.append(line+'=>'+next) - skip_next = True - # 누락 - else: - line = line.replace('- ', '-') - result_diff.append(line) - missing_list.append(line) - error_missing_list.append(line) - # 없어도 되는 글자가 있는 경우 (추가) - elif line.startswith('+ '): - line = line.replace('+ ', '+') - result_diff.append(line) - - # result_diff 출력 - # print("\nResult Differences:") - # for diff in result_diff: - # print(diff) - - # result_diff 배열의 길이를 맨 앞에 저장 - - # 모든 차이를 계산해 점수 차감 - # temp = 40 - min(len(result_diff)*2, 40) - - # 누락된 텍스트만 계산해 점수 차감 - # temp = 40 - min(len(missing_list)*2, 40) - - # 2503회 기준 오타 1개당 [2점]->[1점] 차감 - temp = 40 - min(len(error_missing_list)*1, 40) - - self.set_typo_score(temp) - - result_diff.insert(0, temp) - return result_diff - - # XML 파일 채점 - def score_directory(self, xml_directory, correct_answer_file): - # xml 파일 불러오기 - xml_files = Path(xml_directory).glob('*.hml') - - # 결과 저장할 리스트 - results = [] - - for user_answer_file in xml_files: - result = {} - chart_xml = self.binary_to_chartxml(user_answer_file) - result['typo'] = self.typo_check(correct_answer_file, user_answer_file) - result['score'] = self._score_xml_file(user_answer_file, chart_xml) - # result['score']['score_results'][2]['points'] = result['typo'][0] - results.append(result) - return results - - def parse_filename(self, filename): - if isinstance(filename, dict): - filename = filename.get('파일명', '') - match = re.match(r'.*-(\d+)-(.+)\.hml', filename) - if match: - number = match.group(1) - name = match.group(2) - return number, name - - return None, None - - def export_to_excel(self, results, output_path=None): - if output_path is None: - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") #연월일_시분초 - # timestamp = datetime.now().strftime("%Y%m%d") #연월일 - output_path = f"scoring_results_{timestamp}.xlsx" - - summary_data = [] - detail_data = [] - typo_data = [] - - for temp in results: - # 요약 정보 - result = temp['score'] - summary_row = { - '파일명': result['filename'], - '총점': result.get('total_score', 0) - } - if 'error' in result: - summary_row['오류'] = result['error'] - - summary_data.append(summary_row) - - # 상세 정보 - if 'score_results' in result: - filename = {'파일명': result['filename']} - number, name = self.parse_filename(filename) - if (number or name) is None: - detail_row = {'채점항목': result['filename'] } - else: - detail_row = {'채점항목':f"{number}-{name}"} - - section_num = None - partial_idx = 0 - row_index = [] - for i, score_result in enumerate(result['score_results']): - current_section = int(score_result['id'].split('-')[0]) - - if section_num is None: - section_num = current_section - - # 다음 섹션(페이지)로 넘어갔을 경우 - if current_section != section_num: - # 이전 섹션의 부분합을 출력 - detail_row[f'문제{section_num}'] = result['partial_scores'][partial_idx]['score'] - row_index.append(f'문제{section_num}') - partial_idx += 1 - section_num = current_section - - detail_row[f'{i+1}'] = score_result['points'] - row_index.append(score_result['id']) - - # 마지막 섹션의 부분합을 출력 - if section_num is not None and partial_idx < len(result['partial_scores']): - detail_row[f'문제{section_num}'] = result['partial_scores'][partial_idx]['score'] - row_index.append(f'문제{section_num}') - - detail_row['총점'] = result.get('total_score', 0) - row_index.append('총점') - detail_data.append(detail_row) - - summary_df = pd.DataFrame(summary_data) - detail_df = pd.DataFrame(detail_data).transpose() - detail_df.columns = detail_df.iloc[0] - detail_df = detail_df[1:] - - detail_df.index = row_index - # detail_df = pd.DataFrame(detail_data) - - for temp in results: - result = temp['typo'] - typo_data.append(result) - - typo_df = pd.DataFrame(typo_data).transpose() - # detail_df = pd.DataFrame(detail_data) - - # ExcelWriter 객체 생성 - with pd.ExcelWriter(output_path, engine='openpyxl') as writer: - summary_df.to_excel(writer, sheet_name='채점결과요약', index=False) - detail_df.to_excel(writer, sheet_name='채점상세내역', index=True) - typo_df.to_excel(writer, sheet_name='오타내역', index=False) - - # 열 너비 자동 조정 - # for sheet_name in writer.sheets: - # worksheet = writer.sheets[sheet_name] - # for column_cells in worksheet.columns: - # max_length = 0 - # column = column_cells[0].column_letter # 열의 문자 - # for cell in column_cells: - # try: - # if cell.value: - # max_length = max(max_length, len(str(cell.value))) - # except: - # pass - # adjusted_width = (max_length + 2) - # worksheet.column_dimensions[column].width = adjusted_width - - return output_path - - -def main(): - - # 시험회차 및 유형 - exam_round = '2503' - exam_types = [ - 'A', - # 'B', - # 'C', - ] - # test_mode = False - test_mode = True - - output_excel_paths = [] - for exam_type in exam_types: - scoring_criteria_path = f'./DIW_{exam_round}{exam_type}.json' - # xml(hml)파일 디렉토리 경로 - - xml_directory = f'./output/{exam_type}/{"TEST" if test_mode else "DIW"}' - - - # 오탈자 체크를 위한 정답 파일 경로 (형식:DIW_2503A.hml) - correct_answer_file = f'./output/{exam_type}/DIW/DIW_{exam_round}{exam_type}.hml' - - # 엑셀 파일명 (비어있으면 자동생성) - timestamp = datetime.now().strftime("%y%m%d") - output_path = f'{timestamp}_DIW_{exam_round}{exam_type}_{"TEST" if test_mode else "채점결과"}.xlsx' - - # 채점 클래스 초기화 - scorer = XMLScorer(scoring_criteria_path) - - # 폴더 내 모든 xml 파일 채점 - results = scorer.score_directory(xml_directory, correct_answer_file) - - # 채점 결과 엑셀로 저장 - output_excel_paths.append(scorer.export_to_excel(results, output_path)) - - print(f"채점 결과 엑셀 파일: {output_excel_paths}") - -if __name__ == '__main__': - main() diff --git a/250522_DIW_2504회_A형_채점결과.xlsx b/회차별채점자료/2504/excel_채점결과/250522_DIW_2504회_A형_채점결과.xlsx similarity index 100% rename from 250522_DIW_2504회_A형_채점결과.xlsx rename to 회차별채점자료/2504/excel_채점결과/250522_DIW_2504회_A형_채점결과.xlsx diff --git a/250522_DIW_2504회_B형_채점결과.xlsx b/회차별채점자료/2504/excel_채점결과/250522_DIW_2504회_B형_채점결과.xlsx similarity index 100% rename from 250522_DIW_2504회_B형_채점결과.xlsx rename to 회차별채점자료/2504/excel_채점결과/250522_DIW_2504회_B형_채점결과.xlsx diff --git a/250522_DIW_2504회_C형_채점결과.xlsx b/회차별채점자료/2504/excel_채점결과/250522_DIW_2504회_C형_채점결과.xlsx similarity index 100% rename from 250522_DIW_2504회_C형_채점결과.xlsx rename to 회차별채점자료/2504/excel_채점결과/250522_DIW_2504회_C형_채점결과.xlsx diff --git a/250523_DIW_2504회_A형_채점결과.xlsx b/회차별채점자료/2504/excel_채점결과/250523_DIW_2504회_A형_채점결과.xlsx similarity index 100% rename from 250523_DIW_2504회_A형_채점결과.xlsx rename to 회차별채점자료/2504/excel_채점결과/250523_DIW_2504회_A형_채점결과.xlsx diff --git a/250523_DIW_2504회_B형_채점결과.xlsx b/회차별채점자료/2504/excel_채점결과/250523_DIW_2504회_B형_채점결과.xlsx similarity index 100% rename from 250523_DIW_2504회_B형_채점결과.xlsx rename to 회차별채점자료/2504/excel_채점결과/250523_DIW_2504회_B형_채점결과.xlsx diff --git a/250523_DIW_2504회_C형_채점결과.xlsx b/회차별채점자료/2504/excel_채점결과/250523_DIW_2504회_C형_채점결과.xlsx similarity index 100% rename from 250523_DIW_2504회_C형_채점결과.xlsx rename to 회차별채점자료/2504/excel_채점결과/250523_DIW_2504회_C형_채점결과.xlsx diff --git a/구버전신버전점수비교A형.xlsx b/회차별채점자료/2504/excel_채점결과/구버전신버전점수비교A형.xlsx similarity index 100% rename from 구버전신버전점수비교A형.xlsx rename to 회차별채점자료/2504/excel_채점결과/구버전신버전점수비교A형.xlsx diff --git a/구버전신버전점수비교B형.xlsx b/회차별채점자료/2504/excel_채점결과/구버전신버전점수비교B형.xlsx similarity index 100% rename from 구버전신버전점수비교B형.xlsx rename to 회차별채점자료/2504/excel_채점결과/구버전신버전점수비교B형.xlsx diff --git a/구버전신버전점수비교C형.xlsx b/회차별채점자료/2504/excel_채점결과/구버전신버전점수비교C형.xlsx similarity index 100% rename from 구버전신버전점수비교C형.xlsx rename to 회차별채점자료/2504/excel_채점결과/구버전신버전점수비교C형.xlsx diff --git a/회차별채점자료/2504/json_채점기준표/0522/DIW_2504A.json b/회차별채점자료/2504/json_채점기준표/0522/DIW_2504A.json index c688cba..0604868 100644 --- a/회차별채점자료/2504/json_채점기준표/0522/DIW_2504A.json +++ b/회차별채점자료/2504/json_채점기준표/0522/DIW_2504A.json @@ -412,8 +412,7 @@ "value": "견고딕", "points": 1, "category": "FontName", - "item": "문구 (클라우드 컴퓨팅)/⑧ 글씨체 (견고딕)", - "desc": "폰트 '견고딕'과 '중고딕'은 한글프로그램 내부적으로 '한양견고딕', '한양중고딕'처리 되어서 프로그램 내부에서 수험자 답변에서 '한양'을 제거하는 과정을 거침" + "item": "문구 (클라우드 컴퓨팅)/⑧ 글씨체 (견고딕)" }, "12": { "path": "//CHARSHAPE[@Id=//RECTANGLE//TEXT[./CHAR[text()='{searchValue}']]/@CharShape]/@Height", @@ -445,14 +444,14 @@ "value": "80", "points": 2, "category": "mmSize", - "item": "② 크기-너비 (80mm)" + "item": "② 크기-너비 (80 mm)" }, "16": { "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/SIZE/@Height", "value": "45", "points": 2, "category": "mmSize", - "item": "③ 크기-높이 (45mm)" + "item": "③ 크기-높이 (45 mm)" }, "17": { "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/POSITION/@HorzOffset", @@ -599,7 +598,7 @@ "item": "문구 (…유출과 데이터 사이버…)/\"유출과\" / \"데이터\" 순서바꿈" }, "33": { - "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", + "path": "//TEXT[CHAR[contains(text(),'{searchValue}')]]/@CharShape", "searchValue": "클라우드 보안(단위: 백만 달러)", "value": "돋움", "points": 1, @@ -702,7 +701,7 @@ "points": 2, "category": "ChartType", "item": "① 종류 (묶은 세로 막대형)", - "desc": "chart_type을 입력받아 차트타입에 맞는 xml요소가 있는지 내부적으로 검사, chart_type만 한글로 입력해주면 된다." + "desc": "chart_type을 입력받아 차트타입에 맞는 xml요소가 있는지 내부적으로 검사, chart_type만 한글로 입력해주면 된다. (공백무시)" }, "46": { "chart_xpath": "//c:valAx/c:majorTickMark/@val", @@ -717,14 +716,14 @@ "value": "80", "points": 2, "category": "mmSize", - "item": "③ 크기-너비 (80mm)" + "item": "③ 크기-너비 (80 mm)" }, "48": { "path": "//OLE[@BinItem=//BINITEM[@Format='OLE']/@BinData]//SIZE/@Height", "value": "90", "points": 2, "category": "mmSize", - "item": "④ 크기-높이 (90mm)" + "item": "④ 크기-높이 (90 mm)" }, "49": { "chart_xpath": "boolean(//c:chart and not(//c:pt[not(ancestor::c:tx)]/c:v[text()='합계' or text()='평균']))", @@ -764,14 +763,14 @@ "chart_xpath": "//c:catAx/c:txPr//a:ea/@typeface", "value": "돋움", "points": 1, - "category": "OneAnswer", + "category": "ChartOneAnswer", "item": "X축/① 글꼴 (돋움)" }, "54": { "chart_xpath": "//c:catAx/c:txPr//a:defRPr/@sz", "value": "900", "points": 1, - "category": "OneAnswer", + "category": "ChartOneAnswer", "item": "X축/② 크기 (9pt)" }, "55": { @@ -779,7 +778,7 @@ "option": "i", "value": "1", "points": 1, - "category": "OneAnswer", + "category": "ChartOneAnswer", "item": "X축/③ 기울임", "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" }, @@ -787,14 +786,14 @@ "chart_xpath": "//c:valAx/c:txPr//a:ea/@typeface", "value": "돋움", "points": 1, - "category": "OneAnswer", + "category": "ChartOneAnswer", "item": "Y축/① 글꼴 (돋움)" }, "57": { "chart_xpath": "//c:valAx/c:txPr//a:defRPr/@sz", "value": "900", "points": 1, - "category": "OneAnswer", + "category": "ChartOneAnswer", "item": "Y축/② 크기 (9pt)" }, "58": { @@ -802,7 +801,7 @@ "option": "i", "value": "1", "points": 1, - "category": "OneAnswer", + "category": "ChartOneAnswer", "item": "Y축/③ 기울임", "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" }, diff --git a/회차별채점자료/2504/json_채점기준표/0522/DIW_2504B.json b/회차별채점자료/2504/json_채점기준표/0522/DIW_2504B.json index 4a2b765..2ac1a76 100644 --- a/회차별채점자료/2504/json_채점기준표/0522/DIW_2504B.json +++ b/회차별채점자료/2504/json_채점기준표/0522/DIW_2504B.json @@ -412,8 +412,7 @@ "value": "궁서체", "points": 1, "category": "FontName", - "item": "문구 (친환경 에너지)/⑧ 글씨체 (궁서체)", - "desc": "폰트 '견고딕'과 '중고딕'은 한글프로그램 내부적으로 '한양견고딕', '한양중고딕'처리 되어서 프로그램 내부에서 수험자 답변에서 '한양'을 제거하는 과정을 거침" + "item": "문구 (친환경 에너지)/⑧ 글씨체 (궁서체)" }, "12": { "path": "//CHARSHAPE[@Id=//RECTANGLE//TEXT[./CHAR[text()='{searchValue}']]/@CharShape]/@Height", diff --git a/회차별채점자료/2505/excel_채점기준표/DIW_2505A.xlsx b/회차별채점자료/2505/excel_채점기준표/DIW_2505A.xlsx new file mode 100644 index 0000000..755c6b1 Binary files /dev/null and b/회차별채점자료/2505/excel_채점기준표/DIW_2505A.xlsx differ diff --git a/회차별채점자료/2505/excel_채점기준표/DIW_2505B.xlsx b/회차별채점자료/2505/excel_채점기준표/DIW_2505B.xlsx new file mode 100644 index 0000000..dd56de1 Binary files /dev/null and b/회차별채점자료/2505/excel_채점기준표/DIW_2505B.xlsx differ diff --git a/회차별채점자료/2505/excel_채점기준표/DIW_2505C.xlsx b/회차별채점자료/2505/excel_채점기준표/DIW_2505C.xlsx new file mode 100644 index 0000000..f8f6bee Binary files /dev/null and b/회차별채점자료/2505/excel_채점기준표/DIW_2505C.xlsx differ diff --git a/회차별채점자료/2505/excel_채점기준표/DIW_2505D.xlsx b/회차별채점자료/2505/excel_채점기준표/DIW_2505D.xlsx new file mode 100644 index 0000000..6d1a417 Binary files /dev/null and b/회차별채점자료/2505/excel_채점기준표/DIW_2505D.xlsx differ diff --git a/회차별채점자료/2505/hml_변환/DIW_2505A.hml b/회차별채점자료/2505/hml_변환/DIW_2505A.hml new file mode 100644 index 0000000..790c812 --- /dev/null +++ b/회차별채점자료/2505/hml_변환/DIW_2505A.hml @@ -0,0 +1,4220 @@ +1user2025년 4월 2일 수요일 오후 1:24:06^1.^2.^3)^4)(^5)(^6)^7^8^1.^2.^3)^4)(^5)(^6)^7^8