diff --git a/250507_DIW_2504회_A형_채점결과.xlsx b/250507_DIW_2504회_A형_채점결과.xlsx index 2509e91..bd8fd35 100644 Binary files a/250507_DIW_2504회_A형_채점결과.xlsx and b/250507_DIW_2504회_A형_채점결과.xlsx differ diff --git a/250516_DIW_2504회_A형_TEST.xlsx b/250516_DIW_2504회_A형_TEST.xlsx new file mode 100644 index 0000000..9ce21ce Binary files /dev/null and b/250516_DIW_2504회_A형_TEST.xlsx differ diff --git a/250516_DIW_2504회_A형_채점결과.xlsx b/250516_DIW_2504회_A형_채점결과.xlsx new file mode 100644 index 0000000..582323e Binary files /dev/null and b/250516_DIW_2504회_A형_채점결과.xlsx differ diff --git a/DIW_2504A_new.json b/DIW_2504A_new.json index 17f8250..d4a5ca1 100644 --- a/DIW_2504A_new.json +++ b/DIW_2504A_new.json @@ -87,7 +87,7 @@ "item": "문구 (클라우드컴퓨팅컨퍼런스)/⑤ 위치 (글자처럼 취급)" }, "6": { - "path":"//PARASHAPE[@Id=//P[.//TEXTART[@Text='클라우드컴퓨팅컨퍼런스']]/@ParaShape]/@Align", + "path":"//PARASHAPE[@Id=//P[.//TEXTART[@Text='{searchValue}']]/@ParaShape]/@Align", "searchValue": "클라우드컴퓨팅컨퍼런스", "value": "Center", "points": 2, @@ -313,8 +313,8 @@ }, "2": { "1": { - "path": "//SECTION[2]//PAGEBORDERFILL[@Type='Both' or @Type='Even']/@HeaderInside", - "path2": "//BORDERFILL[@Id=//SECTION[2]//PAGEBORDERFILL[@Type='Both' or @Type='Even']/@BorferFill]", + "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 @@ -332,7 +332,7 @@ "desc": "섹션이 1개 이상이면 점수부여" }, "3": { - "path": "//SECTION[2]//COLDEF/@Count", + "path": "//COLDEF/@Count", "value": "2", "points": 3, "category": "OneAnswer", @@ -686,14 +686,137 @@ "desc": "option값에 합계는 SUM / 평균은 AVG" }, "45": { - "path": "", + "chart_xpath": "", "chart_type": "묶은세로막대형", "value": true, "points": 2, - "category": "chart_type", + "category": "ChartType", "item": "① 종류 (묶은 세로 막대형)", "desc": "chart_type을 입력받아 차트타입에 맞는 xml요소가 있는지 내부적으로 검사, chart_type만 한글로 입력해주면 된다." }, - "61": {} + "46": { + "chart_xpath": "//c:valAx/c:majorTickMark/@val", + "value": "out", + "points": 2, + "category": "OneAnswer", + "item": "② 값 축 주 눈금선", + "desc": "chart xml파일에서 답안을 가져오는 문항은 path키값 대신 chart_xpath키값을 이용해 xapth구문을 작성한다" + }, + "47": { + "path": "//OLE[@BinItem=//BINITEM[@Format='OLE']/@BinData]//SIZE/@Width", + "value": "80", + "points": 2, + "category": "mmSize", + "item": "③ 크기-너비 (80mm)" + }, + "48": { + "path": "//OLE[@BinItem=//BINITEM[@Format='OLE']/@BinData]//SIZE/@Height", + "value": "90", + "points": 2, + "category": "mmSize", + "item": "④ 크기-높이 (90mm)" + }, + "49": { + "chart_xpath": "boolean(//c:chart and not(//c:pt[not(ancestor::c:tx)]/c:v[text()='합계' or text()='평균']))", + "value": true, + "points": 2, + "category": "Boolean", + "item": "⑤ 차트 데이터(표에서 블록계산식을 제외한 나머지 값만 이용)", + "desc": "차트가 존재하고 블록계산식(합계, 평균) 데이터가 없는 경우 정답 처리" + }, + "50": { + "chart_xpath": "//a:t[text()='{searchValue}']/ancestor::a:r//a:ea/@typeface", + "searchValue": "클라우드 보안 투자", + "value": "굴림", + "points": 1, + "category": "OneAnswer", + "item": "제목 문구 (클라우드 보안 투자)/① 글씨체 (굴림)" + }, + "51": { + "chart_xpath": "//a:t[text()='{searchValue}']/ancestor::a:r/a:rPr/@sz", + "searchValue": "클라우드 보안 투자", + "value": "1300", + "points": 1, + "category": "OneAnswer", + "item": "제목 문구 (클라우드 보안 투자)/② 크기 (13pt)" + }, + "52": { + "chart_xpath": "//a:t[text()='{searchValue}']/ancestor::a:r/a:rPr/@b", + "searchValue": "클라우드 보안 투자", + "value": "1", + "points": 1, + "category": "OneAnswer", + "item": "제목 문구 (클라우드 보안 투자)/③ 진하게" + }, + "53": { + "chart_xpath": "//c:catAx//a:ea/@typeface", + "value": "돋움", + "points": 1, + "category": "OneAnswer", + "item": "X축/① 글꼴 (돋움)" + }, + "54": { + "chart_xpath": "//c:catAx//a:defRPr/@sz", + "value": "900", + "points": 1, + "category": "OneAnswer", + "item": "X축/② 크기 (9pt)" + }, + "55": { + "chart_xpath": "//c:catAx//a:defRPr/@{option}", + "option": "i", + "value": "1", + "points": 1, + "category": "OneAnswer", + "item": "X축/③ 기울임", + "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" + }, + "56": { + "chart_xpath": "//c:valAx//a:ea/@typeface", + "value": "돋움", + "points": 1, + "category": "OneAnswer", + "item": "Y축/① 글꼴 (돋움)" + }, + "57": { + "chart_xpath": "//c:valAx//a:defRPr/@sz", + "value": "900", + "points": 1, + "category": "OneAnswer", + "item": "Y축/② 크기 (9pt)" + }, + "58": { + "chart_xpath": "//c:valAx//a:defRPr/@{option}", + "option": "i", + "value": "1", + "points": 1, + "category": "OneAnswer", + "item": "Y축/③ 기울임", + "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" + + }, + "59": { + "chart_xpath": "//c:legend//a:ea/@typeface", + "value": "돋움", + "points": 1, + "category": "OneAnswer", + "item": "범례/① 글꼴 (돋움)" + }, + "60": { + "chart_xpath": "//c:legend//a:defRPr/@sz", + "value": "900", + "points": 1, + "category": "OneAnswer", + "item": "범례/② 크기 (9pt)" + }, + "61": { + "chart_xpath": "//c:legend//a:defRPr/@{option}", + "option": "i", + "value": "1", + "points": 1, + "category": "OneAnswer", + "item": "범례/③ 기울임", + "desc": "option값 - 기울임(Italic):i / 굵게(Bold):b" + } } } \ No newline at end of file diff --git a/diff.xlsx b/diff.xlsx new file mode 100644 index 0000000..4351b79 Binary files /dev/null and b/diff.xlsx differ diff --git a/diwScoring.py b/diwScoring.py index 2836095..5ee834a 100644 --- a/diwScoring.py +++ b/diwScoring.py @@ -615,9 +615,9 @@ def main(): # 250429기준 없는 시험 형식(A,B,C..)은 주석처리 하지 않으면 오류 발생 exam_types = [ - # 'A', + 'A', # 'B', - 'C', + # 'C', ] # test_mode = False test_mode = True diff --git a/diwScoring2.py b/diwScoring2.py index 8e28396..f833245 100644 --- a/diwScoring2.py +++ b/diwScoring2.py @@ -41,57 +41,7 @@ class XMLScorer: hwp_internal_conversion_method = 100 pt = math.trunc(mm * one_mm_per_pt * hwp_internal_conversion_method) return pt - - # XML 파일에서 element의 값을 찾아 반환 - def query_xml(self, root, *args): - first_xpath = args[0] - second_xpath = args[1] - points = args[2] - category = args[3] - - if ("특수문자" in category) and (second_xpath is not None): - try: - result = root.xpath(first_xpath) - # 결과값이 리스트형인데 내부에 정보가 없는경우 - # 결과값이 없음 - if type(result) is list and len(result) == 0: - return None - elif result < points: - result = root.xpath(second_xpath) - return result - else: - return result - except ET.XPathEvalError as e: - return None - - elif second_xpath is not None: - try: - result1 = root.xpath(first_xpath) - result2 = root.xpath(second_xpath) - if (type(result1) is list and len(result1) == 0) and (type(result2) is list and len(result2) == 0): - return None - return result1 if result1 else result2 - - except ET.XPathEvalError as e: - return None - - else: - try: - result = root.xpath(first_xpath) - if type(result) is list and len(result) == 0: - return None - return result - except ET.XPathEvalError as e: - return None - - def chart_query_xml(self, tree, xpath, namespaces): - result = tree.xpath(xpath, namespaces=namespaces) - if type(result) is list and len(result) == 0: - return None - - return result - # 유사한 텍스트 찾기 def find_similar_text(self, root, target_text, threshold=0.7): """ @@ -199,6 +149,7 @@ class XMLScorer: 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) @@ -211,13 +162,14 @@ class XMLScorer: if search_value is not None: # search_value를 포함하는 텍스트 찾기 similar_text = self.find_similar_text(root, search_value) - xpath = xpath.replace('{searchValue}', similar_text) - if xpath2 is not None: - xpath2 = xpath2.replace('{searchValue}', similar_text) + xpath = xpath.replace('{searchValue}', similar_text) if xpath else "" + xpath2 = xpath2.replace('{searchValue}', similar_text) if xpath2 else "" + 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 = { @@ -269,12 +221,14 @@ class XMLScorer: # 수험자 답안 user_answer = { ######################################################################## - # 보통 정답은 글꼴이 [바탕]이어야 하지만 대부분 설정하지 않고 + # 정답은 글꼴이 [바탕]이어야 하지만 대부분 설정하지 않고 # 기본 [함초롱바탕]으로 두는 경우가 많아 - # 폰트명을 정답과 비교하면 감점이 많이 발생해서 - # 폰트명은 정답과 비교하지 않게 적용된 상태 + # 폰트명을 정답과 비교하면 감점이 많이 발생함 + # + # 수험자가 지정한 폰트명과 정답을 비교할때 'FontName': font_name[0], 적용 + # 폰트명은 상관없이 정답을 비교하고자 할때 'FontName': "바탕", 적용 ######################################################################## - #'FontName': font_name[0], + # 'FontName': font_name[0], 'FontName': "바탕", 'FontSize': font_size[0], 'Alignment': alignment[0], @@ -292,10 +246,11 @@ class XMLScorer: # 정답이 하나인 경우 elif (category or "") == "OneAnswer": - items = root.xpath(xpath) + items = root.xpath(xpath) if xpath else [] items2 = root.xpath(xpath2) if xpath2 else [] + chart_items = chart_tree.xpath(chart_xpath, namespaces=namespaces) if chart_xpath else [] - for item in chain(items, items2): + for item in chain(items, items2, chart_items): user_answer = item self.evaluate_answer(scoring, user_answer, right_answer, points) @@ -304,7 +259,7 @@ class XMLScorer: break elif (category or "") == "DoubleAnswer": - items1 = root.xpath(xpath) + items1 = root.xpath(xpath) if xpath else [] items2 = root.xpath(xpath2) if xpath else [] user_answer = [] @@ -323,7 +278,11 @@ class XMLScorer: for item in items: user_answer = float(item) - right_answer = self.convert_mm_to_pt(float(right_answer)) + + # 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)) self.evaluate_answer(scoring, user_answer, right_answer, points, method="tolerance") @@ -347,10 +306,11 @@ class XMLScorer: # Boolean 타입 정답인 경우 elif (category or "") == "Boolean": - items = root.xpath(xpath) + 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 ) + user_answer = bool( items or items2 or chart_items ) self.evaluate_answer(scoring, user_answer, right_answer, points) @@ -453,7 +413,7 @@ class XMLScorer: self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") # 특수문자 갯수 채점 - elif "SpecialChar" in (category or ""): + elif (category or "") == "SpecialChar": ch1 = criterion.get('char1', None) ch2 = criterion.get('char2', None) ch3 = criterion.get('char3', None) @@ -493,7 +453,7 @@ class XMLScorer: self.evaluate_answer(scoring, user_answer, right_answer, points, method="partial_score") # 쪽 테두리 (이중 실선, 머리말 포함) 설정 - elif "PageBorder" in (category or ""): + elif (category or "") == "PageBorder": user_answer = { "header_inside": False, "all_double_slim": False @@ -505,33 +465,33 @@ class XMLScorer: # print("머릿말포함: ",header_inside) if "true" in header_inside: user_answer["header_inside"] = True + break # BORDERFILL요소의 자녀 # LEFTBORDER, RIGHTBORDER, TOPBORDER, BOTTOMBORDER 요소의 Type속성이 # 모두 DoubleSlim이면 정답 - border_fill_elements = root.xpath(xpath2) - for bf in border_fill_elements: - border_tags = ["LEFTBORDER", "RIGHTBORDER", "TOPBORDER", "BOTTOMBORDER"] - + 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 = bf.find(tag) - if element is None or element.get("Type") != "DoubleSlim": + element = borderfill.find(tag) + + if (element is None) or (element.get("Type") != "DoubleSlim"): all_double_slim = False break - #모든 BORDER 태그의 Type 속성이 'DoubleSlim' + #모든 BORDER 태그의 Type 속성이 'DoubleSlim'인 객체가 있다면 반복문 탈출 if all_double_slim: user_answer["all_double_slim"] = True - - # 하나 이상의 BORDER 태그가 'DoubleSlim'이 아님 - else: - user_answer["all_double_slim"] = False + break self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") # 한자 - elif "Hanja" in (category or ""): + elif (category or "") == "Hanja": word_list = criterion.get('word', []) # 점수 계산 @@ -557,7 +517,7 @@ class XMLScorer: self.evaluate_answer(scoring, user_answer, right_answer, points, method="partial_score") - elif (category or "") == "chart_type": + elif (category or "") == "ChartType": chart_type_list = { '꺾은선형': "//c:lineChart", '가로막대형': "//c:barChart[c:barDir[@val='bar']]", @@ -627,20 +587,35 @@ class XMLScorer: return xml_data - def typo_check(self, correct_answer_file, user_answer_file): + def typo_check(self, correct_answer_file, user_answer_file, chart_xml): user_answer_tree = ET.parse(user_answer_file) user_answer_root = user_answer_tree.getroot() correct_answer_tree = ET.parse(correct_answer_file) correct_answer_root = correct_answer_tree.getroot() - + # xpath로 바이너리 부분추출 user_input_text = user_answer_root.xpath('//CHAR//text()[not(ancestor::HEADER) and not(ancestor::TABLE)]') user_table_text = user_answer_root.xpath('//TABLE//CHAR//text()') user_input_text += user_table_text - + correct_input_text = correct_answer_root.xpath('//CHAR//text()[not(ancestor::HEADER) and not(ancestor::TABLE)]') correct_table_text = correct_answer_root.xpath('//TABLE//CHAR//text()') correct_input_text += correct_table_text + + # 차트 XML에서 제목 추출 + if chart_xml is not None: + chart_xml_tree = ET.fromstring(chart_xml) + + # 차트 제목 추출 + user_chart_title = chart_xml_tree.xpath('/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:r/a:t', namespaces={'c': 'http://schemas.openxmlformats.org/drawingml/2006/chart', 'a': 'http://schemas.openxmlformats.org/drawingml/2006/main'}) + + # 차트 제목이 존재하는 경우 + if user_chart_title: + user_input_text.append(user_chart_title[0].text) + + # 차트 제목 정답 텍스트 추출 + correct_chart_title = self.scoring_criteria["2"]["50"]["searchValue"] + correct_input_text.append(correct_chart_title) # 각 요소에서 공백 제거 user_input_text = [text.replace(' ', '') for text in user_input_text] @@ -652,8 +627,9 @@ class XMLScorer: correct_input_text = [re.sub(r'\d+\.\s*|-', '', text) for text in correct_input_text] try : - xpath = self.scoring_criteria["2-29"]['path'].split("'")[1] - ignore_word = xpath.split("'")[1] + # xpath = self.scoring_criteria["2"]["29"]['path'].split("'")[1] + # ignore_word = xpath.split("'")[1] + ignore_word = self.scoring_criteria["2"]["29"]["ignoreWord"] # 특정 단어 제거 # 오타와 누락의 경우만 판단하면 정상작동하지만 # 추가 된 단어의 경우를 채점기준에 추가하면 정확하게 채점 되지 않을 수 있음 @@ -746,7 +722,7 @@ class XMLScorer: 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) + 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) @@ -869,8 +845,8 @@ def main(): # 'B', # 'C', ] - # test_mode = False - test_mode = True + test_mode = False + # test_mode = True output_excel_paths = [] for exam_type in exam_types: diff --git a/filtered_score_diff.py b/filtered_score_diff.py new file mode 100644 index 0000000..cf70d97 --- /dev/null +++ b/filtered_score_diff.py @@ -0,0 +1,25 @@ +import pandas as pd + +# 엑셀 파일 경로 +file_path = "./diff.xlsx" + +# 엑셀 파일 읽기 +df = pd.read_excel(file_path) + +# 데이터 미리 보기 +df.head() + +# '총점' 컬럼 기준으로 점수가 다른 경우만 남기기 +filtered_df = df.groupby("Unnamed: 0").filter(lambda x: x["총점"].nunique() > 1) + +# 결과 확인 +filtered_df.head() + +# 점수가 다른 경우만 남기는 필터링 +filtered_df = df.groupby("Unnamed: 0").filter(lambda x: x["총점"].nunique() > 1) + +# 결과 저장 +output_path = "./filtered_score_diff.xlsx" +filtered_df.to_excel(output_path, index=False) + +output_path \ No newline at end of file diff --git a/filtered_score_diff.xlsx b/filtered_score_diff.xlsx new file mode 100644 index 0000000..206c472 Binary files /dev/null and b/filtered_score_diff.xlsx differ diff --git a/zzz.xbook b/zzz.xbook index 791db43..2709891 100644 --- a/zzz.xbook +++ b/zzz.xbook @@ -1 +1 @@ -[{"kind":2,"language":"xpath","value":"//BORDERFILL[@Id=//PAGEBORDERFILL[@Type='Both' or @Type='Even']/@BorferFill]/*[contains(local-name(), 'BORDER')]/@Type"},{"kind":2,"language":"xpath","value":"//BORDERFILL[@Id=//SECTION[2]//PAGEBORDERFILL[@Type='Both' or @Type='Even']/@BorferFill]"},{"kind":2,"language":"xpath","value":"//RECTANGLE//CHAR[text()='클라우드 컴퓨팅']/ancestor::RECTANGLE/descendant::LINESHAPE"},{"kind":2,"language":"xpath","value":"//RECTANGLE[.//CHAR[text()='클라우드 컴퓨팅']]//LINESHAPE"},{"kind":2,"language":"xpath","value":"//RECTANGLE[.//CHAR[text()='클라우드 컴퓨팅']]/SHAPEOBJECT/POSITION/@TreatAsChar"},{"kind":2,"language":"xpath","value":"//PARASHAPE[@Id=//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::P[last()]/@ParaShape]/@Align"},{"kind":2,"language":"xpath","value":"//CHARSHAPE[@Id=//RECTANGLE//CHAR[text()='클라우드 컴퓨팅']/parent::TEXT/@CharShape]/@Height"},{"kind":2,"language":"xpath","value":"//PARASHAPE[@Id=//RECTANGLE//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align"},{"kind":2,"language":"xpath","value":"//IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]/preceding-sibling::SHAPEOBJECT/SIZE/@Width"},{"kind":2,"language":"xpath","value":"//CHAR[text()='{searchValue}']/parent::TEXT/@CharShape"},{"kind":2,"language":"xpath","value":"//TEXT[CHAR[text()='{searchValue}']]/@CharShape"},{"kind":2,"language":"xpath","value":"//PARASHAPE[@Id=//P[.//TEXTART[@Text='클라우드컴퓨팅컨퍼런스']]/@ParaShape]/@Align"},{"kind":2,"language":"xpath","value":"//CHARSHAPE[@Id=//TEXT[CHAR[contains(text(),'클라우드 보안(단위: 백만 달러)')]]/@CharShape]/@Height"},{"kind":2,"language":"xpath","value":"//TEXT[CHAR[contains(text(),'클라우드')]]/FOOTNOTE[CHAR[contains(text(),'인터넷을 통해 액세스할 수 있는 가상화된 서버에서 실행되는 프로그램과 데이터베이스를 제공하는 환경')]]"},{"kind":2,"language":"xpath","value":"//TEXT[CHAR[contains(text(),'클라우드')]]/FOOTNOTE[.//CHAR[contains(text(),'인터넷을 통해 액세스할 수 있는 가상화된 서버에서 실행되는 프로그램과 데이터베이스를 제공하는 환경')]]"},{"kind":2,"language":"xpath","value":"//TEXT[CHAR[contains(text(),'클라우드')]]/FOOTNOTE"},{"kind":2,"language":"xpath","value":"//CHARSHAPE[@Id=//TEXT[CHAR[text()='클라우드 보안(단위: 백만 달러)']]/@CharShape]"},{"kind":2,"language":"xpath","value":"//PARASHAPE[@Id=//P[.//CHAR[text()='클라우드 보안(단위: 백만 달러)']]/@ParaShape]/@Align"},{"kind":2,"language":"xpath","value":"//PARASHAPE[@Id=//CHAR[contains(text(),'클라우드 보안(단위: 백만 달러)')]/ancestor::P/@ParaShape]/@Align"},{"kind":2,"language":"xpath","value":"//BORDERFILL[@Id=//CELLZONE[@StartRowAddr='0' and @EndRowAddr='0' and @StartColAddr='0' and @EndColAddr=(ancestor::TABLE[1]/@ColCount)-1]/@BorderFill]/FILLBRUSH/WINDOWBRUSH/@FaceColor"},{"kind":2,"language":"xpath","value":"//BORDERFILL[@Id=//CELLZONE[@EndColAddr=../../@ColCount]]"},{"kind":2,"language":"xpath","value":"//CHARSHAPE[@Id=//TABLE//TEXT/@CharShape]/@Height"},{"kind":2,"language":"xpath","value":"//PARASHAPE[@Id=//TABLE/ROW//P/@ParaShape]/@Align"},{"kind":2,"language":"xpath","value":"//TABLE[1]/ROW[last()]/CELL[last()-1]//FIELDBEGIN[starts-with(@Command, '=SUM')]"},{"kind":2,"language":"xpath","value":"//TABLE[1]/ROW[last()]/CELL[position() = last() or position() = last() - 1]//FIELDBEGIN[starts-with(@Command, '=SUM')]\r\n"}] \ No newline at end of file +[{"kind":2,"language":"xpath","value":"//BORDERFILL[@Id=//PAGEBORDERFILL[@Type='Both' or @Type='Even']/@BorferFill]/*[contains(local-name(), 'BORDER')]/@Type"},{"kind":2,"language":"xpath","value":"//BORDERFILL[@Id=//SECTION[2]//PAGEBORDERFILL[@Type='Both' or @Type='Even']/@BorferFill]"},{"kind":2,"language":"xpath","value":"//RECTANGLE//CHAR[text()='클라우드 컴퓨팅']/ancestor::RECTANGLE/descendant::LINESHAPE"},{"kind":2,"language":"xpath","value":"//RECTANGLE[.//CHAR[text()='클라우드 컴퓨팅']]//LINESHAPE"},{"kind":2,"language":"xpath","value":"//RECTANGLE[.//CHAR[text()='클라우드 컴퓨팅']]/SHAPEOBJECT/POSITION/@TreatAsChar"},{"kind":2,"language":"xpath","value":"//PARASHAPE[@Id=//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::P[last()]/@ParaShape]/@Align"},{"kind":2,"language":"xpath","value":"//CHARSHAPE[@Id=//RECTANGLE//CHAR[text()='클라우드 컴퓨팅']/parent::TEXT/@CharShape]/@Height"},{"kind":2,"language":"xpath","value":"//PARASHAPE[@Id=//RECTANGLE//P[.//CHAR[text()='{searchValue}']]/@ParaShape]/@Align"},{"kind":2,"language":"xpath","value":"//IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]/preceding-sibling::SHAPEOBJECT/SIZE/@Width"},{"kind":2,"language":"xpath","value":"//CHAR[text()='{searchValue}']/parent::TEXT/@CharShape"},{"kind":2,"language":"xpath","value":"//TEXT[CHAR[text()='{searchValue}']]/@CharShape"},{"kind":2,"language":"xpath","value":"//PARASHAPE[@Id=//P[.//TEXTART[@Text='클라우드컴퓨팅컨퍼런스']]/@ParaShape]/@Align"},{"kind":2,"language":"xpath","value":"//CHARSHAPE[@Id=//TEXT[CHAR[contains(text(),'클라우드 보안(단위: 백만 달러)')]]/@CharShape]/@Height"},{"kind":2,"language":"xpath","value":"//TEXT[CHAR[contains(text(),'클라우드')]]/FOOTNOTE[CHAR[contains(text(),'인터넷을 통해 액세스할 수 있는 가상화된 서버에서 실행되는 프로그램과 데이터베이스를 제공하는 환경')]]"},{"kind":2,"language":"xpath","value":"//TEXT[CHAR[contains(text(),'클라우드')]]/FOOTNOTE[.//CHAR[contains(text(),'인터넷을 통해 액세스할 수 있는 가상화된 서버에서 실행되는 프로그램과 데이터베이스를 제공하는 환경')]]"},{"kind":2,"language":"xpath","value":"//TEXT[CHAR[contains(text(),'클라우드')]]/FOOTNOTE"},{"kind":2,"language":"xpath","value":"//CHARSHAPE[@Id=//TEXT[CHAR[text()='클라우드 보안(단위: 백만 달러)']]/@CharShape]"},{"kind":2,"language":"xpath","value":"//PARASHAPE[@Id=//P[.//CHAR[text()='클라우드 보안(단위: 백만 달러)']]/@ParaShape]/@Align"},{"kind":2,"language":"xpath","value":"//PARASHAPE[@Id=//CHAR[contains(text(),'클라우드 보안(단위: 백만 달러)')]/ancestor::P/@ParaShape]/@Align"},{"kind":2,"language":"xpath","value":"//BORDERFILL[@Id=//CELLZONE[@StartRowAddr='0' and @EndRowAddr='0' and @StartColAddr='0' and @EndColAddr=(ancestor::TABLE[1]/@ColCount)-1]/@BorderFill]/FILLBRUSH/WINDOWBRUSH/@FaceColor"},{"kind":2,"language":"xpath","value":"//BORDERFILL[@Id=//CELLZONE[@EndColAddr=../../@ColCount]]"},{"kind":2,"language":"xpath","value":"//CHARSHAPE[@Id=//TABLE//TEXT/@CharShape]/@Height"},{"kind":2,"language":"xpath","value":"//PARASHAPE[@Id=//TABLE/ROW//P/@ParaShape]/@Align"},{"kind":2,"language":"xpath","value":"//TABLE[1]/ROW[last()]/CELL[last()-1]//FIELDBEGIN[starts-with(@Command, '=SUM')]"},{"kind":2,"language":"xpath","value":"//c:chart and not(//c:pt[not(ancestor::c:tx)]/c:v[text()='합계' or text()='평균'])"},{"kind":2,"language":"xpath","value":"//BORDERFILL[@Id=//PAGEBORDERFILL[@Type='Both' or @Type='Even']/@BorferFill]"},{"kind":2,"language":"xpath","value":"//PAGEBORDERFILL[@Type='Both' or @Type='Even']/@HeaderInside"}] \ No newline at end of file diff --git a/구버전신버전점수비교A형.xlsx b/구버전신버전점수비교A형.xlsx new file mode 100644 index 0000000..918dd34 Binary files /dev/null and b/구버전신버전점수비교A형.xlsx differ diff --git a/회차별채점자료/2504/excel_채점기준표/DIW_2504A.xlsx b/회차별채점자료/2504/excel_채점기준표/DIW_2504A.xlsx index d297037..871f8dd 100644 Binary files a/회차별채점자료/2504/excel_채점기준표/DIW_2504A.xlsx and b/회차별채점자료/2504/excel_채점기준표/DIW_2504A.xlsx differ