diff --git a/250829_DIW_2508_2A_채점결과.xlsx b/250829_DIW_2508_2A_채점결과.xlsx deleted file mode 100644 index 4a1a307..0000000 Binary files a/250829_DIW_2508_2A_채점결과.xlsx and /dev/null differ diff --git a/250908_DIW_2508D_채점결과_header.xlsx b/250908_DIW_2508D_채점결과_header.xlsx deleted file mode 100644 index 5f1eeb7..0000000 Binary files a/250908_DIW_2508D_채점결과_header.xlsx and /dev/null differ diff --git a/250912_DIW_2508C_TEST.xlsx b/250912_DIW_2508C_TEST.xlsx deleted file mode 100644 index 19e9b5a..0000000 Binary files a/250912_DIW_2508C_TEST.xlsx and /dev/null differ diff --git a/DIW_2508A.json b/DIW_2508A.json index c8dca59..b36b977 100644 --- a/DIW_2508A.json +++ b/DIW_2508A.json @@ -259,7 +259,7 @@ "searchValue": "DIAT", "value": "굴림", "points": 1, - "category": "FontName.Header", + "category": "Header.FontName", "item": "문구 (DIAT)/① 글꼴 (굴림)" }, "26": { @@ -267,7 +267,7 @@ "searchValue": "DIAT", "value": "900", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/② 크기 (9pt)" }, "27": { @@ -275,7 +275,7 @@ "searchValue": "DIAT", "value": "Right", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)" }, "28": { @@ -365,7 +365,7 @@ }, "6": { "path": "//RECTANGLE//LINESHAPE", - "value": { + "value": { "Style": "DoubleSlim", "Width": "283" }, @@ -376,7 +376,7 @@ }, "7": { "path": "//RECTANGLE/@Ratio", - "value": "50", + "value": "50", "points": 2, "category": "Rectangle.OneAnswer", "item": "문구 (노인일자리)/④ 글상자 모서리 (반원)", @@ -384,35 +384,35 @@ }, "8": { "path": "//RECTANGLE//WINDOWBRUSH/@FaceColor", - "value": "211,251,193", + "value": "211,251,193", "points": 2, "category": "Rectangle.Color", "item": "문구 (노인일자리)/⑤ 채우기 : 색상(RGB:211,251,193)" }, "9": { "path": "//RECTANGLE/SHAPEOBJECT/POSITION/@TreatAsChar", - "value": "true", + "value": "true", "points": 1, "category": "Rectangle.OneAnswer", "item": "문구 (노인일자리)/⑥ 글상자 위치 (글자처럼 취급)" }, "10": { "path": "//PARASHAPE[@Id='{rect_parashape_id}']/@Align", - "value": "Center", + "value": "Center", "points": 1, "category": "Rectangle.TextBoxAlign", "item": "문구 (노인일자리)/⑦ 글상자 정렬 (가운데 정렬)" }, "11": { "path": ".//RECTANGLE//TEXT/@CharShape", - "value": "맑은 고딕", + "value": "맑은 고딕", "points": 1, "category": "Rectangle.FontName", "item": "문구 (노인일자리)/⑧ 글씨체 (맑은고딕)" }, "12": { "path": "//CHARSHAPE[@Id='{rect_charshape_id}']/@Height", - "value": "2200", + "value": "2200", "points": 1, "category": "Rectangle.FontSize", "item": "문구 (노인일자리)/⑨ 글씨크기 (2200)", diff --git a/DIW_2508B.json b/DIW_2508B.json index 409a23f..ad2cf4e 100644 --- a/DIW_2508B.json +++ b/DIW_2508B.json @@ -259,7 +259,7 @@ "searchValue": "DIAT", "value": "굴림", "points": 1, - "category": "FontName.Header", + "category": "Header.FontName", "item": "문구 (DIAT)/① 글꼴 (굴림)" }, "26": { @@ -267,7 +267,7 @@ "searchValue": "DIAT", "value": "900", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/② 크기 (9pt)" }, "27": { @@ -275,7 +275,7 @@ "searchValue": "DIAT", "value": "Right", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)" }, "28": { diff --git a/DIW_2508C.json b/DIW_2508C.json index 6221332..a0bb67b 100644 --- a/DIW_2508C.json +++ b/DIW_2508C.json @@ -256,11 +256,10 @@ }, "25": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "page": 1, "searchValue": "DIAT", "value": "궁서", "points": 1, - "category": "FontName.Header", + "category": "Header.FontName", "item": "문구 (DIAT)/① 글꼴 (궁서)" }, "26": { @@ -268,7 +267,7 @@ "searchValue": "DIAT", "value": "900", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/② 크기 (9pt)" }, "27": { @@ -276,7 +275,7 @@ "searchValue": "DIAT", "value": "Right", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)" }, "28": { diff --git a/diwScoring2.py b/diwScoring2.py index b78e1e7..0068d01 100644 --- a/diwScoring2.py +++ b/diwScoring2.py @@ -178,34 +178,6 @@ class XMLScorer: page_start_index = None return pages - # def parse_pages_by_bookmark(root): - # """ - # BOOKMARK(Name="Page_X_start" ~ "Page_X_end") 사이의

요소들을 - # 페이지 단위로 딕셔너리에 저장 - # """ - # pages = {} - # all_p_tags = root.xpath('//P') - - # current_page = None - # page_start_index = None - - # for i, p in enumerate(all_p_tags): - # # P 안의 모든 BOOKMARK 탐색 - # bookmarks = p.xpath('.//BOOKMARK') - # for bm in bookmarks: - # name = bm.get('Name') - # if name and name.endswith('_start'): - # current_page = name.replace('_start', '') - # page_start_index = i - # elif name and name.endswith('_end') and current_page is not None: - # page_end_index = i - # # 시작~끝까지 P 태그 묶음 저장 - # page_content = all_p_tags[page_start_index:page_end_index + 1] - # pages[current_page] = page_content - # current_page = None - # page_start_index = None - - # return pages def extract_char_text_from_p(p_element): """ @@ -510,7 +482,6 @@ class XMLScorer: elif "TextBoxAlign" in (category or ""): if has_page2_rectangle: parashape_list = rect_parashapes - else: parashape_list = root.xpath(xpath) @@ -521,7 +492,6 @@ class XMLScorer: exec_xpath = xpath.replace('{rect_parashape_id}', parashape_id) items = root.xpath(exec_xpath) result_items.extend(items) - else: # RECTANGLE이 없으면 items는 빈 리스트 items = [None] @@ -532,17 +502,6 @@ class XMLScorer: if scoring['points'] > 0: break - # if has_page2_rectangle: - # # 2페이지 내에서만 검색 - # search_root = etree.Element("Page_2") - # for p in page2_ptags: - # search_root.append(p) - # rect_parashape_id = search_root.xpath(".//RECTANGLE/ancestor::P[last()]/@ParaShape") - - # else: - # # 전체 root에서 검색 - # rect_parashape_id = root.xpath(".//RECTANGLE/ancestor::P[last()]/@ParaShape") - # 정답이 하나인 경우 # elif (category or "") in ["OneAnswer", "ChartOneAnswer"]: elif "OneAnswer" in (category or ""): @@ -619,21 +578,8 @@ class XMLScorer: items.extend(p.xpath(xpath)) else: - # print(etree.tostring(root, pretty_print=True, encoding="unicode")) - - # 단계별 점검 - # print("1) PICTURE 태그 존재 여부:", root.xpath("//PICTURE")) - # print("2) BINITEM 태그 존재 여부:", root.xpath("//BINITEM")) - # print("3) BINITEM Format 값:", root.xpath("//BINITEM/@Format")) - # print("4) BINITEM BinData 값:", root.xpath("//BINITEM/@BinData")) - # print("5) IMAGE BinItem 값:", root.xpath("//IMAGE/@BinItem")) - # print("6) PICTURE 안의 IMAGE 존재 여부:", root.xpath("//PICTURE/IMAGE")) - # print("7) SIZE Width 값:", root.xpath("//PICTURE/SHAPEOBJECT/SIZE/@Width")) - - # 원래 쓰시던 XPath 그대로 결과 확인 - - # print("8) 원래 XPath 결과:", root.xpath(xpath_expr)) items = root.xpath(xpath) + # 오차범위 설정 # 한글 프로그램 내부에서 드물게 0mm이지만 1pt로 저장되는 경우가 있음 # diff --git a/diwScoring2_new.py b/diwScoring2_new.py deleted file mode 100644 index 31d9e8a..0000000 --- a/diwScoring2_new.py +++ /dev/null @@ -1,1445 +0,0 @@ -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 -import math -from itertools import chain - - -# from xpathSearch import XMLPathHandler - -class XMLScorer: - # 채점 기준 경로 초기화 - def __init__(self, scoring_criteria_path): - # 채점 기준 로드 - self.scoring_criteria = self._load_scoring_criteria(scoring_criteria_path) - self.total_score = 0 - self.partial_score = 0 - self.typo_score = 0 - - 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) - - # mm to pt - def convert_mm_to_pt(self, mm): - one_mm_per_pt = 2.83465 - hwp_scale = 100 - pt = math.trunc(mm * one_mm_per_pt * hwp_scale) - return pt - - def convert_pt_to_mm(self, pt): - one_mm_per_pt = 2.83465 - hwp_scale = 100 - mm = round(pt / (one_mm_per_pt * hwp_scale), 1) - return mm - - # 유사한 텍스트 찾기 - def find_similar_text(self, root, target_text, xml_type, 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' - } - - if xml_type == "hml": - all_text = root.xpath(f"//BODY//text() | //TEXTART/@Text") if root is not None else [] - - elif xml_type == "chart": - all_text = root.xpath(f"//c:chart//text()", namespaces=namespaces) if root is not None else [] - - else: - all_text = [] - - # 유사도 비교 - 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 target_text - - # 정답 비교 및 점수 계산 - def evaluate_answer(self, scoring, user_answer, right_answer, points, - method="equal", tolerance=0): - - scoring['user_answer'] = user_answer - - is_correct = False - - # 일치 여부 확인 - if method == "equal": - is_correct = (user_answer == right_answer) - - # 정답이 오차범위가 필요한 경우 - elif method == "tolerance": - if isinstance(user_answer, dict) and isinstance(right_answer, dict): - is_correct = all(abs(user_answer[k] - right_answer[k]) <= tolerance for k in right_answer) - else: - is_correct = abs(user_answer - right_answer) <= tolerance - - # 정답이 포함되어 있는 경우 - elif method == "in": - is_correct = user_answer in right_answer - - # 정답을 부분점수로 계산(특수문자, 한자) - elif method == "partial_score": - # 부분 점수 계산 - is_correct = isinstance(user_answer, (int, float)) and user_answer <= right_answer - points = min(points, user_answer) - else: - raise ValueError(f"Unknown comparison method: {method}") - - if is_correct: - scoring['points'] = points - self.total_score += points - self.partial_score += points - else: - scoring['points'] = 0 - - # 하나의 XML 파일 채점 - def _score_xml_file(self, xml_file, chart_xml): - - def parse_pages_by_bookmark(root): - """ - P/TEXT/BOOKMARK 구조를 가진 XML에서 페이지 구간별 전체 XML을 저장 - """ - pages = {} - all_p_tags = root.xpath('//P') - - current_page = None - page_start_index = None - - for i, p in enumerate(all_p_tags): - bookmark = p.xpath('./TEXT/BOOKMARK') - if bookmark: - name = bookmark[0].get('Name') - if name and name.endswith('_start'): - current_page = name.replace('_start', '') - page_start_index = i - elif name and name.endswith('_end') and current_page is not None: - page_end_index = i - # 페이지 전체 XML fragment 만들기 - page_root = ET.Element("Page") - for ptag in all_p_tags[page_start_index:page_end_index + 1]: - page_root.append(ptag) - - # dict에 저장 (ElementTree 자체 저장) - pages[current_page] = page_root - - current_page = None - page_start_index = None - - return pages - - def extract_char_text_from_p(p_element): - """ - 주어진

요소에서 모든 자손 의 텍스트를 추출해 문자열 리스트로 반환합니다. - """ - full_text = [] - for p in p_element: - char_elements = p.xpath('.//CHAR') - combined_text = ''.join([char.text for char in char_elements if char.text]) - no_space_text = re.sub(r'\s+', '', combined_text) # 공백 문자 제거 - full_text.append(no_space_text) - return full_text - - def has_elements(ptags, xpath): - for p in ptags: - element_list = p.xpath(xpath) if xpath else [] - if element_list: - return True - return False - - def get_items(xpath, pages, root, use_page2=False): - if not xpath: - return [] - if use_page2: - return pages["Page_2"].xpath(xpath) - return root.xpath(xpath) - - try: - tree = ET.parse(xml_file) - root = tree.getroot() - - # XML문서 페이지 파싱 전처리 - pages = parse_pages_by_bookmark(root) - # print("🚩Pages : ", pages) - - # 네임스페이스 정의 - 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) - - # 결과값을 Dictionary로 저장 - # 하나의 xml파일 = 수험생 한명의 답안지 - onePersonResult = { - 'filename': os.path.basename(xml_file), - 'score_results': [], - 'total_score': 0, - 'partial_scores': [] - } - print(f"🔜File name: {onePersonResult['filename']}") - - self.total_score = 0 - for section_id, section in self.scoring_criteria.items(): - self.partial_score = 0 - for criterion_id, criterion in section.items(): - id = criterion_id - xpath = criterion.get('path', None) - xpath2 = criterion.get('path2', None) - xpath3 = criterion.get('path3', None) - chart_xpath = criterion.get('chart_xpath', None) - search_value = criterion.get('searchValue', None) - right_answer = criterion.get('value', None) - points = criterion.get('points', 0) - category = criterion.get('category', None) - item = criterion.get('item', None) - option = criterion.get('option', None) - page = criterion.get('page', None) - similar_text = None - - # search_value가 있는 경우 - if search_value is not None: - if xpath or xpath2: - similar_text = self.find_similar_text(root, search_value, xml_type="hml") - xpath = xpath.replace('{searchValue}', similar_text) if xpath else "" - xpath2 = xpath2.replace('{searchValue}', similar_text) if xpath2 else "" - if chart_xpath: - similar_text = self.find_similar_text(chart_tree, search_value, xml_type="chart") - chart_xpath = chart_xpath.replace('{searchValue}', similar_text) if chart_xpath else "" - - if option: - xpath = xpath.replace('{option}', option) if xpath else "" - xpath2 = xpath2.replace('{option}', option) if xpath2 else "" - chart_xpath = chart_xpath.replace('{option}', option) if chart_xpath else "" - - - # 문항 별 채점 결과 저장 - scoring = { - 'section': section_id, - 'id': id, - 'category': category, # 채점 분류 - 'item': item, # 채점 항목 - 'right_answer': right_answer, # 정답 - 'user_answer': None, # 실제 작성 답안 - 'points': 0, # 점수 - } - - try: - if (category or "") == "PageSetting": - items = root.xpath(xpath) - error_range = criterion.get('tolerance', 0) - - right_answer = { - 'Top' : float(right_answer.get("Top", 0)), - 'Bottom' : float(right_answer.get("Bottom", 0)), - 'Left' : float(right_answer.get("Left", 0)), - 'Right' : float(right_answer.get("Right", 0)), - 'Header' : float(right_answer.get("Header", 0)), - 'Footer' : float(right_answer.get("Footer", 0)), - 'Gutter' : float(right_answer.get("Gutter", 0)), - } - right_answer = { - k: self.convert_mm_to_pt(v) - for k, v in right_answer.items() - } - - for item in items: - user_answer = { - 'Top' : float(item.get("Top", 0)), - 'Bottom' : float(item.get("Bottom", 0)), - 'Left' : float(item.get("Left", 0)), - 'Right' : float(item.get("Right", 0)), - 'Header' : float(item.get("Header", 0)), - 'Footer' : float(item.get("Footer", 0)), - 'Gutter' : float(item.get("Gutter", 0)), - } - - self.evaluate_answer(scoring, user_answer, right_answer, points, method="tolerance", tolerance=error_range) - - if scoring['points'] > 0: - break - - elif (category or "") == "BasicSetting": - # FontName, FontSize, Alignment, LineSpacing - # 해당 속성의 요소(텍스트)가 문서 내부에 존재하면 정답처리 - - matches = set() - - # P 태그 순회 - for p_tag in root.xpath(".//P"): - parashape = p_tag.get("ParaShape") - - for text_tag in p_tag.xpath(".//TEXT"): - charshape = text_tag.get("CharShape") - - if parashape is not None and charshape is not None: - matches.add((parashape, charshape)) - - # 출력 - for para, char in matches: - # print(f"ParaShape = {para}, CharShape = {char}") - font_id = root.xpath(f"//CHARSHAPE[@Id='{char}']/FONTID/@Hangul") - font_name = root.xpath(f"//FONTFACE[@Lang='Hangul']/FONT[@Id='{font_id[0]}']/@Name") - - user_answer = { - 'FontName': font_name[0], - 'FontSize': root.xpath(f"//CHARSHAPE[@Id='{char}']/@Height")[0], - 'Alignment': root.xpath(f"//PARASHAPE[@Id='{para}']/@Align")[0], - 'LineSpacing': root.xpath(f"//PARASHAPE[@Id='{para}']/PARAMARGIN/@LineSpacing")[0] - } - - # 정답과 수험자 답안 비교 - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") - - if scoring['points'] > 0: - break - - # 1, 2페이지 모두 정답이어야 함 - elif (category or "") == "PageNumber": - items = root.xpath(xpath) if xpath else [] - - all_match = True - for item in chain(items): - user_answer = item - if right_answer != user_answer: - all_match = False - break - - if all_match: - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") - else: - self.evaluate_answer(scoring, user_answer, right_answer, 0, method="equal") - - - # 오타 감점 부분은 미리 계산 하고, 이후 점수만 계산 - elif (category or "") == "오타감점": - points = self.get_typo_score() - self.total_score += points - self.partial_score += points - scoring['points'] = points - - # 테이블의 경우 모든 셀에 요구사항이 적용되어야 정답처리 - elif (category or "") == "TableAnswer": - items = root.xpath(xpath) if xpath else [] - items2 = root.xpath(xpath2) if xpath2 else [] - - def is_all_match(item_list): - return item_list and all(item == right_answer for item in item_list) - ## 위 코드와 동일한 기능(풀어서 설명) - # 리스트가 비어 있으면 False 반환 - # if not item_list: - # return False - - # # 리스트의 모든 항목이 right_answer와 같은지 검사 - # for item in item_list: - # if item != right_answer: - # return False # 하나라도 다르면 False 반환 - - # return True # 전부 일치하면 True 반환 - - if is_all_match(items): - user_answer = right_answer - elif is_all_match(items2): - user_answer = right_answer - else: - user_answer = "" - points = 0 - - self.evaluate_answer(scoring, user_answer, right_answer, points) - - # [1-16] ◈ 행사안내 ◈ - # 특수문자와 글자의 속성이 같고 문서 내부에 '행사안내'와 같은 문자가 있을 경우 - # 유사도 문제로 의도치 않은 다른 부분의 텍스트 속성이 채점되는것을 방지하고자 - # 해당 문자를 포함하는 모든 문단의 속성을 판단해 - # 정렬값이 정답과 일치하는 경우 정답으로 채점 - elif (category or "") == "Align": - match_str = criterion.get('match_str', None) - - xpath = xpath.replace('{match_str}', match_str) - items = root.xpath(xpath) - - for item in items: - user_answer = item - self.evaluate_answer(scoring, user_answer, right_answer, points) - if scoring['points'] > 0: - break - - elif (category or "") == "majorGridlines": - # 줄/칸 전환여부 확인 - # table_col_count = root.xpath("//SECTION[2]//TABLE/@ColCount") - table_col_count = root.xpath("//TABLE/@ColCount") - - # print("🟡테이블 열 개수: ", int(table_col_count[0]) if table_col_count else 0) - - chart_ser_count = chart_tree.xpath("count(//c:ser)", namespaces=namespaces) if chart_xpath else 0 - - # print("🟡차트 데이터 개수: ", int(chart_ser_count) if isinstance(chart_ser_count, (int, float)) else 0) - - isXYtransposed = False - if table_col_count and chart_ser_count: - if int(chart_ser_count) > int(table_col_count[0])-1: - isXYtransposed = True - - # 값 축 주눈금선 존재하는지 여부 확인 - items = chart_tree.xpath(chart_xpath, namespaces=namespaces) if chart_xpath else [] - - for item in items: - # item이 존재하면 True, 없으면 False - user_answer = (item is not None) and isXYtransposed - - # 정답과 수험자 답안 비교 - self.evaluate_answer(scoring, user_answer, right_answer, points) - if scoring['points'] > 0: - break - - - # 정답이 하나인 경우 - # elif (category or "") in ["OneAnswer", "ChartOneAnswer"]: - elif "OneAnswer" in (category or ""): - if "Header" in category: - page1_ptags = pages.get('Page_1', []) - page2_ptags = pages.get('Page_2', []) - header_xpath = "//HEADER//P" - has_page1_element = has_elements(page1_ptags, header_xpath) - has_page2_element = has_elements(page2_ptags, header_xpath) - - if not has_page1_element or not has_page2_element: - user_answer = None - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") - continue - - # 2페이지 글상자인지 확인 - is_page2_rectangle = False - if "Rectangle" in category: - page2_ptags = pages.get('Page_2', []) - rectangle_xpath = "//RECTANGLE" - has_page2_element = has_elements(page2_ptags, rectangle_xpath) - - if not has_page2_element: - user_answer = None - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") - continue - else: - is_page2_rectangle = True - - # items = get_items(xpath, pages, root, use_page2=is_page2_rectangle) - # items2 = get_items(xpath, pages, root, use_page2=is_page2_rectangle) - - items = root.xpath(xpath) if xpath else [] - items2 = root.xpath(xpath2) if xpath2 else [] - - # 차트 XML에서 정답을 찾는 경우 - # 차트 종류가 - # 세로막대형이면 x축이 카테고리(catAx) y축이 값(valAx) - # 가로막대형이면 x축이 값(valAx) y축이 카테고리(catAx) - if "ChartOneAnswer" in category: - # 하드코딩이라 [2-45문항] 변경시 수정 필요 - # chart_type = self.scoring_criteria["2"]["45"]["chart_type"].replace(" ","") - - # chart_type 변수의 경우 45번 문항을 먼저 채점하므로 - # xy축의 변경이 필요한 53~58번 문항 채점시에 chart_type변수에 차트모양의 정보는 입력 되어있음 - - # 가로 차트일 경우에만 x축과 y축을 바꿔줌 - # 세로, 꺾은선, 원형 차트의 경우 그대로 사용 - if "가로" in chart_type: - if "catAx" in chart_xpath: - chart_xpath = chart_xpath.replace("catAx", "valAx") - elif "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.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: - break - - # [2-6] 테두리 이중실선 1.00mm - # elif (category or "") == "LineShape": - elif "LineShape" in (category or ""): - user_answer = { - 'Style': None, - 'Width': None - } - - # 2페이지 글상자인지 확인 - is_page2_rectangle = False - if "Rectangle" in category: - page2_ptags = pages.get('Page_2', []) - rectangle_xpath = "//RECTANGLE" - has_page2_element = has_elements(page2_ptags, rectangle_xpath) - - if not has_page2_element: - user_answer = None - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") - continue - else: - is_page2_rectangle = True - - line_shapes = get_items(xpath, pages, root, use_page2=is_page2_rectangle) - - # line_shapes = root.xpath(xpath) if xpath else [] - - for line_shape in line_shapes: - style = line_shape.get("Style") - width = line_shape.get("Width") - - user_answer['Style'] = style - user_answer['Width'] = width - - self.evaluate_answer(scoring, user_answer, right_answer, points) - if scoring['points'] > 0: - break - - # 사용자 입력값이 mm단위인 경우 - # elif (category or "") == "mmSize": - elif "mmSize" in (category or ""): - # 2페이지 글상자인지 확인 - is_page2_rectangle = False - if "Rectangle" in category: - page2_ptags = pages.get('Page_2', []) - rectangle_xpath = "//RECTANGLE" - has_page2_element = has_elements(page2_ptags, rectangle_xpath) - - if not has_page2_element: - user_answer = None - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") - continue - else: - is_page2_rectangle = True - - items = get_items(xpath, pages, root, use_page2=is_page2_rectangle) - - # 오차범위 설정 - # 한글 프로그램 내부에서 드물게 0mm이지만 1pt로 저장되는 경우가 있음 - # - # XML파일의 요소 옵션값은 내부적으로 1=0.01pt - # 이 경우를 대비하여 tolerance를 10으로 설정 (1pt=약0.04mm 만큼의 오차 혀용) - error_range = criterion.get('tolerance', 10) - - # JSON 파일 value키값에 mm나 공백이 입력될 경우 제거 - # 예) "80.2 mm" >> 80.2 로 변환 - float_string = right_answer.strip().replace("mm", "") - right_answer = self.convert_mm_to_pt(float(float_string)) - - if not items: - scoring['points'] = 0 - else: - for item in items: - user_answer = float(item) - - self.evaluate_answer(scoring, user_answer, right_answer, points, method="tolerance", tolerance=error_range) - - if scoring['points'] > 0: - break - - elif (category or "") == "ParaShape": - items = root.xpath(xpath) - - for item in items: - user_answer = { - 'Left': float(item.get('Left', 0)) / 200, - 'Indent': float(item.get('Indent', 0)) / -200, - } - - # 정답과 수험자 답안 비교 - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") - - if scoring['points'] > 0: - break - - # Boolean 타입 정답인 경우 - elif (category or "") == "Boolean": - items = root.xpath(xpath) if xpath else False - items2 = root.xpath(xpath2) if xpath2 else False - chart_items = chart_tree.xpath(chart_xpath, namespaces=namespaces) if chart_xpath else False - - user_answer = bool( items or items2 or chart_items ) - - self.evaluate_answer(scoring, user_answer, right_answer, points) - - # 채점기준표 파일에 작성된 rgb값을 그대로 읽어와 HML파일 요소의 int형 rgb값과 비교 - # elif (category or "") == "Color": - elif "Color" in (category or ""): - is_page2_rectangle = False - if "Rectangle" in category: - page2_ptags = pages.get('Page_2', []) - rectangle_xpath = "//RECTANGLE" - has_page2_element = has_elements(page2_ptags, rectangle_xpath) - - if not has_page2_element: - user_answer = None - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") - continue - else: - is_page2_rectangle = True - - items = get_items(xpath, pages, root, use_page2=is_page2_rectangle) - items2 = get_items(xpath, pages, root, use_page2=is_page2_rectangle) - - rgb_text = right_answer - - # 정규식을 이용해 숫자만 리스트로 추출 - numbers = re.findall(r'\d+', rgb_text) - r, g, b = map(int, numbers) if len(numbers) == 3 else None - - # 콤마(,)로 구분된 문자열을 정수형으로 변환 - # r, g, b = map(int, rgb_text.split(',')) - - rgb_int = (b << 16) + (g << 8) + r - - # items, items2를 순차적으로 순회 - for item in chain(items, items2): - user_answer = int(item) - self.evaluate_answer(scoring, user_answer, rgb_int, points, method="equal") - if scoring['points'] > 0: - break - - # 문단 첫글자 장식 채점 - elif (category or "") == "TwoLineSize": - items = root.xpath(xpath) - error_range = criterion.get('tolerance', 0) - for item in items: - user_answer = { - "Height": int(item.get('Height', 0)), - "Width": int(item.get('Width', 0)) - } - self.evaluate_answer(scoring, user_answer, right_answer, points, method="tolerance", tolerance=error_range) - - if scoring['points'] > 0: - break - - # 폰트명 - elif "FontName" in (category or ""): - # 'DIAT' 머릿말 문항 1,2페이지 둘 중 하나라도 없으면 0점 처리 - if "Header" in category: - page1_ptags = pages.get('Page_1', []) - page2_ptags = pages.get('Page_2', []) - header_xpath = "//HEADER//P" - has_page1_element = has_elements(page1_ptags, header_xpath) - has_page2_element = has_elements(page2_ptags, header_xpath) - - if not has_page1_element or not has_page2_element: - user_answer = "" - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") - continue - - # 2페이지 글상자인지 확인 - is_page2_rectangle = False - if "Rectangle" in category: - page2_ptags = pages.get('Page_2', []) - rectangle_xpath = "//RECTANGLE" - has_page2_element = has_elements(page2_ptags, rectangle_xpath) - - if not has_page2_element: - user_answer = None - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") - continue - else: - is_page2_rectangle = True - - charshape_list = get_items(xpath, pages, root, use_page2=is_page2_rectangle) - - # 문자속성이 없는 경우 - if not charshape_list: - user_answer = "" - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") - else: - require_all_match = ("TableFontName" in category) - any_match = False - all_match = True - matched_user_answer = None # 일치하는 user_answer를 기억 - - for charshape_id in charshape_list: - font_id = root.xpath(f"//CHARSHAPE[@Id='{charshape_id}']/FONTID/@Hangul") - if not font_id: - all_match = False - 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].replace(" ", "") - right_answer = right_answer.replace(" ","") - - # 접두어 제거 - if right_answer in ["견고딕", "중고딕"]: - user_answer = user_answer.replace("한양", "") - - if user_answer == right_answer: - any_match = True - matched_user_answer = user_answer - else: - all_match = False - if require_all_match: - break - - if require_all_match: - score = points if all_match else 0 - self.evaluate_answer(scoring, user_answer, right_answer, score) - else: - score = points if any_match else 0 - self.evaluate_answer(scoring, matched_user_answer if any_match else "", right_answer, score) - - # 폰트 속성 - elif (category or "") == "FontAttribute": - # 하이퍼링크 처리 - - # 1. 하이퍼링크를 포함하는 P요소를 가져옴 - # 2. 그 P요소의 자손 CHAR태그에 있는 텍스트를 하나의 문자열로 변환 - # 3. P요소의 문자열과 채점하려는 문자열이 일치하는지 확인 - hyperlink_xpath = criterion.get('hyperlink_ptag', None) - hyperlink_ptag = root.xpath(hyperlink_xpath) if hyperlink_xpath else None - - p_tag_text_list = extract_char_text_from_p(hyperlink_ptag) if hyperlink_ptag else [] - hyperlink_text = search_value.replace(" ", "") if search_value else "" - - # search_value가 hyperlink문자열에 포함되어 있는지 확인 - # search_value가 hyperlink인 경우와 아닌경우를 구분해 채점 - search_in_hyperlink = False - if hyperlink_text and any(hyperlink_text in text for text in p_tag_text_list): - search_in_hyperlink = True - else: - search_in_hyperlink = False - - # hyperlink가 아닌 경우(일반적인 텍스트 일 경우) - # 하이퍼링크를 포함한 P태그가 없거나 search_value값이 하이퍼링크텍스트에 포함되어 있지 않을 경우 - if not hyperlink_ptag or not search_in_hyperlink: - charshape_list = root.xpath(xpath) - if not charshape_list: - charshape = None - user_answer = None - else: - 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") - - if scoring['points'] > 0: - break - - # 하이퍼링크인 경우 - # elif hyperlink_ptag and search_in_hyperlink: - else: - p_elements = hyperlink_ptag - - for p in p_elements: - # 수험자가 입력한 텍스트 중 하이퍼링크가 들어간 문단의 모든 텍스트를 가져와 - # 채점하고자 하는 (정답) 하이퍼링크 텍스트와 시작 위치를 비교 - # (예시) - # [수험자입력] 1. 사전등록 : 서울 국제 도서 박람회 흠페이지(http://www.ind.or.kr) 참조 - # [정답] 서울 국제 도서 박람회 흠페이지(http://www.ind.or.kr) 참조 - # 수험자 텍스트의 "1. 사전등록" 부분을 제외하고 난 뒤 - # 남은 "서울 국제 도서 박람회 흠페이지(http://www.ind.or.kr) 참조"의 정답 부분과 유사도를 비교 - - text_list = p.xpath(".//CHAR/text()") - full_text = ''.join(text_list).replace(" ", "") - # print("full_text: ", full_text) - - # 채점하고자 하는 문자열 (search_value)의 첫 문자 - first_char = search_value[0] - - # 수험자 답안에서 첫 문자 인덱스 위치 - user_answer_first_index = full_text.find(first_char) - - if user_answer_first_index != -1: - # 수험자 답안에서 첫 문자 인덱스 위치부터 search_value 길이만큼 잘라서 비교 - trimmed_full_text = full_text[user_answer_first_index:] - else: - trimmed_full_text = full_text - - # 두 문자열의 유사도 계산 - similarity = difflib.SequenceMatcher(None, trimmed_full_text, hyperlink_text).ratio() - - # 두 문자열의 유사도에 따라 하이퍼링크 확인 - # 유사도가 낮은 경우 오답처리 - if similarity < 0.7: - self.evaluate_answer(scoring, user_answer, right_answer, 0, method="equal") - - # 유사도가 높은 경우 - else: - inside_field = False - charshape_list = [] - - for elem in p.iter(): - # 시작 지점 확인 - # FIELDBEGIN태그와 FIELDEND태그 사이 - if elem.tag == "FIELDBEGIN": - inside_field = True - elif elem.tag == "FIELDEND": - inside_field = False - - # 하이퍼링크 텍스트가 CharShape 속성값이 앞의 텍스트와 다른 경우 - # http://www.ihd.or.kr 주소가 TEXT 부모태그를 가지는 경우 - # [예시] - # - # http://www.ihd.or.kr) - # - # 해당 부모 TEXT태그의 CharShape속성을 확인 - elif inside_field and elem.tag == "TEXT": - charshape = elem.get("CharShape") - print('charshape : ', charshape) - if charshape: - charshape_list.append(charshape) - - # 하이퍼링크 텍스트가 CharShape 속성값이 앞의 텍스트와 같은 경우 - # http://www.ihd.or.kr 주소가 TEXT부모태그 없이 CHAR로만 있는경우 - # [예시] - # http://www.ihd.or.kr) - # FIELDBEGIN밖의 TEXT태그의 CharShape속성을 확인해야 한다 - elif inside_field and elem.tag == "CHAR": - parent = elem.getparent() - - charshape = parent.get("CharShape") - print('charshape : ', charshape) - if charshape: - charshape_list.append(charshape) - - - # 하이퍼링크에 해당하는 P태그 내 존재하는 charshape ID값 모두를 비교해 해당 속성(ITALIC, BOLD, UNDERLINE) 확인 - # 모든 charshape ID값이 정답과 일치하는 경우에만 점수 부여 - all_attributes_match = True - if charshape_list: - for charshape_id in charshape_list: - charshape = root.xpath(f"//CHARSHAPE[@Id='{charshape_id}']") - - # 속성 태그가 존재하는지 확인 - font_attribute = charshape[0].find(right_answer) - if font_attribute is None: - user_answer = None - all_attributes_match = False - break - - else: - user_answer = font_attribute.tag - - if all_attributes_match: - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") - else: - self.evaluate_answer(scoring, user_answer, right_answer, 0, method="equal") - - elif (category or "") == "LineSpacing": - page1_ptags = pages.get('Page_1', []) - - # 줄간격이 하나라도 일치하지 않을 경우 오답처리 - linespacing_match = True - for p in page1_ptags: - parashape_id = p.get('ParaShape') - xpath = xpath.replace('{parashape_id}', parashape_id) - linespacing = root.xpath(xpath) - user_answer = linespacing[0] - - # print("🟡줄간격: ", user_answer) - if user_answer != right_answer: - linespacing_match = False - break - - # 문단 첫 글자 크기에 따라 채점 기준 추가 (050624) - # 1. 기본 줄간격 160% 일 때 26pt - # 2. 해당 문제의 정답 줄간격 (180% = 28pt / 200% = 30pt ) - # 두 경우의 글자 크기가 아니라면 오답처리 - firstword = criterion.get('first_word', None) - result = root.xpath(f"//CHARSHAPE[@Id=//RECTANGLE//TEXT[CHAR[text()='{firstword}']]/@CharShape]/@Height") - firstword_size = result[0] if result else None - - if (right_answer == '180' and firstword_size not in ['2600', '2800', None]) or (right_answer == '200' and firstword_size not in ['2600', '3000', None]): - linespacing_match = False - - if linespacing_match is True: - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") - else: - self.evaluate_answer(scoring, user_answer, right_answer, 0, method="equal") - - - # 특수문자 갯수 채점 - elif (category or "") == "SpecialChar": - ch1 = criterion.get('char1', None) - ch2 = criterion.get('char2', None) - ch3 = criterion.get('char3', None) - xpath = xpath.replace('{char1}', ch1) - xpath2 = xpath2.replace('{char2}', ch2) - xpath3 = xpath3.replace('{char3}', ch3) - ch1_str = root.xpath(xpath) - ch2_str = root.xpath(xpath2) - ch3_str = root.xpath(xpath3) - sum_char = 0 - - # char1 요소에서 특수문자 갯수 세기 (최대 2점) - for text in ch1_str or []: - ch1_count = text.count(ch1) - sum_char += ch1_count - if sum_char >= 2: - sum_char = 2 - break - - # char2 요소에서 특수문자 갯수 세기 (최대 1점) - # char1과 char2가 다른 경우 (예: ▶ 행사안내 ◀) - if (ch1 != ch2) and ch2_str: - for text in ch2_str or []: - ch2_count = text.count(ch2) - if ch2_count > 1: - ch2_count = 1 - sum_char += ch2_count - - # char3 요소에서 특수문자 갯수 세기 (최대 1점) - if ch3_str: - for text in ch3_str or []: - ch3_count = text.count(ch3) - if ch3_count > 1: - ch3_count = 1 - sum_char += ch3_count - - user_answer = sum_char - - self.evaluate_answer(scoring, user_answer, right_answer, points, method="partial_score") - - # 쪽 테두리 (이중 실선, 머리말 포함) 설정 - elif (category or "") == "PageBorder": - user_answer = { - "header_inside": False, - "all_double_slim": False - } - - # 머릿말 포함 객체가 하나라도 있으면 정답 - header_inside_elements = root.xpath(xpath) - for header_inside in header_inside_elements: - # print("머릿말포함: ",header_inside) - if "true" in header_inside: - user_answer["header_inside"] = True - break - - # BORDERFILL요소의 자녀 - # LEFTBORDER, RIGHTBORDER, TOPBORDER, BOTTOMBORDER 요소의 Type속성이 - # 모두 DoubleSlim이면 정답 - border_tags = ["LEFTBORDER", "RIGHTBORDER", "TOPBORDER", "BOTTOMBORDER"] - - borderfill_elements = root.xpath(xpath2) - for borderfill in borderfill_elements: - all_double_slim = True - - for tag in border_tags: - element = borderfill.find(tag) - - if (element is None) or (element.get("Type") != "DoubleSlim"): - all_double_slim = False - break - - #모든 BORDER 태그의 Type 속성이 'DoubleSlim'인 객체가 있다면 반복문 탈출 - if all_double_slim: - user_answer["all_double_slim"] = True - break - - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") - - # 다단 확인 [2-3]문항 - elif (category or "") == "TwoColumn": - page2_ptags = pages.get('Page_2', []) - - for p in page2_ptags: - column_count = p.xpath(xpath) - user_answer = column_count[0] if column_count else '0' - - if user_answer == right_answer: - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") - - # P태그들 중 하나라도 다단이 존재할 경우 정답처리 - if scoring['points'] > 0: - break - - # 한자 - elif (category or "") == "Hanja": - # 점수 계산 - score = 0 - max_score = points - - word_list = criterion.get('word', []) - # 부분점수 (최대점수에서 한자 갯수만큼 나눈 몫) - score_per_pair = max_score // len(word_list) - - # 한자가 5개 고정일 경우 - # score_per_pair = 2 - - for kor, chn in word_list: - # XPath 구문 구성 및 실행 - exec_xpath = xpath.replace('{kor}', kor).replace('{chn}', chn) - matched = root.xpath(exec_xpath) - - if matched: - score += score_per_pair - - # 최대 점수 초과 방지 - user_answer = min(score, max_score) - - self.evaluate_answer(scoring, user_answer, right_answer, points, method="partial_score") - - elif (category or "") == "ChartType": - 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" - } - chart_type = criterion.get('chart_type').replace(" ","") - - # 입력한 chart_type에 해당하는 xpath를 가져옴 - chart_xpath = chart_type_list[chart_type] - - # xpath를 사용하여 차트 요소가 있는지 확인 - user_answer = bool(chart_tree.xpath(chart_xpath, namespaces=namespaces)) - self.evaluate_answer(scoring, user_answer, right_answer, points) - - finally: - # 문항 채점 결과를 리스트에 입력 - onePersonResult['score_results'].append(scoring) - print(f'scoring: {scoring}') - - onePersonResult['partial_scores'].append({ - 'section': section_id, - 'score': self.partial_score - }) - onePersonResult['total_score'] = self.total_score - return onePersonResult - - except ET.ParseError as e: - return { - 'filename': os.path.basename(xml_file), - '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, chart_xml): - - # 문자열 리스트를 필터링 - def clean_text_list(text_list, ignore_words=None): - result = [] - for text in text_list: - if ignore_words: - text = text.replace(ignore_words, '') - text = text.replace(' ', '') # 공백 제거 - text = re.sub(r'\d+\.\s*|-', '', text) # 숫자. / - 제거 - result.append(text) - return result - - # 1. 텍스트 추출 - # 2. 공백제거, 특정 형식 제거 - # 3. 리스트를 문자열로 변환 - - user_answer_root = ET.parse(user_answer_file).getroot() - correct_answer_root = ET.parse(correct_answer_file).getroot() - - # xpath로 바이너리 부분추출 - user_input_text = user_answer_root.xpath('//CHAR//text()[not(ancestor::HEADER) and not(ancestor::TABLE)]') - correct_input_text = correct_answer_root.xpath('//CHAR//text()[not(ancestor::HEADER) and not(ancestor::TABLE)]') - - # 테이블 구간 추출 - user_table_text = user_answer_root.xpath('//TABLE//CHAR//text()') - correct_table_text = correct_answer_root.xpath('//TABLE//CHAR//text()') - - user_chart_title = "" - correct_chart_title = self.scoring_criteria["2"]["50"]["searchValue"] - - # 차트 XML에서 차트제목 추출 - if chart_xml is not None: - chart_xml_tree = ET.fromstring(chart_xml) - ns = {'c': 'http://schemas.openxmlformats.org/drawingml/2006/chart', - 'a': 'http://schemas.openxmlformats.org/drawingml/2006/main'} - xpath_expr = '/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:r/a:t' - - # 차트 제목 추출 - chart_title = chart_xml_tree.xpath(xpath_expr, namespaces=ns) - - # 차트 제목이 존재하는 경우 - user_chart_title = chart_title[0].text if chart_title else "" - - try : - ignore_word = self.scoring_criteria["2"]["29"]["ignoreWord"] - # 특정 단어 제거 - # 오타와 누락의 경우만 판단하면 정상작동하지만 - # 추가 된 단어의 경우를 채점기준에 추가하면 정확하게 채점 되지 않을 수 있음 - # [정답] 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] - except (KeyError, IndexError, AttributeError): - ignore_word = None - - # print(f"ignore_word: {ignore_word}") - - # 문자열 필터링 - correct_input_text = clean_text_list(correct_input_text, ignore_word) - user_input_text = clean_text_list(user_input_text, ignore_word) - - correct_table_text = clean_text_list(correct_table_text) - user_table_text = clean_text_list(user_table_text) - - correct_chart_title = clean_text_list(correct_chart_title) - user_chart_title = clean_text_list(user_chart_title) - - # 리스트를 하나의 문자열로 변경 - correct_input_text_str = ''.join(correct_input_text) - user_input_text_str = ''.join(user_input_text) - - correct_table_text_str = ''.join(correct_table_text) - user_table_text_str = ''.join(user_table_text) - - correct_chart_title_str = ''.join(correct_chart_title) - user_chart_title_str = ''.join(user_chart_title) - - print("user_input_text as string:") - print(user_input_text_str) - print("\n") - print("correct_input_text_answer as string:") - print(correct_input_text_str) - - # 문자열의 차이를 비교 - text_diff = difflib.ndiff(correct_input_text_str, user_input_text_str) - table_text_diff = difflib.ndiff(correct_table_text_str, user_table_text_str) - chart_title_diff = difflib.ndiff(correct_chart_title_str, user_chart_title_str) - - # text_diff = difflib.ndiff(correct_input_text, user_input_text) - # table_text_diff = difflib.ndiff(correct_table_text, user_table_text) - # chart_title_diff = difflib.ndiff(correct_chart_title, user_chart_title) - # diff_list = list(diff) - text_list = list(text_diff) - table_list = list(table_text_diff) - chart_list = list(chart_title_diff) - - diff_list = text_list + table_list + chart_list - # diff_list = text_list + table_list - - # 차이점을 정리하여 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') - - # 채점결과 저장할 리스트 - score_results = [] - - for user_answer_file in xml_files: - score_result = {} - chart_xml = self.binary_to_chartxml(user_answer_file) - score_result['typo'] = self.typo_check(correct_answer_file, user_answer_file, chart_xml) - score_result['score'] = self._score_xml_file(user_answer_file, chart_xml) - # score_result['score']['score_results'][2]['points'] = score_result['typo'][0] - score_results.append(score_result) - return score_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 - row_index = [] - for i, score_result in enumerate(result['score_results']): - current_section = score_result['section'] - - if section_num is None: - section_num = current_section - - # 다음 섹션(문제0 => 문제1)로 넘어갔을 경우 or 마지막 문제일 경우 - if current_section != section_num: - # 이전 섹션의 부분합을 출력 - detail_row[f'문제{section_num}'] = result['partial_scores'][int(section_num)]['score'] - row_index.append(f'문제{section_num}') - section_num = current_section - - detail_row[f'{i+1}'] = score_result['points'] - row_index.append(score_result['id']) - - # 마지막 섹션(문제2)부분합 점수를 출력 - if i == len(result['score_results']) - 1: - detail_row[f'문제{current_section}'] = result['partial_scores'][int(current_section)]['score'] - row_index.append(f'문제{current_section}') - - 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 one_result in results: - total_typo_err_score = one_result['typo'][0] - typo_err_list = one_result['typo'][1:] - - typo_row = { - '파일명': one_result['score']['filename'], - '오타점수': total_typo_err_score, - } - typo_row.update({f'오타{i+1}': typo_err for i, typo_err in enumerate(typo_err_list)}) - - typo_data.append(typo_row) - - typo_df = pd.DataFrame(typo_data) - typo_df = typo_df.transpose() - # transpose 후 행 -> 열 변환했을 때의 인덱스 제거 (기본 인덱스 제거) - typo_df.reset_index(drop=True, inplace=True) - - # transpose 했으므로 첫 행을 컬럼명으로 지정 - typo_df.columns = typo_df.iloc[0] # 첫 행을 컬럼명으로 지정 - typo_df = typo_df.drop(typo_df.index[0]) # 첫 행 제거 - - - # ExcelWriter 객체 생성 - with pd.ExcelWriter(output_path, engine='openpyxl') as writer: - detail_df.to_excel(writer, sheet_name='채점상세내역', index=True) - typo_df.to_excel(writer, sheet_name='오타내역', index=False) - summary_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 = '2507' - exam_round = '2508' - - # 채점하고자 하는 유형은 주석 해제 - exam_types = [ - # 'A', - # 'B', - 'C', - # 'D', - ] - - # test_mode = False - test_mode = True #/TEST 폴더 채점시 - - output_excel_paths = [] - for exam_type in exam_types: - # JSON 채점기준표 파일 (예시:DIW_2503A.json) - scoring_criteria_path = f'./DIW_{exam_round}{exam_type}.json' - - # xml(hml)파일 디렉토리 경로 (예시:./output/2503/A/DIW) - xml_directory = f'./output/{exam_round}/{exam_type}/{"TEST" if test_mode else "DIW"}' - # 오탈자 체크를 위한 정답 파일 경로 (예시:./output/A/DIW/DIW_2503A.hml) - # correct_answer_file = f'./output/{exam_type}/DIW/DIW_{exam_round}{exam_type}.hml' - correct_answer_file = f'./output/{exam_round}/{exam_type}/DIW/DIW_{exam_round}{exam_type}.hml' - - # 엑셀 파일명 (비어있으면 자동생성) (예시:241001_DIW_2503A_채점결과.xlsx) - 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) - if not results: - print(f"❌ 채점 결과가 없습니다. {xml_directory} 폴더에 답안파일이 존재하는지 확인하세요.") - continue - # 채점 결과 엑셀로 저장 - output_excel_paths.append(scorer.export_to_excel(results, output_path)) - - if output_excel_paths: - print(f"채점 결과 엑셀 파일: {output_excel_paths}") - -if __name__ == '__main__': - main() diff --git a/회차별채점자료/2508/DIW_2508A.json b/회차별채점자료/2508/DIW_2508A.json index 9ea62c4..b36b977 100644 --- a/회차별채점자료/2508/DIW_2508A.json +++ b/회차별채점자료/2508/DIW_2508A.json @@ -259,7 +259,7 @@ "searchValue": "DIAT", "value": "굴림", "points": 1, - "category": "FontName.Header", + "category": "Header.FontName", "item": "문구 (DIAT)/① 글꼴 (굴림)" }, "26": { @@ -267,7 +267,7 @@ "searchValue": "DIAT", "value": "900", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/② 크기 (9pt)" }, "27": { @@ -275,7 +275,7 @@ "searchValue": "DIAT", "value": "Right", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)" }, "28": { @@ -343,96 +343,86 @@ "desc": "섹션이 1개 이상이면 점수부여" }, "3": { - "path": "TEXT/COLDEF/@Count", + "path": "./TEXT/COLDEF/@Count", "value": "2", "points": 3, "category": "TwoColumn", "item": "② 다단 2단" }, "4": { - "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width", - "searchValue": "노인일자리", + "path": "//RECTANGLE/SHAPEOBJECT/SIZE/@Width", "value": "60", "points": 2, - "category": "mmSize", + "category": "Rectangle.mmSize", "item": "문구 (노인일자리)/① 크기-너비 (60 mm)" }, "5": { - "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Height", - "searchValue": "노인일자리", + "path": "//RECTANGLE/SHAPEOBJECT/SIZE/@Height", "value": "12", "points": 2, - "category": "mmSize", + "category": "Rectangle.mmSize", "item": "문구 (노인일자리)/② 크기-높이 (12 mm)" }, "6": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE", - "searchValue": "노인일자리", + "path": "//RECTANGLE//LINESHAPE", "value": { "Style": "DoubleSlim", "Width": "283" }, "points": 2, - "category": "LineShape", + "category": "Rectangle.LineShape", "item": "문구 (노인일자리)/③ 테두리 : 이중 실선(1.00mm)", "desc": "1mm = 283pt value['Width']에 pt값 입력" }, "7": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/@Ratio", - "searchValue": "노인일자리", + "path": "//RECTANGLE/@Ratio", "value": "50", "points": 2, - "category": "OneAnswer", + "category": "Rectangle.OneAnswer", "item": "문구 (노인일자리)/④ 글상자 모서리 (반원)", "desc": "모서리 비율 반원:50 / 둥근모양:20" }, "8": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "노인일자리", + "path": "//RECTANGLE//WINDOWBRUSH/@FaceColor", "value": "211,251,193", "points": 2, - "category": "Color", + "category": "Rectangle.Color", "item": "문구 (노인일자리)/⑤ 채우기 : 색상(RGB:211,251,193)" }, "9": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/POSITION/@TreatAsChar", - "searchValue": "노인일자리", + "path": "//RECTANGLE/SHAPEOBJECT/POSITION/@TreatAsChar", "value": "true", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.OneAnswer", "item": "문구 (노인일자리)/⑥ 글상자 위치 (글자처럼 취급)" }, "10": { - "path": "//PARASHAPE[@Id=//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::P[last()]/@ParaShape]/@Align", - "searchValue": "노인일자리", + "path": "//PARASHAPE[@Id='{rect_parashape_id}']/@Align", "value": "Center", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.TextBoxAlign", "item": "문구 (노인일자리)/⑦ 글상자 정렬 (가운데 정렬)" }, "11": { - "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "노인일자리", - "value": "맑은고딕", + "path": ".//RECTANGLE//TEXT/@CharShape", + "value": "맑은 고딕", "points": 1, - "category": "FontName", + "category": "Rectangle.FontName", "item": "문구 (노인일자리)/⑧ 글씨체 (맑은고딕)" }, "12": { - "path": "//CHARSHAPE[@Id=//RECTANGLE//TEXT[./CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "노인일자리", + "path": "//CHARSHAPE[@Id='{rect_charshape_id}']/@Height", "value": "2200", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.FontSize", "item": "문구 (노인일자리)/⑨ 글씨크기 (2200)", "desc": "1pt당 100" }, "13": { - "path": "//PARASHAPE[@Id=//RECTANGLE//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "노인일자리", + "path": "//PARASHAPE[@Id={rect_parashape_id}]/@Align", "value": "Center", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.TextBoxAlign", "item": "문구 (노인일자리)/⑩ 정렬 (가운데 정렬)" }, "14": { diff --git a/회차별채점자료/2508/DIW_2508B.json b/회차별채점자료/2508/DIW_2508B.json index bb67be2..ad2cf4e 100644 --- a/회차별채점자료/2508/DIW_2508B.json +++ b/회차별채점자료/2508/DIW_2508B.json @@ -259,7 +259,7 @@ "searchValue": "DIAT", "value": "굴림", "points": 1, - "category": "FontName.Header", + "category": "Header.FontName", "item": "문구 (DIAT)/① 글꼴 (굴림)" }, "26": { @@ -267,7 +267,7 @@ "searchValue": "DIAT", "value": "900", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/② 크기 (9pt)" }, "27": { @@ -275,7 +275,7 @@ "searchValue": "DIAT", "value": "Right", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)" }, "28": { @@ -343,96 +343,86 @@ "desc": "섹션이 1개 이상이면 점수부여" }, "3": { - "path": "TEXT/COLDEF/@Count", + "path": "./TEXT/COLDEF/@Count", "value": "2", "points": 3, "category": "TwoColumn", "item": "② 다단 2단" }, "4": { - "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width", - "searchValue": "기능경진대회", + "path": "//RECTANGLE/SHAPEOBJECT/SIZE/@Width", "value": "60", "points": 2, - "category": "mmSize", + "category": "Rectangle.mmSize", "item": "문구 (기능경진대회)/① 크기-너비 (60 mm)" }, "5": { - "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Height", - "searchValue": "기능경진대회", + "path": "//RECTANGLE/SHAPEOBJECT/SIZE/@Height", "value": "12", "points": 2, - "category": "mmSize", + "category": "Rectangle.mmSize", "item": "문구 (기능경진대회)/② 크기-높이 (12 mm)" }, "6": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE", - "searchValue": "기능경진대회", + "path": "//RECTANGLE//LINESHAPE", "value": { "Style": "DoubleSlim", "Width": "283" }, "points": 2, - "category": "LineShape", + "category": "Rectangle.LineShape", "item": "문구 (기능경진대회)/③ 테두리 : 이중 실선(1.00mm)", "desc": "1mm = 283pt value['Width']에 pt값 입력" }, "7": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/@Ratio", - "searchValue": "기능경진대회", + "path": "//RECTANGLE/@Ratio", "value": "50", "points": 2, - "category": "OneAnswer", + "category": "Rectangle.OneAnswer", "item": "문구 (기능경진대회)/④ 글상자 모서리 (반원)", "desc": "모서리 비율 반원:50 / 둥근모양:20" }, "8": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "기능경진대회", + "path": "//RECTANGLE//WINDOWBRUSH/@FaceColor", "value": "202,86,167", "points": 2, - "category": "Color", + "category": "Rectangle.Color", "item": "문구 (기능경진대회)/⑤ 채우기 : 색상(RGB:202,86,167)" }, "9": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/POSITION/@TreatAsChar", - "searchValue": "기능경진대회", + "path": "//RECTANGLE/SHAPEOBJECT/POSITION/@TreatAsChar", "value": "true", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.OneAnswer", "item": "문구 (기능경진대회)/⑥ 글상자 위치 (글자처럼 취급)" }, "10": { - "path": "//PARASHAPE[@Id=//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::P[last()]/@ParaShape]/@Align", - "searchValue": "기능경진대회", + "path": "//PARASHAPE[@Id='{rect_parashape_id}']/@Align", "value": "Center", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.TextBoxAlign", "item": "문구 (기능경진대회)/⑦ 글상자 정렬 (가운데 정렬)" }, "11": { - "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "기능경진대회", + "path": ".//RECTANGLE//TEXT/@CharShape", "value": "견고딕", "points": 1, - "category": "FontName", + "category": "Rectangle.FontName", "item": "문구 (기능경진대회)/⑧ 글씨체 (견고딕)" }, "12": { - "path": "//CHARSHAPE[@Id=//RECTANGLE//TEXT[./CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "기능경진대회", + "path": "//CHARSHAPE[@Id='{rect_charshape_id}']/@Height", "value": "2200", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.FontSize", "item": "문구 (기능경진대회)/⑨ 글씨크기 (2200)", "desc": "1pt당 100" }, "13": { - "path": "//PARASHAPE[@Id=//RECTANGLE//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "기능경진대회", + "path": "//PARASHAPE[@Id={rect_parashape_id}]/@Align", "value": "Center", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.TextBoxAlign", "item": "문구 (기능경진대회)/⑩ 정렬 (가운데 정렬)" }, "14": { diff --git a/회차별채점자료/2508/DIW_2508C.json b/회차별채점자료/2508/DIW_2508C.json index 3df41c9..a0bb67b 100644 --- a/회차별채점자료/2508/DIW_2508C.json +++ b/회차별채점자료/2508/DIW_2508C.json @@ -256,11 +256,10 @@ }, "25": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "page": 1, "searchValue": "DIAT", "value": "궁서", "points": 1, - "category": "FontName.Header", + "category": "Header.FontName", "item": "문구 (DIAT)/① 글꼴 (궁서)" }, "26": { @@ -268,7 +267,7 @@ "searchValue": "DIAT", "value": "900", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/② 크기 (9pt)" }, "27": { @@ -276,7 +275,7 @@ "searchValue": "DIAT", "value": "Right", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)" }, "28": { @@ -344,96 +343,86 @@ "desc": "섹션이 1개 이상이면 점수부여" }, "3": { - "path": "TEXT/COLDEF/@Count", + "path": "./TEXT/COLDEF/@Count", "value": "2", "points": 3, "category": "TwoColumn", "item": "② 다단 2단" }, "4": { - "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width", - "searchValue": "구강건강관리", + "path": "//RECTANGLE/SHAPEOBJECT/SIZE/@Width", "value": "60", "points": 2, - "category": "mmSize", + "category": "Rectangle.mmSize", "item": "문구 (구강건강관리)/① 크기-너비 (60 mm)" }, "5": { - "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Height", - "searchValue": "구강건강관리", + "path": "//RECTANGLE/SHAPEOBJECT/SIZE/@Height", "value": "12", "points": 2, - "category": "mmSize", + "category": "Rectangle.mmSize", "item": "문구 (구강건강관리)/② 크기-높이 (12 mm)" }, "6": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE", - "searchValue": "구강건강관리", + "path": "//RECTANGLE//LINESHAPE", "value": { "Style": "DoubleSlim", "Width": "283" }, "points": 2, - "category": "LineShape", + "category": "Rectangle.LineShape", "item": "문구 (구강건강관리)/③ 테두리 : 이중 실선(1.00mm)", "desc": "1mm = 283pt value['Width']에 pt값 입력" }, "7": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/@Ratio", - "searchValue": "구강건강관리", + "path": "//RECTANGLE/@Ratio", "value": "20", "points": 2, - "category": "OneAnswer", + "category": "Rectangle.OneAnswer", "item": "문구 (구강건강관리)/④ 글상자 모서리 (반원)", "desc": "모서리 비율 반원:50 / 둥근모양:20" }, "8": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "구강건강관리", + "path": "//RECTANGLE//WINDOWBRUSH/@FaceColor", "value": "187,140,209", "points": 2, - "category": "Color", + "category": "Rectangle.Color", "item": "문구 (구강건강관리)/⑤ 채우기 : 색상(RGB:187,140,209)" }, "9": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/POSITION/@TreatAsChar", - "searchValue": "구강건강관리", + "path": "//RECTANGLE/SHAPEOBJECT/POSITION/@TreatAsChar", "value": "true", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.OneAnswer", "item": "문구 (구강건강관리)/⑥ 글상자 위치 (글자처럼 취급)" }, "10": { - "path": "//PARASHAPE[@Id=//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::P[last()]/@ParaShape]/@Align", - "searchValue": "구강건강관리", + "path": "//PARASHAPE[@Id='{rect_parashape_id}']/@Align", "value": "Center", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.TextBoxAlign", "item": "문구 (구강건강관리)/⑦ 글상자 정렬 (가운데 정렬)" }, "11": { - "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "구강건강관리", + "path": ".//RECTANGLE//TEXT/@CharShape", "value": "맑은 고딕", "points": 1, - "category": "FontName", + "category": "Rectangle.FontName", "item": "문구 (구강건강관리)/⑧ 글씨체 (맑은 고딕)" }, "12": { - "path": "//CHARSHAPE[@Id=//RECTANGLE//TEXT[./CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "구강건강관리", + "path": "//CHARSHAPE[@Id='{rect_charshape_id}']/@Height", "value": "2300", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.FontSize", "item": "문구 (구강건강관리)/⑨ 글씨크기 (2300)", "desc": "1pt당 100" }, "13": { - "path": "//PARASHAPE[@Id=//RECTANGLE//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "구강건강관리", + "path": "//PARASHAPE[@Id={rect_parashape_id}]/@Align", "value": "Center", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.TextBoxAlign", "item": "문구 (구강건강관리)/⑩ 정렬 (가운데 정렬)" }, "14": { diff --git a/회차별채점자료/2508/DIW_2508D.json b/회차별채점자료/2508/DIW_2508D.json index 684479e..4c904b0 100644 --- a/회차별채점자료/2508/DIW_2508D.json +++ b/회차별채점자료/2508/DIW_2508D.json @@ -259,7 +259,7 @@ "searchValue": "DIAT", "value": "궁서", "points": 1, - "category": "FontName.Header", + "category": "Header.FontName", "item": "문구 (DIAT)/① 글꼴 (궁서)" }, "26": { @@ -267,7 +267,7 @@ "searchValue": "DIAT", "value": "900", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/② 크기 (9pt)" }, "27": { @@ -275,7 +275,7 @@ "searchValue": "DIAT", "value": "Right", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)" }, "28": { @@ -343,96 +343,86 @@ "desc": "섹션이 1개 이상이면 점수부여" }, "3": { - "path": "TEXT/COLDEF/@Count", + "path": "./TEXT/COLDEF/@Count", "value": "2", "points": 3, "category": "TwoColumn", "item": "② 다단 2단" }, "4": { - "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width", - "searchValue": "매력적인 강원도", + "path": "//RECTANGLE/SHAPEOBJECT/SIZE/@Width", "value": "68", "points": 2, - "category": "mmSize", + "category": "Rectangle.mmSize", "item": "문구 (매력적인 강원도)/① 크기-너비 (68 mm)" }, "5": { - "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Height", - "searchValue": "매력적인 강원도", + "path": "//RECTANGLE/SHAPEOBJECT/SIZE/@Height", "value": "12", "points": 2, - "category": "mmSize", + "category": "Rectangle.mmSize", "item": "문구 (매력적인 강원도)/② 크기-높이 (12 mm)" }, "6": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE", - "searchValue": "매력적인 강원도", + "path": "//RECTANGLE//LINESHAPE", "value": { "Style": "DoubleSlim", "Width": "283" }, "points": 2, - "category": "LineShape", + "category": "Rectangle.LineShape", "item": "문구 (매력적인 강원도)/③ 테두리 : 이중 실선(1.00mm)", "desc": "1mm = 283pt value['Width']에 pt값 입력" }, "7": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/@Ratio", - "searchValue": "매력적인 강원도", + "path": "//RECTANGLE/@Ratio", "value": "50", "points": 2, - "category": "OneAnswer", + "category": "Rectangle.OneAnswer", "item": "문구 (매력적인 강원도)/④ 글상자 모서리 (반원)", "desc": "모서리 비율 반원:50 / 둥근모양:20" }, "8": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "매력적인 강원도", + "path": "//RECTANGLE//WINDOWBRUSH/@FaceColor", "value": "130,159,32", "points": 2, - "category": "Color", + "category": "Rectangle.Color", "item": "문구 (매력적인 강원도)/⑤ 채우기 : 색상(RGB:130,159,32)" }, "9": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/POSITION/@TreatAsChar", - "searchValue": "매력적인 강원도", + "path": "//RECTANGLE/SHAPEOBJECT/POSITION/@TreatAsChar", "value": "true", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.OneAnswer", "item": "문구 (매력적인 강원도)/⑥ 글상자 위치 (글자처럼 취급)" }, "10": { - "path": "//PARASHAPE[@Id=//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::P[last()]/@ParaShape]/@Align", - "searchValue": "매력적인 강원도", + "path": "//PARASHAPE[@Id='{rect_parashape_id}']/@Align", "value": "Center", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.TextBoxAlign", "item": "문구 (매력적인 강원도)/⑦ 글상자 정렬 (가운데 정렬)" }, "11": { - "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "매력적인 강원도", + "path": ".//RECTANGLE//TEXT/@CharShape", "value": "굴림체", "points": 1, - "category": "FontName", + "category": "Rectangle.FontName", "item": "문구 (매력적인 강원도)/⑧ 글씨체 (굴림체)" }, "12": { - "path": "//CHARSHAPE[@Id=//RECTANGLE//TEXT[./CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "매력적인 강원도", + "path": "//CHARSHAPE[@Id='{rect_charshape_id}']/@Height", "value": "2300", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.FontSize", "item": "문구 (매력적인 강원도)/⑨ 글씨크기 (2300)", "desc": "1pt당 100" }, "13": { - "path": "//PARASHAPE[@Id=//RECTANGLE//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "매력적인 강원도", + "path": "//PARASHAPE[@Id={rect_parashape_id}]/@Align", "value": "Center", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.TextBoxAlign", "item": "문구 (매력적인 강원도)/⑩ 정렬 (가운데 정렬)" }, "14": { diff --git a/회차별채점자료/2508/JSON/DIW_2508A.json b/회차별채점자료/2508/JSON/DIW_2508A.json index 9ea62c4..b36b977 100644 --- a/회차별채점자료/2508/JSON/DIW_2508A.json +++ b/회차별채점자료/2508/JSON/DIW_2508A.json @@ -259,7 +259,7 @@ "searchValue": "DIAT", "value": "굴림", "points": 1, - "category": "FontName.Header", + "category": "Header.FontName", "item": "문구 (DIAT)/① 글꼴 (굴림)" }, "26": { @@ -267,7 +267,7 @@ "searchValue": "DIAT", "value": "900", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/② 크기 (9pt)" }, "27": { @@ -275,7 +275,7 @@ "searchValue": "DIAT", "value": "Right", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)" }, "28": { @@ -343,96 +343,86 @@ "desc": "섹션이 1개 이상이면 점수부여" }, "3": { - "path": "TEXT/COLDEF/@Count", + "path": "./TEXT/COLDEF/@Count", "value": "2", "points": 3, "category": "TwoColumn", "item": "② 다단 2단" }, "4": { - "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width", - "searchValue": "노인일자리", + "path": "//RECTANGLE/SHAPEOBJECT/SIZE/@Width", "value": "60", "points": 2, - "category": "mmSize", + "category": "Rectangle.mmSize", "item": "문구 (노인일자리)/① 크기-너비 (60 mm)" }, "5": { - "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Height", - "searchValue": "노인일자리", + "path": "//RECTANGLE/SHAPEOBJECT/SIZE/@Height", "value": "12", "points": 2, - "category": "mmSize", + "category": "Rectangle.mmSize", "item": "문구 (노인일자리)/② 크기-높이 (12 mm)" }, "6": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE", - "searchValue": "노인일자리", + "path": "//RECTANGLE//LINESHAPE", "value": { "Style": "DoubleSlim", "Width": "283" }, "points": 2, - "category": "LineShape", + "category": "Rectangle.LineShape", "item": "문구 (노인일자리)/③ 테두리 : 이중 실선(1.00mm)", "desc": "1mm = 283pt value['Width']에 pt값 입력" }, "7": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/@Ratio", - "searchValue": "노인일자리", + "path": "//RECTANGLE/@Ratio", "value": "50", "points": 2, - "category": "OneAnswer", + "category": "Rectangle.OneAnswer", "item": "문구 (노인일자리)/④ 글상자 모서리 (반원)", "desc": "모서리 비율 반원:50 / 둥근모양:20" }, "8": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "노인일자리", + "path": "//RECTANGLE//WINDOWBRUSH/@FaceColor", "value": "211,251,193", "points": 2, - "category": "Color", + "category": "Rectangle.Color", "item": "문구 (노인일자리)/⑤ 채우기 : 색상(RGB:211,251,193)" }, "9": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/POSITION/@TreatAsChar", - "searchValue": "노인일자리", + "path": "//RECTANGLE/SHAPEOBJECT/POSITION/@TreatAsChar", "value": "true", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.OneAnswer", "item": "문구 (노인일자리)/⑥ 글상자 위치 (글자처럼 취급)" }, "10": { - "path": "//PARASHAPE[@Id=//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::P[last()]/@ParaShape]/@Align", - "searchValue": "노인일자리", + "path": "//PARASHAPE[@Id='{rect_parashape_id}']/@Align", "value": "Center", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.TextBoxAlign", "item": "문구 (노인일자리)/⑦ 글상자 정렬 (가운데 정렬)" }, "11": { - "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "노인일자리", - "value": "맑은고딕", + "path": ".//RECTANGLE//TEXT/@CharShape", + "value": "맑은 고딕", "points": 1, - "category": "FontName", + "category": "Rectangle.FontName", "item": "문구 (노인일자리)/⑧ 글씨체 (맑은고딕)" }, "12": { - "path": "//CHARSHAPE[@Id=//RECTANGLE//TEXT[./CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "노인일자리", + "path": "//CHARSHAPE[@Id='{rect_charshape_id}']/@Height", "value": "2200", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.FontSize", "item": "문구 (노인일자리)/⑨ 글씨크기 (2200)", "desc": "1pt당 100" }, "13": { - "path": "//PARASHAPE[@Id=//RECTANGLE//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "노인일자리", + "path": "//PARASHAPE[@Id={rect_parashape_id}]/@Align", "value": "Center", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.TextBoxAlign", "item": "문구 (노인일자리)/⑩ 정렬 (가운데 정렬)" }, "14": { diff --git a/회차별채점자료/2508/JSON/DIW_2508B.json b/회차별채점자료/2508/JSON/DIW_2508B.json index bb67be2..ad2cf4e 100644 --- a/회차별채점자료/2508/JSON/DIW_2508B.json +++ b/회차별채점자료/2508/JSON/DIW_2508B.json @@ -259,7 +259,7 @@ "searchValue": "DIAT", "value": "굴림", "points": 1, - "category": "FontName.Header", + "category": "Header.FontName", "item": "문구 (DIAT)/① 글꼴 (굴림)" }, "26": { @@ -267,7 +267,7 @@ "searchValue": "DIAT", "value": "900", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/② 크기 (9pt)" }, "27": { @@ -275,7 +275,7 @@ "searchValue": "DIAT", "value": "Right", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)" }, "28": { @@ -343,96 +343,86 @@ "desc": "섹션이 1개 이상이면 점수부여" }, "3": { - "path": "TEXT/COLDEF/@Count", + "path": "./TEXT/COLDEF/@Count", "value": "2", "points": 3, "category": "TwoColumn", "item": "② 다단 2단" }, "4": { - "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width", - "searchValue": "기능경진대회", + "path": "//RECTANGLE/SHAPEOBJECT/SIZE/@Width", "value": "60", "points": 2, - "category": "mmSize", + "category": "Rectangle.mmSize", "item": "문구 (기능경진대회)/① 크기-너비 (60 mm)" }, "5": { - "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Height", - "searchValue": "기능경진대회", + "path": "//RECTANGLE/SHAPEOBJECT/SIZE/@Height", "value": "12", "points": 2, - "category": "mmSize", + "category": "Rectangle.mmSize", "item": "문구 (기능경진대회)/② 크기-높이 (12 mm)" }, "6": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE", - "searchValue": "기능경진대회", + "path": "//RECTANGLE//LINESHAPE", "value": { "Style": "DoubleSlim", "Width": "283" }, "points": 2, - "category": "LineShape", + "category": "Rectangle.LineShape", "item": "문구 (기능경진대회)/③ 테두리 : 이중 실선(1.00mm)", "desc": "1mm = 283pt value['Width']에 pt값 입력" }, "7": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/@Ratio", - "searchValue": "기능경진대회", + "path": "//RECTANGLE/@Ratio", "value": "50", "points": 2, - "category": "OneAnswer", + "category": "Rectangle.OneAnswer", "item": "문구 (기능경진대회)/④ 글상자 모서리 (반원)", "desc": "모서리 비율 반원:50 / 둥근모양:20" }, "8": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "기능경진대회", + "path": "//RECTANGLE//WINDOWBRUSH/@FaceColor", "value": "202,86,167", "points": 2, - "category": "Color", + "category": "Rectangle.Color", "item": "문구 (기능경진대회)/⑤ 채우기 : 색상(RGB:202,86,167)" }, "9": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/POSITION/@TreatAsChar", - "searchValue": "기능경진대회", + "path": "//RECTANGLE/SHAPEOBJECT/POSITION/@TreatAsChar", "value": "true", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.OneAnswer", "item": "문구 (기능경진대회)/⑥ 글상자 위치 (글자처럼 취급)" }, "10": { - "path": "//PARASHAPE[@Id=//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::P[last()]/@ParaShape]/@Align", - "searchValue": "기능경진대회", + "path": "//PARASHAPE[@Id='{rect_parashape_id}']/@Align", "value": "Center", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.TextBoxAlign", "item": "문구 (기능경진대회)/⑦ 글상자 정렬 (가운데 정렬)" }, "11": { - "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "기능경진대회", + "path": ".//RECTANGLE//TEXT/@CharShape", "value": "견고딕", "points": 1, - "category": "FontName", + "category": "Rectangle.FontName", "item": "문구 (기능경진대회)/⑧ 글씨체 (견고딕)" }, "12": { - "path": "//CHARSHAPE[@Id=//RECTANGLE//TEXT[./CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "기능경진대회", + "path": "//CHARSHAPE[@Id='{rect_charshape_id}']/@Height", "value": "2200", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.FontSize", "item": "문구 (기능경진대회)/⑨ 글씨크기 (2200)", "desc": "1pt당 100" }, "13": { - "path": "//PARASHAPE[@Id=//RECTANGLE//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "기능경진대회", + "path": "//PARASHAPE[@Id={rect_parashape_id}]/@Align", "value": "Center", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.TextBoxAlign", "item": "문구 (기능경진대회)/⑩ 정렬 (가운데 정렬)" }, "14": { diff --git a/회차별채점자료/2508/JSON/DIW_2508C.json b/회차별채점자료/2508/JSON/DIW_2508C.json index 3df41c9..a0bb67b 100644 --- a/회차별채점자료/2508/JSON/DIW_2508C.json +++ b/회차별채점자료/2508/JSON/DIW_2508C.json @@ -256,11 +256,10 @@ }, "25": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "page": 1, "searchValue": "DIAT", "value": "궁서", "points": 1, - "category": "FontName.Header", + "category": "Header.FontName", "item": "문구 (DIAT)/① 글꼴 (궁서)" }, "26": { @@ -268,7 +267,7 @@ "searchValue": "DIAT", "value": "900", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/② 크기 (9pt)" }, "27": { @@ -276,7 +275,7 @@ "searchValue": "DIAT", "value": "Right", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)" }, "28": { @@ -344,96 +343,86 @@ "desc": "섹션이 1개 이상이면 점수부여" }, "3": { - "path": "TEXT/COLDEF/@Count", + "path": "./TEXT/COLDEF/@Count", "value": "2", "points": 3, "category": "TwoColumn", "item": "② 다단 2단" }, "4": { - "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width", - "searchValue": "구강건강관리", + "path": "//RECTANGLE/SHAPEOBJECT/SIZE/@Width", "value": "60", "points": 2, - "category": "mmSize", + "category": "Rectangle.mmSize", "item": "문구 (구강건강관리)/① 크기-너비 (60 mm)" }, "5": { - "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Height", - "searchValue": "구강건강관리", + "path": "//RECTANGLE/SHAPEOBJECT/SIZE/@Height", "value": "12", "points": 2, - "category": "mmSize", + "category": "Rectangle.mmSize", "item": "문구 (구강건강관리)/② 크기-높이 (12 mm)" }, "6": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE", - "searchValue": "구강건강관리", + "path": "//RECTANGLE//LINESHAPE", "value": { "Style": "DoubleSlim", "Width": "283" }, "points": 2, - "category": "LineShape", + "category": "Rectangle.LineShape", "item": "문구 (구강건강관리)/③ 테두리 : 이중 실선(1.00mm)", "desc": "1mm = 283pt value['Width']에 pt값 입력" }, "7": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/@Ratio", - "searchValue": "구강건강관리", + "path": "//RECTANGLE/@Ratio", "value": "20", "points": 2, - "category": "OneAnswer", + "category": "Rectangle.OneAnswer", "item": "문구 (구강건강관리)/④ 글상자 모서리 (반원)", "desc": "모서리 비율 반원:50 / 둥근모양:20" }, "8": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "구강건강관리", + "path": "//RECTANGLE//WINDOWBRUSH/@FaceColor", "value": "187,140,209", "points": 2, - "category": "Color", + "category": "Rectangle.Color", "item": "문구 (구강건강관리)/⑤ 채우기 : 색상(RGB:187,140,209)" }, "9": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/POSITION/@TreatAsChar", - "searchValue": "구강건강관리", + "path": "//RECTANGLE/SHAPEOBJECT/POSITION/@TreatAsChar", "value": "true", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.OneAnswer", "item": "문구 (구강건강관리)/⑥ 글상자 위치 (글자처럼 취급)" }, "10": { - "path": "//PARASHAPE[@Id=//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::P[last()]/@ParaShape]/@Align", - "searchValue": "구강건강관리", + "path": "//PARASHAPE[@Id='{rect_parashape_id}']/@Align", "value": "Center", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.TextBoxAlign", "item": "문구 (구강건강관리)/⑦ 글상자 정렬 (가운데 정렬)" }, "11": { - "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "구강건강관리", + "path": ".//RECTANGLE//TEXT/@CharShape", "value": "맑은 고딕", "points": 1, - "category": "FontName", + "category": "Rectangle.FontName", "item": "문구 (구강건강관리)/⑧ 글씨체 (맑은 고딕)" }, "12": { - "path": "//CHARSHAPE[@Id=//RECTANGLE//TEXT[./CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "구강건강관리", + "path": "//CHARSHAPE[@Id='{rect_charshape_id}']/@Height", "value": "2300", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.FontSize", "item": "문구 (구강건강관리)/⑨ 글씨크기 (2300)", "desc": "1pt당 100" }, "13": { - "path": "//PARASHAPE[@Id=//RECTANGLE//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "구강건강관리", + "path": "//PARASHAPE[@Id={rect_parashape_id}]/@Align", "value": "Center", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.TextBoxAlign", "item": "문구 (구강건강관리)/⑩ 정렬 (가운데 정렬)" }, "14": { diff --git a/회차별채점자료/2508/JSON/DIW_2508D.json b/회차별채점자료/2508/JSON/DIW_2508D.json index 684479e..4c904b0 100644 --- a/회차별채점자료/2508/JSON/DIW_2508D.json +++ b/회차별채점자료/2508/JSON/DIW_2508D.json @@ -259,7 +259,7 @@ "searchValue": "DIAT", "value": "궁서", "points": 1, - "category": "FontName.Header", + "category": "Header.FontName", "item": "문구 (DIAT)/① 글꼴 (궁서)" }, "26": { @@ -267,7 +267,7 @@ "searchValue": "DIAT", "value": "900", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/② 크기 (9pt)" }, "27": { @@ -275,7 +275,7 @@ "searchValue": "DIAT", "value": "Right", "points": 1, - "category": "OneAnswer.Header", + "category": "Header.OneAnswer", "item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)" }, "28": { @@ -343,96 +343,86 @@ "desc": "섹션이 1개 이상이면 점수부여" }, "3": { - "path": "TEXT/COLDEF/@Count", + "path": "./TEXT/COLDEF/@Count", "value": "2", "points": 3, "category": "TwoColumn", "item": "② 다단 2단" }, "4": { - "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width", - "searchValue": "매력적인 강원도", + "path": "//RECTANGLE/SHAPEOBJECT/SIZE/@Width", "value": "68", "points": 2, - "category": "mmSize", + "category": "Rectangle.mmSize", "item": "문구 (매력적인 강원도)/① 크기-너비 (68 mm)" }, "5": { - "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Height", - "searchValue": "매력적인 강원도", + "path": "//RECTANGLE/SHAPEOBJECT/SIZE/@Height", "value": "12", "points": 2, - "category": "mmSize", + "category": "Rectangle.mmSize", "item": "문구 (매력적인 강원도)/② 크기-높이 (12 mm)" }, "6": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE", - "searchValue": "매력적인 강원도", + "path": "//RECTANGLE//LINESHAPE", "value": { "Style": "DoubleSlim", "Width": "283" }, "points": 2, - "category": "LineShape", + "category": "Rectangle.LineShape", "item": "문구 (매력적인 강원도)/③ 테두리 : 이중 실선(1.00mm)", "desc": "1mm = 283pt value['Width']에 pt값 입력" }, "7": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/@Ratio", - "searchValue": "매력적인 강원도", + "path": "//RECTANGLE/@Ratio", "value": "50", "points": 2, - "category": "OneAnswer", + "category": "Rectangle.OneAnswer", "item": "문구 (매력적인 강원도)/④ 글상자 모서리 (반원)", "desc": "모서리 비율 반원:50 / 둥근모양:20" }, "8": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "매력적인 강원도", + "path": "//RECTANGLE//WINDOWBRUSH/@FaceColor", "value": "130,159,32", "points": 2, - "category": "Color", + "category": "Rectangle.Color", "item": "문구 (매력적인 강원도)/⑤ 채우기 : 색상(RGB:130,159,32)" }, "9": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/POSITION/@TreatAsChar", - "searchValue": "매력적인 강원도", + "path": "//RECTANGLE/SHAPEOBJECT/POSITION/@TreatAsChar", "value": "true", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.OneAnswer", "item": "문구 (매력적인 강원도)/⑥ 글상자 위치 (글자처럼 취급)" }, "10": { - "path": "//PARASHAPE[@Id=//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::P[last()]/@ParaShape]/@Align", - "searchValue": "매력적인 강원도", + "path": "//PARASHAPE[@Id='{rect_parashape_id}']/@Align", "value": "Center", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.TextBoxAlign", "item": "문구 (매력적인 강원도)/⑦ 글상자 정렬 (가운데 정렬)" }, "11": { - "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "매력적인 강원도", + "path": ".//RECTANGLE//TEXT/@CharShape", "value": "굴림체", "points": 1, - "category": "FontName", + "category": "Rectangle.FontName", "item": "문구 (매력적인 강원도)/⑧ 글씨체 (굴림체)" }, "12": { - "path": "//CHARSHAPE[@Id=//RECTANGLE//TEXT[./CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "매력적인 강원도", + "path": "//CHARSHAPE[@Id='{rect_charshape_id}']/@Height", "value": "2300", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.FontSize", "item": "문구 (매력적인 강원도)/⑨ 글씨크기 (2300)", "desc": "1pt당 100" }, "13": { - "path": "//PARASHAPE[@Id=//RECTANGLE//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "매력적인 강원도", + "path": "//PARASHAPE[@Id={rect_parashape_id}]/@Align", "value": "Center", "points": 1, - "category": "OneAnswer", + "category": "Rectangle.TextBoxAlign", "item": "문구 (매력적인 강원도)/⑩ 정렬 (가운데 정렬)" }, "14": { diff --git a/회차별채점자료/2508/_DIW_2508A.json b/회차별채점자료/2508/_DIW_2508A.json deleted file mode 100644 index d8f0f4d..0000000 --- a/회차별채점자료/2508/_DIW_2508A.json +++ /dev/null @@ -1,840 +0,0 @@ -{ - "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": "199,58,82", - "points": 2, - "category": "Color", - "item": "문구 (노인일자리참여자모집)/② 채우기 : 색상(RGB:199,58,82)" - }, - "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": "137,221,202", - "points": 2, - "category": "Color", - "item": "어/③ 면색 : 색상(RGB:137,221,202)" - }, - "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": "문구 (어르신들에게 다양한 일자리와 봉사활동 기회)/① BOLD" - }, - "13": { - "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]", - "searchValue": "어르신들에게 다양한 일자리와 봉사활동 기회", - "value": "UNDERLINE", - "points": 2, - "category": "FontAttribute", - "item": "문구 (어르신들에게 다양한 일자리와 봉사활동 기회)/② UNDERLINE" - }, - "14": { - "path": "//CHAR[contains(string(.),'{char1}')]/text()", - "path2": "//CHAR[contains(string(.),'{char2}')]/text()", - "path3": "//CHAR[contains(string(.),'{char3}')]/text()", - "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(),'{match_str}')]/ancestor::P/@ParaShape]/@Align", - "match_str": "모집안내", - "value": "Center", - "points": 1, - "category": "Align", - "item": "문구 (▶ 모집안내 ◀)/② 정렬 (가운데 정렬)" - }, - "17": { - "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", - "hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]", - "searchValue": "공익활동형, 사회서비스형, 공동체사업단", - "value": "BOLD", - "points": 1, - "category": "FontAttribute", - "item": "문구 (공익활동형, 사회서비스형, 공동체사업단)/① BOLD" - }, - "18": { - "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", - "hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]", - "searchValue": "공익활동형, 사회서비스형, 공동체사업단", - "value": "ITALIC", - "points": 1, - "category": "FontAttribute", - "item": "문구 (공익활동형, 사회서비스형, 공동체사업단)/② ITALIC" - }, - "19": { - "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/following-sibling::P[1]/@ParaShape]/PARAMARGIN", - "searchValue": "기타사항", - "value": { - "Left": 15, - "Indent": 12 - }, - "points": 2, - "category": "ParaShape", - "item": "문구 (※ 기타… 이하 문단)/왼쪽여백 (15), 내어쓰기 (12)", - "desc": "내부적으로 내어쓰기는 음수값 / JSON value값은 양수로 입력" - }, - "20": { - "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]/@Height", - "searchValue": "2025. 08. 23", - "value": "1300", - "points": 1, - "category": "OneAnswer", - "item": "문구 (2025. 08. 23)/① 크기 (1300)", - "desc": "1pt당 100" - }, - "21": { - "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/@ParaShape]/@Align", - "searchValue": "2025. 08. 23", - "value": "Center", - "points": 1, - "category": "OneAnswer", - "item": "문구 (2025. 08. 23)/② 정렬 (가운데 정렬)" - }, - "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": "2400", - "points": 1, - "category": "OneAnswer", - "item": "문구 (시니어클럽)/② 크기 (2400)" - }, - "24": { - "path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/ancestor::P/@ParaShape]/@Align", - "searchValue": "시니어클럽", - "value": "Center", - "points": 1, - "category": "OneAnswer", - "item": "문구 (시니어클럽)/③ 정렬 (가운데 정렬)" - }, - "25": { - "path": "//SECTION[1]//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": "HangulSyllable", - "points": 2, - "category": "PageNumber", - "item": "① 쪽 번호 매기기 (가,나,다 순으로)", - "desc1": { - "가,나,다": "HangulSyllable", - "1,2,3": "Digit", - "갑,을,병": "DecagonCircle", - "A,B,C": "LatinCapital", - "a,b,c": "LatinSmall", - "①,②,③": "CircledDigit", - "一,二,三": "Ideograph", - "㉠,㉡,㉢": "CircledHangulJamo", - "ⓐ,ⓑ,ⓒ": "CircledLatinSmall", - "i,ii,iii": "RomanSmall", - "I,II,III": "RomanCapital", - "desc": "정답에 맞는 값 value에 입력" - }, - "desc2": "1, 2페이지 모두 정답이어야 점수 부여" - }, - "29": { - "path": "//PAGENUM/@Pos", - "value": "BottomCenter", - "points": 2, - "category": "PageNumber", - "item": "가운데 아래", - "desc": "1, 2페이지 모두 정답이어야 점수 부여", - "desc2": { - "가운데 아래": "BottomCenter", - "오른쪽 아래": "BottomRight" - } - }, - "30": { - "path": "//PARASHAPE[@Id='{parashape_id}']/PARAMARGIN/@LineSpacing", - "value": "180", - "first_word": "어", - "points": 2, - "category": "LineSpacing", - "item": "문제 1 줄간격 180% 설정", - "desc": "1페이지 문단의 줄간격이 정답이 아닌 문단이 있으면 False(감점), first_word 속성에 [문단 첫글자 장식]에 해당하는 글자를 입력해준다." - } - }, - "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": "TEXT/COLDEF/@Count", - "value": "2", - "points": 3, - "category": "TwoColumn", - "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": "문구 (노인일자리)/② 크기-높이 (12 mm)" - }, - "6": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE", - "searchValue": "노인일자리", - "value": { - "Style": "DoubleSlim", - "Width": "283" - }, - "points": 2, - "category": "LineShape", - "item": "문구 (노인일자리)/③ 테두리 : 이중 실선(1.00mm)", - "desc": "1mm = 283pt value['Width']에 pt값 입력" - }, - "7": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/@Ratio", - "searchValue": "노인일자리", - "value": "50", - "points": 2, - "category": "OneAnswer", - "item": "문구 (노인일자리)/④ 글상자 모서리 (반원)", - "desc": "모서리 비율 반원:50 / 둥근모양:20" - }, - "8": { - "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "노인일자리", - "value": "211,251,193", - "points": 2, - "category": "Color", - "item": "문구 (노인일자리)/⑤ 채우기 : 색상(RGB:211,251,193)" - }, - "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": "2200", - "points": 1, - "category": "OneAnswer", - "item": "문구 (노인일자리)/⑨ 글씨크기 (2200)", - "desc": "1pt당 100" - }, - "13": { - "path": "//PARASHAPE[@Id=//RECTANGLE//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "노인일자리", - "value": "Center", - "points": 1, - "category": "OneAnswer", - "item": "문구 (노인일자리)/⑩ 정렬 (가운데 정렬)" - }, - "14": { - "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG' or @Format='JPEG']", - "value": true, - "points": 2, - "category": "Boolean", - "item": "① 파일명 \"그림A.jpg\" 삽입", - "desc": "첨부 이미지 파일명 손상으로 정상적인 채점이 불가한 경우가 발견되어서 이미지 첨부 여부로 채점 방식 변경 (7/3)" - }, - "15": { - "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG']/@BinData]]/SHAPEOBJECT/SIZE/@Width", - "value": "85", - "points": 2, - "category": "mmSize", - "item": "② 크기-너비 (85 mm)" - }, - "16": { - "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG']/@BinData]]/SHAPEOBJECT/SIZE/@Height", - "value": "40", - "points": 2, - "category": "mmSize", - "item": "③ 크기-높이 (40 mm)" - }, - "17": { - "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@HorzOffset", - "value": "0", - "points": 2, - "category": "mmSize", - "item": "④ 위치 (어울림 : 가로-쪽의 왼쪽 0.0mm)" - }, - "18": { - "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@VertOffset", - "value": "22", - "points": 2, - "category": "mmSize", - "item": "⑤ 위치 (어울림 : 세로-쪽의 위 22 mm)" - }, - "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. 필요성)/② 크기 (1200)" - }, - "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.주요 노인일자리사업)/② 크기 (1200)" - }, - "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": { - "가,나,다": "HangulSyllable", - "1,2,3": "Digit", - "갑,을,병": "DecagonCircle", - "A,B,C": "LatinCapital", - "a,b,c": "LatinSmall", - "①,②,③": "CircledDigit", - "一,二,三": "Ideograph", - "㉠,㉡,㉢": "CircledHangulJamo", - "ⓐ,ⓑ,ⓒ": "CircledLatinSmall", - "i,ii,iii": "RomanSmall", - "I,II,III": "RomanCapital", - "甲,乙,丙": "DecagonCircleHanja", - "+,++,+++": "UserChar", - "정답에 맞는 값 value에 입력": "" - } - }, - "29": { - "path": "boolean(//CHAR[contains(text(),'Improvement')])", - "ignoreWord": "Improvement", - "value": true, - "points": 3, - "category": "Boolean", - "item": "Improvement/영단어 미입력, 대소문자/오타 시 전체 감점", - "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": "제목 문구 (노인일자리 창출 현황(예산:십억원))/② 크기 (1200)" - }, - "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,215,77", - "points": 2, - "category": "Color", - "item": "위쪽 제목 셀/① 색상(RGB:233,215,77)" - }, - "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": "글자모양/② 크기 (1000)" - }, - "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": "ChartOneAnswer", - "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": "제목 문구 (노인 일자리 창출)/② 크기 (1300)" - }, - "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": "ChartOneAnswer", - "item": "X축/① 글꼴 (굴림)" - }, - "54": { - "chart_xpath": "//c:catAx/c:txPr//a:defRPr/@sz", - "value": "900", - "points": 1, - "category": "ChartOneAnswer", - "item": "X축/② 크기 (9pt)" - }, - "55": { - "chart_xpath": "//c:catAx/c:txPr//a:defRPr/@{option}", - "option": "i", - "value": "1", - "points": 1, - "category": "ChartOneAnswer", - "item": "X축/③ 기울임", - "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" - }, - "56": { - "chart_xpath": "//c:valAx/c:txPr//a:ea/@typeface", - "value": "굴림", - "points": 1, - "category": "ChartOneAnswer", - "item": "Y축/① 글꼴 (굴림)" - }, - "57": { - "chart_xpath": "//c:valAx/c:txPr//a:defRPr/@sz", - "value": "900", - "points": 1, - "category": "ChartOneAnswer", - "item": "Y축/② 크기 (9pt)" - }, - "58": { - "chart_xpath": "//c:valAx/c:txPr//a:defRPr/@{option}", - "option": "i", - "value": "1", - "points": 1, - "category": "ChartOneAnswer", - "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" - } - } -} diff --git a/250908_DIW_2508D_채점결과.xlsx b/회차별채점자료/2508/채점결과/250908_DIW_2508D_채점결과.xlsx similarity index 100% rename from 250908_DIW_2508D_채점결과.xlsx rename to 회차별채점자료/2508/채점결과/250908_DIW_2508D_채점결과.xlsx diff --git a/250909_DIW_2508D_채점결과.xlsx b/회차별채점자료/2508/채점결과/250909_DIW_2508D_채점결과.xlsx similarity index 100% rename from 250909_DIW_2508D_채점결과.xlsx rename to 회차별채점자료/2508/채점결과/250909_DIW_2508D_채점결과.xlsx diff --git a/250910_DIW_2522C_채점결과.xlsx b/회차별채점자료/2508/채점결과/250910_DIW_2522C_채점결과.xlsx similarity index 100% rename from 250910_DIW_2522C_채점결과.xlsx rename to 회차별채점자료/2508/채점결과/250910_DIW_2522C_채점결과.xlsx diff --git a/250912_DIW_2508C_채점결과.xlsx b/회차별채점자료/2508/채점결과/250912_DIW_2508C_채점결과.xlsx similarity index 100% rename from 250912_DIW_2508C_채점결과.xlsx rename to 회차별채점자료/2508/채점결과/250912_DIW_2508C_채점결과.xlsx diff --git a/회차별채점자료/2508/_DIW_2508B.json b/회차별채점자료/2522/DIW_2522A.json similarity index 73% rename from 회차별채점자료/2508/_DIW_2508B.json rename to 회차별채점자료/2522/DIW_2522A.json index d6109db..cf251ee 100644 --- a/회차별채점자료/2508/_DIW_2508B.json +++ b/회차별채점자료/2522/DIW_2522A.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": "84,139,241", + "searchValue": "공주맛밤수확체험행사", + "value": "51,69,153", "points": 2, "category": "Color", - "item": "문구 (기능경진대회참가안내)/② 채우기 : 색상(RGB:84,139,241)" + "item": "문구 (공주맛밤수확체험행사)/② 채우기 : 색상(RGB:51,69,153)" }, "3": { "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Width", - "searchValue": "기능경진대회참가안내", - "value": "120", + "searchValue": "공주맛밤수확체험행사", + "value": "110", "tolerance": 1, "points": 2, "category": "mmSize", - "item": "문구 (기능경진대회참가안내)/③ 크기-너비 (120 mm)" + "item": "문구 (공주맛밤수확체험행사)/③ 크기-너비 (110 mm)" }, "4": { "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Height", - "searchValue": "기능경진대회참가안내", + "searchValue": "공주맛밤수확체험행사", "value": "20", "tolerance": 1, "points": 2, "category": "mmSize", - "item": "문구 (기능경진대회참가안내)/④ 크기-높이 (20 mm)" + "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": "2", + "searchValue": "공", "value": { "Height": 2800, "Width": 2800 @@ -112,155 +112,155 @@ "tolerance": 200, "points": 1, "category": "TwoLineSize", - "item": "2/① 모양 (2줄)" + "item": "공/① 모양 (2줄)" }, "9": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "2", - "value": "맑은 고딕", + "searchValue": "공", + "value": "굴림", "points": 1, "category": "FontName", - "item": "2/② 글씨체 (맑은 고딕)" + "item": "공/② 글씨체 (굴림)" }, "10": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "2", - "value": "240,223,102", + "searchValue": "공", + "value": "219,207,102", "points": 2, "category": "Color", - "item": "2/③ 면색 : 색상(RGB:240,223,102)" + "item": "공/③ 면색 : 색상(RGB:219,207,102)" }, "11": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//OUTSIDEMARGIN/@Right", - "searchValue": "2", + "searchValue": "공", "value": "3.0", "tolerance": 1, "points": 2, "category": "mmSize", - "item": "2/④ 본문과의 간격 : 3.0mm" + "item": "공/④ 본문과의 간격 : 3.0mm" }, "12": { "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]", - "searchValue": "지역사회의 기능 수준 향상과 기술 및 기능 개발 촉진", - "value": "BOLD", - "points": 2, - "category": "FontAttribute", - "item": "문구 (지역사회의 기능 수준 향상과 기술 및 기능 개발 촉진)/① BOLD" - }, - "13": { - "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]", - "searchValue": "지역사회의 기능 수준 향상과 기술 및 기능 개발 촉진", + "searchValue": "전국적으로 사랑받는 지역 특산물", "value": "UNDERLINE", "points": 2, "category": "FontAttribute", - "item": "문구 (지역사회의 기능 수준 향상과 기술 및 기능 개발 촉진)/② UNDERLINE" + "item": "문구 (전국적으로 사랑받는 지역 특산물)/① UNDERLINE" + }, + "13": { + "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]", + "searchValue": "전국적으로 사랑받는 지역 특산물", + "value": "ITALIC", + "points": 2, + "category": "FontAttribute", + "item": "문구 (전국적으로 사랑받는 지역 특산물)/② ITALIC" }, "14": { "path": "//CHAR[contains(string(.),'{char1}')]/text()", "path2": "//CHAR[contains(string(.),'{char2}')]/text()", "path3": "//CHAR[contains(string(.),'{char3}')]/text()", - "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(),'{match_str}')]/ancestor::P/@ParaShape]/@Align", - "match_str": "접수안내", + "match_str": "행사안내", "value": "Center", "points": 1, "category": "Align", - "item": "문구 (▶ 접수안내 ◀)/② 정렬 (가운데 정렬)" + "item": "문구 (■ 행사안내 ■)/② 정렬 (가운데 정렬)" }, "17": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", "hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]", - "searchValue": "누구나 참가 가능", + "searchValue": "2025년 09월 20일(토) 13:30 ~ 17:30", "value": "BOLD", "points": 1, "category": "FontAttribute", - "item": "문구 (누구나 참가 가능)/① BOLD" + "item": "문구 (2025년 09월 20일(토) 13:30 ~ 17:30)/① BOLD" }, "18": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", "hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]", - "searchValue": "누구나 참가 가능", - "value": "ITALIC", + "searchValue": "2025년 09월 20일(토) 13:30 ~ 17:30", + "value": "UNDERLINE", "points": 1, "category": "FontAttribute", - "item": "문구 (누구나 참가 가능)/② ITALIC" + "item": "문구 (2025년 09월 20일(토) 13:30 ~ 17:30)/② UNDERLINE" }, "19": { "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/following-sibling::P[1]/@ParaShape]/PARAMARGIN", - "searchValue": "기타사항", + "searchValue": "신청안내", "value": { - "Left": 15, + "Left": 10, "Indent": 12 }, "points": 2, "category": "ParaShape", - "item": "문구 (※ 기타… 이하 문단)/왼쪽여백 (15pt), 내어쓰기 (12pt)", + "item": "문구 (※ 신청안내… 이하 문단)/왼쪽여백 (10pt), 내어쓰기 (12pt)", "desc": "내부적으로 내어쓰기는 음수값 / JSON value값은 양수로 입력" }, "20": { "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]/@Height", - "searchValue": "2025. 08. 23.", - "value": "1300", + "searchValue": "2025. 08. 27.", + "value": "1400", "points": 1, "category": "OneAnswer", - "item": "문구 (2025. 08. 23.)/① 크기 (1300)", + "item": "문구 (2025. 08. 27.)/① 크기 (1400)", "desc": "1pt당 100" }, "21": { "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/@ParaShape]/@Align", - "searchValue": "2025. 08. 23.", + "searchValue": "2025. 08. 27.", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (2025. 08. 23.)/② 정렬 (가운데 정렬)" + "item": "문구 (2025. 08. 27.)/② 정렬 (가운데 정렬)" }, "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": "2400", + "searchValue": "공주시청농촌활력과", + "value": "2200", "points": 1, "category": "OneAnswer", - "item": "문구 (기능경진대회운영위원회)/② 크기 (2400)" + "item": "문구 (공주시청농촌활력과)/② 크기 (2200)" }, "24": { "path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/ancestor::P/@ParaShape]/@Align", - "searchValue": "기능경진대회운영위원회", + "searchValue": "공주시청농촌활력과", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (기능경진대회운영위원회)/③ 정렬 (가운데 정렬)" + "item": "문구 (공주시청농촌활력과)/③ 정렬 (가운데 정렬)" }, "25": { "path": "//SECTION[1]//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", @@ -314,11 +314,11 @@ }, "30": { "path": "//PARASHAPE[@Id='{parashape_id}']/PARAMARGIN/@LineSpacing", - "value": "190", - "first_word": "2", + "value": "200", + "first_word": "공", "points": 2, "category": "LineSpacing", - "item": "문제 1 줄간격 190% 설정", + "item": "문제 1 줄간격 200% 설정", "desc": "1페이지 문단의 줄간격이 정답이 아닌 문단이 있으면 False(감점), first_word 속성에 [문단 첫글자 장식]에 해당하는 글자를 입력해준다." } }, @@ -351,121 +351,121 @@ }, "4": { "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width", - "searchValue": "기능경진대회", - "value": "60", + "searchValue": "아름다운 계절, 가을", + "value": "65", "points": 2, "category": "mmSize", - "item": "문구 (기능경진대회)/① 크기-너비 (60 mm)" + "item": "문구 (아름다운 계절, 가을)/① 크기-너비 (65 mm)" }, "5": { "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Height", - "searchValue": "기능경진대회", + "searchValue": "아름다운 계절, 가을", "value": "12", "points": 2, "category": "mmSize", - "item": "문구 (기능경진대회)/② 크기-높이 (12 mm)" + "item": "문구 (아름다운 계절, 가을)/② 크기-높이 (12 mm)" }, "6": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE", - "searchValue": "기능경진대회", + "searchValue": "아름다운 계절, 가을", "value": { "Style": "DoubleSlim", "Width": "283" }, "points": 2, "category": "LineShape", - "item": "문구 (기능경진대회)/③ 테두리 : 이중 실선(1.00mm)", + "item": "문구 (아름다운 계절, 가을)/③ 테두리 : 이중 실선(1.00mm)", "desc": "1mm = 283pt value['Width']에 pt값 입력" }, "7": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/@Ratio", - "searchValue": "기능경진대회", + "searchValue": "아름다운 계절, 가을", "value": "50", "points": 2, "category": "OneAnswer", - "item": "문구 (기능경진대회)/④ 글상자 모서리 (반원)", + "item": "문구 (아름다운 계절, 가을)/④ 글상자 모서리 (반원)", "desc": "모서리 비율 반원:50 / 둥근모양:20" }, "8": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "기능경진대회", - "value": "202,86,167", + "searchValue": "아름다운 계절, 가을", + "value": "249,173,168", "points": 2, "category": "Color", - "item": "문구 (기능경진대회)/⑤ 채우기 : 색상(RGB:202,86,167)" + "item": "문구 (아름다운 계절, 가을)/⑤ 채우기 : 색상(RGB:249,173,168)" }, "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": "2200", + "searchValue": "아름다운 계절, 가을", + "value": "1700", "points": 1, "category": "OneAnswer", - "item": "문구 (기능경진대회)/⑨ 글씨크기 (2200)", + "item": "문구 (아름다운 계절, 가을)/⑨ 글씨크기 (1700)", "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": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG' or @Format='JPEG']", + "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG']", "value": true, "points": 2, "category": "Boolean", - "item": "① 파일명 \"그림B.jpg\" 삽입", + "item": "① 파일명 \"그림A.jpg\" 삽입", "desc": "첨부 이미지 파일명 손상으로 정상적인 채점이 불가한 경우가 발견되어서 이미지 첨부 여부로 채점 방식 변경 (7/3)" }, "15": { - "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG']/@BinData]]/SHAPEOBJECT/SIZE/@Width", - "value": "85", + "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/SIZE/@Width", + "value": "80", "points": 2, "category": "mmSize", - "item": "② 크기-너비 (85 mm)" + "item": "② 크기-너비 (80 mm)" }, "16": { - "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG']/@BinData]]/SHAPEOBJECT/SIZE/@Height", + "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' or @Format='JPEG']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@HorzOffset", + "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@HorzOffset", "value": "0", "points": 2, "category": "mmSize", "item": "④ 위치 (어울림 : 가로-쪽의 왼쪽 0.0mm)" }, "18": { - "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@VertOffset", + "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@VertOffset", "value": "22", "points": 2, "category": "mmSize", @@ -473,81 +473,81 @@ }, "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. 기능경진대회 종목)/② 크기 (1200)" + "item": "문구② (2. 우리나라의 가을)/② 크기 (1200)" }, "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": "건물의 벽을 이루는 구조 부분", + "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": "CircledLatinCapital", + "searchValue": "기후 변화로 인해 식물의 잎의 색이 변하는 현상", + "value": "DecagonCircleHanja", "points": 2, "category": "OneAnswer", "item": "문구 (전당)/④ 각주 번호모양", @@ -560,7 +560,6 @@ "①,②,③": "CircledDigit", "一,二,三": "Ideograph", "㉠,㉡,㉢": "CircledHangulJamo", - "Ⓐ,Ⓑ,Ⓒ": "CircledLatinCapital", "ⓐ,ⓑ,ⓒ": "CircledLatinSmall", "i,ii,iii": "RomanSmall", "I,II,III": "RomanCapital", @@ -570,81 +569,81 @@ } }, "29": { - "path": "boolean(//CHAR[contains(text(),'Interior')])", - "ignoreWord": "Interior", + "path": "boolean(//CHAR[contains(text(),'Economy')])", + "ignoreWord": "Economy", "value": true, "points": 3, "category": "Boolean", - "item": "Interior/영단어 미입력, 대소문자/오타 시 전체 감점", + "item": "Economy/영단어 미입력, 대소문자/오타 시 전체 감점", "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": "지역별 대회 참가자 현황", - "value": "1200", + "searchValue": "가을 명산 입장객 수(기준: 명)", + "value": "1100", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (지역별 대회 참가자 현황)/② 크기 (1200)" + "item": "제목 문구 (가을 명산 입장객 수(기준: 명))/② 크기 (1100)" }, "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": "144,210,67", + "value": "154,235,85", "points": 2, "category": "Color", - "item": "위쪽 제목 셀/① 색상(RGB:144,210,67)" + "item": "위쪽 제목 셀/① 색상(RGB:154,235,85)" }, "38": { "path": "//CHARSHAPE[@Id=//TABLE/ROW[1]/descendant::TEXT/@CharShape]", @@ -673,11 +672,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": { @@ -705,11 +704,11 @@ }, "45": { "chart_xpath": "", - "chart_type": "꺾은선형", + "chart_type": "묶은세로막대형", "value": true, "points": 2, "category": "ChartType", - "item": "① 종류 (꺾은선형)", + "item": "① 종류 (묶은세로막대형)", "desc": "chart_type을 입력받아 차트타입에 맞는 xml요소가 있는지 내부적으로 검사, chart_type만 한글로 입력해주면 된다. (공백무시)" }, "46": { @@ -729,10 +728,10 @@ }, "48": { "path": "//OLE[@BinItem=//BINITEM[@Format='OLE']/@BinData]//SIZE/@Height", - "value": "90", + "value": "80", "points": 2, "category": "mmSize", - "item": "④ 크기-높이 (90 mm)" + "item": "④ 크기-높이 (80 mm)" }, "49": { "chart_xpath": "boolean(//c:chart and not(//c:pt[not(ancestor::c:tx)]/c:v[text()='합계' or text()='평균']))", @@ -744,28 +743,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": "지역별 대회 참가자 현황", - "value": "1300", + "searchValue": "가을 명산 입장객 수", + "value": "1200", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (지역별 대회 참가자 현황)/② 크기 (1300)" + "item": "제목 문구 (가을 명산 입장객 수)/② 크기 (1200)" }, "52": { "chart_xpath": "//a:t[text()='{searchValue}']/ancestor::a:r/a:rPr/@{option}", - "option": "b", - "searchValue": "지역별 대회 참가자 현황", + "option": "i", + "searchValue": "가을 명산 입장객 수", "value": "1", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (지역별 대회 참가자 현황)/③ 기울임", + "item": "제목 문구 (가을 명산 입장객 수)/③ 기울임", "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" }, "53": { @@ -784,7 +783,7 @@ }, "55": { "chart_xpath": "//c:catAx/c:txPr//a:defRPr/@{option}", - "option": "i", + "option": "b", "value": "1", "points": 1, "category": "ChartOneAnswer", @@ -807,7 +806,7 @@ }, "58": { "chart_xpath": "//c:valAx/c:txPr//a:defRPr/@{option}", - "option": "i", + "option": "b", "value": "1", "points": 1, "category": "ChartOneAnswer", @@ -830,7 +829,7 @@ }, "61": { "chart_xpath": "//c:legend//a:defRPr/@{option}", - "option": "i", + "option": "b", "value": "1", "points": 1, "category": "OneAnswer", diff --git a/회차별채점자료/2508/_DIW_2508D.json b/회차별채점자료/2522/DIW_2522B.json similarity index 71% rename from 회차별채점자료/2508/_DIW_2508D.json rename to 회차별채점자료/2522/DIW_2522B.json index 2c6a978..f0ca136 100644 --- a/회차별채점자료/2508/_DIW_2508D.json +++ b/회차별채점자료/2522/DIW_2522B.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": "230,47,199", + "searchValue": "소셜네트워킹전략컨퍼런스", + "value": "201,102,248", "points": 2, "category": "Color", - "item": "문구 (강원도지역문화체험안내)/② 채우기 : 색상(RGB:230,47,199)" + "item": "문구 (소셜네트워킹전략컨퍼런스)/② 채우기 : 색상(RGB:201,102,248)" }, "3": { "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Width", - "searchValue": "강원도지역문화체험안내", - "value": "125", + "searchValue": "소셜네트워킹전략컨퍼런스", + "value": "120", "tolerance": 1, "points": 2, "category": "mmSize", - "item": "문구 (강원도지역문화체험안내)/③ 크기-너비 (125 mm)" + "item": "문구 (소셜네트워킹전략컨퍼런스)/③ 크기-너비 (120 mm)" }, "4": { "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Height", - "searchValue": "강원도지역문화체험안내", + "searchValue": "소셜네트워킹전략컨퍼런스", "value": "20", "tolerance": 1, "points": 2, "category": "mmSize", - "item": "문구 (강원도지역문화체험안내)/④ 크기-높이 (20 mm)" + "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,68 +112,68 @@ "tolerance": 200, "points": 1, "category": "TwoLineSize", - "item": "자/① 모양 (2줄)" + "item": "2/① 모양 (2줄)" }, "9": { "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape", - "searchValue": "자", - "value": "돋움", + "searchValue": "최", + "value": "궁서", "points": 1, "category": "FontName", - "item": "자/② 글씨체 (돋움)" + "item": "2/② 글씨체 (궁서)" }, "10": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "자", - "value": "231,215,17", + "searchValue": "최", + "value": "218,202,48", "points": 2, "category": "Color", - "item": "자/③ 면색 : 색상(RGB:231,215,17)" + "item": "2/③ 면색 : 색상(RGB:218,202,48)" }, "11": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//OUTSIDEMARGIN/@Right", - "searchValue": "자", + "searchValue": "최", "value": "3.0", "tolerance": 1, "points": 2, "category": "mmSize", - "item": "자/④ 본문과의 간격 : 3.0mm" + "item": "2/④ 본문과의 간격 : 3.0mm" }, "12": { "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]", - "searchValue": "독특한 문화를 경험하실 수 있도록", + "searchValue": "소셜 네트워킹 서비스", "value": "BOLD", "points": 2, "category": "FontAttribute", - "item": "문구 (독특한 문화를 경험하실 수 있도록)/① BOLD" + "item": "문구 (소셜 네트워킹 서비스)/① BOLD" }, "13": { "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]", - "searchValue": "독특한 문화를 경험하실 수 있도록", + "searchValue": "소셜 네트워킹 서비스", "value": "ITALIC", "points": 2, "category": "FontAttribute", - "item": "문구 (독특한 문화를 경험하실 수 있도록)/② ITALIC" + "item": "문구 (소셜 네트워킹 서비스)/② ITALIC" }, "14": { "path": "//CHAR[contains(string(.),'{char1}')]/text()", "path2": "//CHAR[contains(string(.),'{char2}')]/text()", "path3": "//CHAR[contains(string(.),'{char3}')]/text()", - "char1": "▶", - "char2": "◀", + "char1": "□", + "char2": "□", "char3": "※", "value": 3, "points": 3, "category": "SpecialChar", - "item": "① ▶, ② ◀, ③ ※" + "item": "① □, ② □, ③ ※" }, "15": { "path": "//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape", "searchValue": "행사안내", - "value": "궁서", + "value": "굴림", "points": 1, "category": "FontName", - "item": "문구 (▶ 행사안내 ◀)/① 글씨체 (궁서)" + "item": "문구 (□ 행사안내 □)/① 글씨체 (굴림)" }, "16": { "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{match_str}')]/ancestor::P/@ParaShape]/@Align", @@ -181,86 +181,86 @@ "value": "Center", "points": 1, "category": "Align", - "item": "문구 (▶ 행사안내 ◀)/② 정렬 (가운데 정렬)" + "item": "문구 (□ 행사안내 □)/② 정렬 (가운데 정렬)" }, "17": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", "hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]", - "searchValue": "강원도 춘천시 중앙문화지역센터 및 인근 공원", + "searchValue": "서울 강남구 한국정보기술협력센터 3층 대회의장", "value": "ITALIC", "points": 1, "category": "FontAttribute", - "item": "문구 (강원도 춘천시 중앙문화지역센터 및 인근 공원)/① ITALIC" + "item": "문구 (서울 강남구 한국정보기술협력센터 3층 대회의장)/① ITALIC" }, "18": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", "hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]", - "searchValue": "강원도 춘천시 중앙문화지역센터 및 인근 공원", + "searchValue": "서울 강남구 한국정보기술협력센터 3층 대회의장", "value": "UNDERLINE", "points": 1, "category": "FontAttribute", - "item": "문구 (강원도 춘천시 중앙문화지역센터 및 인근 공원)/② UNDERLINE" + "item": "문구 (서울 강남구 한국정보기술협력센터 3층 대회의장)/② UNDERLINE" }, "19": { "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/following-sibling::P[1]/@ParaShape]/PARAMARGIN", "searchValue": "기타사항", "value": { - "Left": 15, + "Left": 10, "Indent": 12 }, "points": 2, "category": "ParaShape", - "item": "문구 (※ 기타… 이하 문단)/왼쪽여백 (15pt), 내어쓰기 (12pt)", + "item": "문구 (※ 기타… 이하 문단)/왼쪽여백 (10pt), 내어쓰기 (12pt)", "desc": "내부적으로 내어쓰기는 음수값 / JSON value값은 양수로 입력" }, "20": { "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]/@Height", - "searchValue": "2025. 8. 23.", + "searchValue": "2025. 08. 30.", "value": "1400", "points": 1, "category": "OneAnswer", - "item": "문구 (2025. 8. 23.)/① 크기 (1400)", + "item": "문구 (2025. 08. 30.)/① 크기 (1400)", "desc": "1pt당 100" }, "21": { "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/@ParaShape]/@Align", - "searchValue": "2025. 8. 23.", + "searchValue": "2025. 08. 30.", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (2025. 8. 23.)/② 정렬 (가운데 정렬)" + "item": "문구 (2025. 08. 30.)/② 정렬 (가운데 정렬)" }, "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": "2000", "points": 1, "category": "OneAnswer", - "item": "문구 (중앙문화지역센터)/② 크기 (2500)" + "item": "문구 (한국정보서비스학회장)/② 크기 (2000)" }, "24": { "path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/ancestor::P/@ParaShape]/@Align", - "searchValue": "중앙문화지역센터", + "searchValue": "한국정보서비스학회장", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (중앙문화지역센터)/③ 정렬 (가운데 정렬)" + "item": "문구 (기능경진대회운영위원회)/③ 정렬 (가운데 정렬)" }, "25": { "path": "//SECTION[1]//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", @@ -314,11 +314,11 @@ }, "30": { "path": "//PARASHAPE[@Id='{parashape_id}']/PARAMARGIN/@LineSpacing", - "value": "200", - "first_word": "자", + "value": "180", + "first_word": "최", "points": 2, "category": "LineSpacing", - "item": "문제 1 줄간격 200% 설정", + "item": "문제 1 줄간격 180% 설정", "desc": "1페이지 문단의 줄간격이 정답이 아닌 문단이 있으면 False(감점), first_word 속성에 [문단 첫글자 장식]에 해당하는 글자를 입력해준다." } }, @@ -351,121 +351,121 @@ }, "4": { "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width", - "searchValue": "매력적인 강원도", - "value": "68", + "searchValue": "소셜 네트워킹 서비스", + "value": "70", "points": 2, "category": "mmSize", - "item": "문구 (매력적인 강원도)/① 크기-너비 (68 mm)" + "item": "문구 (소셜 네트워킹 서비스)/① 크기-너비 (60 mm)" }, "5": { "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Height", - "searchValue": "매력적인 강원도", + "searchValue": "소셜 네트워킹 서비스", "value": "12", "points": 2, "category": "mmSize", - "item": "문구 (매력적인 강원도)/② 크기-높이 (12 mm)" + "item": "문구 (소셜 네트워킹 서비스)/② 크기-높이 (12 mm)" }, "6": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE", - "searchValue": "매력적인 강원도", + "searchValue": "소셜 네트워킹 서비스", "value": { "Style": "DoubleSlim", "Width": "283" }, "points": 2, "category": "LineShape", - "item": "문구 (매력적인 강원도)/③ 테두리 : 이중 실선(1.00mm)", + "item": "문구 (소셜 네트워킹 서비스)/③ 테두리 : 이중 실선(1.00mm)", "desc": "1mm = 283pt value['Width']에 pt값 입력" }, "7": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/@Ratio", - "searchValue": "매력적인 강원도", + "searchValue": "소셜 네트워킹 서비스", "value": "50", "points": 2, "category": "OneAnswer", - "item": "문구 (매력적인 강원도)/④ 글상자 모서리 (반원)", + "item": "문구 (소셜 네트워킹 서비스)/④ 글상자 모서리 (반원)", "desc": "모서리 비율 반원:50 / 둥근모양:20" }, "8": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "매력적인 강원도", - "value": "130,159,32", + "searchValue": "소셜 네트워킹 서비스", + "value": "90,233,53", "points": 2, "category": "Color", - "item": "문구 (매력적인 강원도)/⑤ 채우기 : 색상(RGB:130,159,32)" + "item": "문구 (소셜 네트워킹 서비스)/⑤ 채우기 : 색상(RGB:90,233,53)" }, "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": "2300", + "searchValue": "소셜 네트워킹 서비스", + "value": "1800", "points": 1, "category": "OneAnswer", - "item": "문구 (매력적인 강원도)/⑨ 글씨크기 (2300)", + "item": "문구 (소셜 네트워킹 서비스)/⑨ 글씨크기 (1800)", "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": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG' or @Format='JPEG']", + "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG' or @Format='JPEG' or @Format='PNG']", "value": true, "points": 2, "category": "Boolean", - "item": "① 파일명 \"그림D.jpg\" 삽입", + "item": "① 파일명 \"그림B.jpg\" 삽입", "desc": "첨부 이미지 파일명 손상으로 정상적인 채점이 불가한 경우가 발견되어서 이미지 첨부 여부로 채점 방식 변경 (7/3)" }, "15": { - "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG']/@BinData]]/SHAPEOBJECT/SIZE/@Width", - "value": "85", + "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG' or @Format='PNG']/@BinData]]/SHAPEOBJECT/SIZE/@Width", + "value": "80", "points": 2, "category": "mmSize", - "item": "② 크기-너비 (85 mm)" + "item": "② 크기-너비 (80 mm)" }, "16": { - "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG']/@BinData]]/SHAPEOBJECT/SIZE/@Height", - "value": "40", + "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG' or @Format='PNG']/@BinData]]/SHAPEOBJECT/SIZE/@Height", + "value": "45", "points": 2, "category": "mmSize", - "item": "③ 크기-높이 (40 mm)" + "item": "③ 크기-높이 (45 mm)" }, "17": { - "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@HorzOffset", + "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG' or @Format='PNG']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@HorzOffset", "value": "0", "points": 2, "category": "mmSize", "item": "④ 위치 (어울림 : 가로-쪽의 왼쪽 0.0mm)" }, "18": { - "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@VertOffset", + "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG' or @Format='PNG']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@VertOffset", "value": "22", "points": 2, "category": "mmSize", @@ -473,94 +473,94 @@ }, "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. 문화유산과 전통)/② 크기 (1200)" + "item": "문구② (2. 소셜 네트워킹 서비스 활용)/② 크기 (1200)" }, "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": "Digit", + "searchValue": "블로거가 한두 문장 정도의 단편적 정보를 관심이 있는 개인들에게 전달하는 통신방식", + "value": "CircledLatinCapital", "points": 2, "category": "OneAnswer", "item": "문구 (전당)/④ 각주 번호모양", "desc": { "가,나,다": "HangulSyllable", "1,2,3": "Digit", - "1),2),3)": "Digit", "갑,을,병": "DecagonCircle", "A,B,C": "LatinCapital", "a,b,c": "LatinSmall", "①,②,③": "CircledDigit", "一,二,三": "Ideograph", "㉠,㉡,㉢": "CircledHangulJamo", + "Ⓐ,Ⓑ,Ⓒ": "CircledLatinCapital", "ⓐ,ⓑ,ⓒ": "CircledLatinSmall", "i,ii,iii": "RomanSmall", "I,II,III": "RomanCapital", @@ -570,81 +570,81 @@ } }, "29": { - "path": "boolean(//CHAR[contains(text(),'Tourism')])", - "ignoreWord": "Tourism", + "path": "boolean(//CHAR[contains(text(),'Marketing')])", + "ignoreWord": "Marketing", "value": true, "points": 3, "category": "Boolean", - "item": "Tourism/영단어 미입력, 대소문자/오타 시 전체 감점", + "item": "Marketing/영단어 미입력, 대소문자/오타 시 전체 감점", "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": "제목 문구 (강원도 지역별 면적(단위:%))/② 크기 (1200)" + "item": "제목 문구 (스마트폰 가입자 수(단위 : 만 명))/② 크기 (1200)" }, "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": "87,215,182", + "value": "248,203,169", "points": 2, "category": "Color", - "item": "위쪽 제목 셀/① 색상(RGB:87,215,182)" + "item": "위쪽 제목 셀/① 색상(RGB:248,203,169)" }, "38": { "path": "//CHARSHAPE[@Id=//TABLE/ROW[1]/descendant::TEXT/@CharShape]", @@ -700,16 +700,16 @@ "value": true, "points": 4, "category": "Boolean", - "item": "블록 계산식/AVG", + "item": "블록 계산식/합계", "desc": "option값에 합계는 SUM / 평균은 AVG" }, "45": { "chart_xpath": "", - "chart_type": "묶은 가로 막대형", + "chart_type": "꺾은선형", "value": true, "points": 2, "category": "ChartType", - "item": "① 종류 (묶은 가로 막대형)", + "item": "① 종류 (꺾은선형)", "desc": "chart_type을 입력받아 차트타입에 맞는 xml요소가 있는지 내부적으로 검사, chart_type만 한글로 입력해주면 된다. (공백무시)" }, "46": { @@ -744,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": "1300", + "searchValue": "스마트폰 가입자 수", + "value": "1200", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (강원도 지역별 면적)/② 크기 (1300)" + "item": "제목 문구 (스마트폰 가입자 수)/② 크기 (1200)" }, "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": "ChartOneAnswer", - "item": "X축/① 글꼴 (돋움)" + "item": "X축/① 글꼴 (돋움체)" }, "54": { "chart_xpath": "//c:catAx/c:txPr//a:defRPr/@sz", @@ -793,10 +793,10 @@ }, "56": { "chart_xpath": "//c:valAx/c:txPr//a:ea/@typeface", - "value": "돋움", + "value": "돋움체", "points": 1, "category": "ChartOneAnswer", - "item": "Y축/① 글꼴 (돋움)" + "item": "Y축/① 글꼴 (돋움체)" }, "57": { "chart_xpath": "//c:valAx/c:txPr//a:defRPr/@sz", @@ -816,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/회차별채점자료/2508/_DIW_2508C.json b/회차별채점자료/2522/DIW_2522C.json similarity index 75% rename from 회차별채점자료/2508/_DIW_2508C.json rename to 회차별채점자료/2522/DIW_2522C.json index 4be4d45..5366f31 100644 --- a/회차별채점자료/2508/_DIW_2508C.json +++ b/회차별채점자료/2522/DIW_2522C.json @@ -46,65 +46,65 @@ "1": { "1": { "path": "//TEXTART[@Text='{searchValue}']/TEXTARTSHAPE/@FontName", - "searchValue": "치아건강특별강연회", - "value": "굴림", + "searchValue": "2025청소년요리경연대회", + "value": "견고딕", "points": 1, "category": "OneAnswer", - "item": "문구 (치아건강특별강연회)/① 글씨체 (굴림)" + "item": "문구 (2025청소년요리경연대회)/① 글씨체 (견고딕)" }, "2": { "path": "//TEXTART[@Text='{searchValue}']/descendant::WINDOWBRUSH/@FaceColor", - "searchValue": "치아건강특별강연회", - "value": "183,29,167", + "searchValue": "2025청소년요리경연대회", + "value": "246,149,102", "points": 2, "category": "Color", - "item": "문구 (치아건강특별강연회)/② 채우기 : 색상(RGB:183,29,167)" + "item": "문구 (2025청소년요리경연대회)/② 채우기 : 색상(RGB:246,149,102)" }, "3": { "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Width", - "searchValue": "치아건강특별강연회", - "value": "125", + "searchValue": "2025청소년요리경연대회", + "value": "120", "tolerance": 1, "points": 2, "category": "mmSize", - "item": "문구 (치아건강특별강연회)/③ 크기-너비 (125 mm)" + "item": "문구 (2025청소년요리경연대회)/③ 크기-너비 (120 mm)" }, "4": { "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Height", - "searchValue": "치아건강특별강연회", + "searchValue": "2025청소년요리경연대회", "value": "20", "tolerance": 1, "points": 2, "category": "mmSize", - "item": "문구 (치아건강특별강연회)/④ 크기-높이 (20 mm)" + "item": "문구 (2025청소년요리경연대회)/④ 크기-높이 (20 mm)" }, "5": { "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/POSITION/@TreatAsChar", - "searchValue": "치아건강특별강연회", + "searchValue": "2025청소년요리경연대회", "value": "true", "points": 2, "category": "OneAnswer", - "item": "문구 (치아건강특별강연회)/⑤ 위치 (글자처럼 취급)" + "item": "문구 (2025청소년요리경연대회)/⑤ 위치 (글자처럼 취급)" }, "6": { "path": "//PARASHAPE[@Id=//P[.//TEXTART[@Text='{searchValue}']]/@ParaShape]/@Align", - "searchValue": "치아건강특별강연회", + "searchValue": "2025청소년요리경연대회", "value": "Center", "points": 2, "category": "OneAnswer", - "item": "문구 (치아건강특별강연회)/⑥ 정렬 (가운데 정렬)" + "item": "문구 (2025청소년요리경연대회)/⑥ 정렬 (가운데 정렬)" }, "7": { "path": "//TEXTART[@Text='{searchValue}']", - "searchValue": "치아건강특별강연회", + "searchValue": "2025청소년요리경연대회", "value": true, "points": 2, "category": "Boolean", - "item": "문구 (치아건강특별강연회)/⑦ 글맵시모양 (육안확인)" + "item": "문구 (2025청소년요리경연대회)/⑦ 글맵시모양 (육안확인)" }, "8": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/SIZE", - "searchValue": "현", + "searchValue": "청", "value": { "Height": 2800, "Width": 2800 @@ -112,94 +112,94 @@ "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": "149,180,174", + "searchValue": "청", + "value": "224,217,93", "points": 2, "category": "Color", - "item": "현/③ 면색 : 색상(RGB:149,180,174)" + "item": "청/③ 면색 : 색상(RGB:224,217,93)" }, "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": "문구 (평생 건강한 치아를 유지하기)/① BOLD" + "item": "문구 (꿈과 희망을 요리하다)/① BOLD" }, "13": { "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]", - "searchValue": "평생 건강한 치아를 유지하기", + "searchValue": "꿈과 희망을 요리하다", "value": "ITALIC", "points": 2, "category": "FontAttribute", - "item": "문구 (평생 건강한 치아를 유지하기)/② ITALIC" + "item": "문구 (꿈과 희망을 요리하다)/② ITALIC" }, "14": { "path": "//CHAR[contains(string(.),'{char1}')]/text()", "path2": "//CHAR[contains(string(.),'{char2}')]/text()", "path3": "//CHAR[contains(string(.),'{char3}')]/text()", - "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(),'{match_str}')]/ancestor::P/@ParaShape]/@Align", - "match_str": "행사안내", + "match_str": "대회안내", "value": "Center", "points": 1, "category": "Align", - "item": "문구 (◎ 행사안내 ◎)/② 정렬 (가운데 정렬)" + "item": "문구 (◐ 대회안내 ◑)/② 정렬 (가운데 정렬)" }, "17": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", "hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]", - "searchValue": "경복궁역 8번 출구 도보 5분", + "searchValue": "청소년 문화 축제 홈페이지(http://www.ihd.or.kr", "value": "ITALIC", "points": 1, "category": "FontAttribute", - "item": "문구 (경복궁역 8번 출구 도보 5분)/① ITALIC" + "item": "문구 (청소년 문화 축제 홈페이지(http://www.ihd.or.kr)/① ITALIC" }, "18": { "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]", "hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]", - "searchValue": "경복궁역 8번 출구 도보 5분", + "searchValue": "청소년 문화 축제 홈페이지(http://www.ihd.or.kr", "value": "UNDERLINE", "points": 1, "category": "FontAttribute", - "item": "문구 (경복궁역 8번 출구 도보 5분)/② UNDERLINE" + "item": "문구 (청소년 문화 축제 홈페이지(http://www.ihd.or.kr)/② UNDERLINE" }, "19": { "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/following-sibling::P[1]/@ParaShape]/PARAMARGIN", @@ -215,44 +215,44 @@ }, "20": { "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]/@Height", - "searchValue": "2025. 8. 23.", + "searchValue": "2025. 08. 30.", "value": "1400", "points": 1, "category": "OneAnswer", - "item": "문구 (2025. 8. 23.)/① 크기 (1400)", + "item": "문구 (2025. 08. 30.)/① 크기 (1400)", "desc": "1pt당 100" }, "21": { "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/@ParaShape]/@Align", - "searchValue": "2025. 8. 23.", + "searchValue": "2025. 08. 30.", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (2025. 8. 23.)/② 정렬 (가운데 정렬)" + "item": "문구 (2025. 08. 30.)/② 정렬 (가운데 정렬)" }, "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": "2400", + "searchValue": "청소년문화축제추진위원회", + "value": "2200", "points": 1, "category": "OneAnswer", - "item": "문구 (밝은미소구강센터)/② 크기 (2400)" + "item": "문구 (청소년문화축제추진위원회)/② 크기 (2200)" }, "24": { "path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/ancestor::P/@ParaShape]/@Align", - "searchValue": "밝은미소구강센터", + "searchValue": "청소년문화축제추진위원회", "value": "Center", "points": 1, "category": "OneAnswer", - "item": "문구 (밝은미소구강센터)/③ 정렬 (가운데 정렬)" + "item": "문구 (청소년문화축제추진위원회)/③ 정렬 (가운데 정렬)" }, "25": { "path": "//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape", @@ -280,7 +280,7 @@ }, "28": { "path": "//PAGENUM/@FormatType", - "value": "HangulSyllable", + "value": "DecagonCircle", "points": 2, "category": "PageNumber", "item": "① 쪽 번호 매기기 (가,나,다 순으로)", @@ -314,11 +314,11 @@ }, "30": { "path": "//PARASHAPE[@Id='{parashape_id}']/PARAMARGIN/@LineSpacing", - "value": "200", - "first_word": "현", + "value": "190", + "first_word": "청", "points": 2, "category": "LineSpacing", - "item": "문제 1 줄간격 200% 설정", + "item": "문제 1 줄간격 190% 설정", "desc": "1페이지 문단의 줄간격이 정답이 아닌 문단이 있으면 False(감점), first_word 속성에 [문단 첫글자 장식]에 해당하는 글자를 입력해준다." } }, @@ -343,7 +343,7 @@ "desc": "섹션이 1개 이상이면 점수부여" }, "3": { - "path": "TEXT/COLDEF/@Count", + "path": "./TEXT/COLDEF/@Count", "value": "2", "points": 3, "category": "TwoColumn", @@ -351,89 +351,89 @@ }, "4": { "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width", - "searchValue": "구강건강관리", - "value": "60", + "searchValue": "요리의 세계", + "value": "50", "points": 2, "category": "mmSize", - "item": "문구 (구강건강관리)/① 크기-너비 (60 mm)" + "item": "문구 (요리의 세계)/① 크기-너비 (50 mm)" }, "5": { "path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Height", - "searchValue": "구강건강관리", + "searchValue": "요리의 세계", "value": "12", "points": 2, "category": "mmSize", - "item": "문구 (구강건강관리)/② 크기-높이 (12 mm)" + "item": "문구 (요리의 세계)/② 크기-높이 (12 mm)" }, "6": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE", - "searchValue": "구강건강관리", + "searchValue": "요리의 세계", "value": { "Style": "DoubleSlim", "Width": "283" }, "points": 2, "category": "LineShape", - "item": "문구 (구강건강관리)/③ 테두리 : 이중 실선(1.00mm)", + "item": "문구 (요리의 세계)/③ 테두리 : 이중 실선(1.00mm)", "desc": "1mm = 283pt value['Width']에 pt값 입력" }, "7": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/@Ratio", - "searchValue": "구강건강관리", - "value": "20", + "searchValue": "요리의 세계", + "value": "50", "points": 2, "category": "OneAnswer", - "item": "문구 (구강건강관리)/④ 글상자 모서리 (반원)", + "item": "문구 (요리의 세계)/④ 글상자 모서리 (반원)", "desc": "모서리 비율 반원:50 / 둥근모양:20" }, "8": { "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor", - "searchValue": "구강건강관리", - "value": "187,140,209", + "searchValue": "요리의 세계", + "value": "95,206,218", "points": 2, "category": "Color", - "item": "문구 (구강건강관리)/⑤ 채우기 : 색상(RGB:187,140,209)" + "item": "문구 (요리의 세계)/⑤ 채우기 : 색상(RGB:95,206,218)" }, "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": "구강건강관리", + "searchValue": "요리의 세계", "value": "맑은 고딕", "points": 1, "category": "FontName", - "item": "문구 (구강건강관리)/⑧ 글씨체 (맑은 고딕)" + "item": "문구 (요리의 세계)/⑧ 글씨체 (맑은 고딕)" }, "12": { "path": "//CHARSHAPE[@Id=//RECTANGLE//TEXT[./CHAR[text()='{searchValue}']]/@CharShape]/@Height", - "searchValue": "구강건강관리", - "value": "2300", + "searchValue": "요리의 세계", + "value": "1700", "points": 1, "category": "OneAnswer", - "item": "문구 (구강건강관리)/⑨ 글씨크기 (2300)", + "item": "문구 (요리의 세계)/⑨ 글씨크기 (1700)", "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": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG' or @Format='JPEG']", @@ -466,94 +466,96 @@ }, "18": { "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@VertOffset", - "value": "22", + "value": "24", "points": 2, "category": "mmSize", - "item": "⑤ 위치 (어울림 : 세로-쪽의 위 22 mm)" + "item": "⑤ 위치 (어울림 : 세로-쪽의 위 24 mm)" }, "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. 관련 연구)/② 크기 (1200)" + "item": "문구② (2. 파스타의 종류)/② 크기 (1200)" }, "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": "DecagonCircle", + "searchValue": "주식에 곁들여 먹는 음식", + "value": "CircledHangulSyllable", "points": 2, "category": "OneAnswer", "item": "문구 (전당)/④ 각주 번호모양", "desc": { "가,나,다": "HangulSyllable", + "㉮,㉯,㉰": "CircledHangulSyllable", "1,2,3": "Digit", + "1),2),3)": "Digit", "갑,을,병": "DecagonCircle", "A,B,C": "LatinCapital", "a,b,c": "LatinSmall", @@ -569,81 +571,81 @@ } }, "29": { - "path": "boolean(//CHAR[contains(text(),'Fluoride')])", - "ignoreWord": "Fluoride", + "path": "boolean(//CHAR[contains(text(),'Culture')])", + "ignoreWord": "Culture", "value": true, "points": 3, "category": "Boolean", - "item": "Fluoride/영단어 미입력, 대소문자/오타 시 전체 감점", + "item": "Culture/영단어 미입력, 대소문자/오타 시 전체 감점", "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": "문구 (…칫솔질은 창아와 잇몸 경계에 45도…)>'창' → '치' 글자바꿈" + "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": "제목 문구 (치주질환 통계표(단위:명)/② 크기 (1200)" + "item": "제목 문구 (부문별 참가자 현황)/② 크기 (1200)" }, "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": "210,191,27", + "value": "231,93,64", "points": 2, "category": "Color", - "item": "위쪽 제목 셀/① 색상(RGB:210,191,27)" + "item": "위쪽 제목 셀/① 색상(RGB:231,93,64)" }, "38": { "path": "//CHARSHAPE[@Id=//TABLE/ROW[1]/descendant::TEXT/@CharShape]", @@ -672,11 +674,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": { @@ -695,7 +697,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", @@ -704,11 +706,11 @@ }, "45": { "chart_xpath": "", - "chart_type": "꺾은선형", + "chart_type": "묶은 세로 막대형", "value": true, "points": 2, "category": "ChartType", - "item": "① 종류 (꺾은선형)", + "item": "① 종류 (묶은 세로 막대형)", "desc": "chart_type을 입력받아 차트타입에 맞는 xml요소가 있는지 내부적으로 검사, chart_type만 한글로 입력해주면 된다. (공백무시)" }, "46": { @@ -743,28 +745,28 @@ }, "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": "1300", + "searchValue": "부문별 참가자 현황", + "value": "1400", "points": 1, "category": "OneAnswer", - "item": "제목 문구 (치주질환 통계표)/② 크기 (1300)" + "item": "제목 문구 (부문별 참가자 현황)/② 크기 (1400)" }, "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": {