From db5ae5b459fd0627c8e23778f85d1329dba9c0ca Mon Sep 17 00:00:00 2001 From: dragdra Date: Fri, 27 Jun 2025 16:22:18 +0900 Subject: [PATCH] =?UTF-8?q?[1-30]=EC=A4=84=EA=B0=84=EA=B2=A9/[2-3]?= =?UTF-8?q?=EB=8B=A4=EB=8B=A8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B5=AC?= =?UTF-8?q?=EB=B6=84=EC=9C=BC=EB=A1=9C=20=EC=B1=84=EC=A0=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 250627_DIW_2505A_TEST.xlsx | Bin 0 -> 18244 bytes DIW_2505A.json | 2 +- diwScoring2.py | 193 ++++++++++--------------------------- zzz.xbook | 2 +- 4 files changed, 55 insertions(+), 142 deletions(-) create mode 100644 250627_DIW_2505A_TEST.xlsx diff --git a/250627_DIW_2505A_TEST.xlsx b/250627_DIW_2505A_TEST.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..9b09b88584f34266867764f0c1d8d041c7c2a95b GIT binary patch literal 18244 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 literal 0 HcmV?d00001 diff --git a/DIW_2505A.json b/DIW_2505A.json index f17b345..7f947f9 100644 --- a/DIW_2505A.json +++ b/DIW_2505A.json @@ -342,7 +342,7 @@ "desc": "섹션이 1개 이상이면 점수부여" }, "3": { - "path": "//COLDEF", + "path": "TEXT/COLDEF/@Count", "value": "2", "points": 3, "category": "TwoColumn", diff --git a/diwScoring2.py b/diwScoring2.py index cf58c98..a31f4af 100644 --- a/diwScoring2.py +++ b/diwScoring2.py @@ -127,6 +127,33 @@ class XMLScorer: # 하나의 XML 파일 채점 def _score_xml_file(self, xml_file, chart_xml): + def parse_pages_by_bookmark(root): + """ + P/TEXT/BOOKMARK 구조를 가진 XML에서 페이지 구간별

요소를 파싱하여 반환 + """ + pages = {} + all_p_tags = root.xpath('//P') + + current_page = None + page_start_index = None + + for i, p in enumerate(all_p_tags): + # BOOKMARK가 존재하는지 확인 + 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 + 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): """ 주어진

요소에서 모든 자손 의 텍스트를 추출해 문자열 리스트로 반환합니다. @@ -143,6 +170,10 @@ class XMLScorer: 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', @@ -163,7 +194,7 @@ class XMLScorer: 'total_score': 0, 'partial_scores': [] } - print(f"File name: {onePersonResult['filename']}") + print(f"🔜File name: {onePersonResult['filename']}") self.total_score = 0 for section_id, section in self.scoring_criteria.items(): @@ -364,7 +395,6 @@ class XMLScorer: right_answer = right_answer.replace(" ", "") self.evaluate_answer(scoring, user_answer, right_answer, points) - if scoring['points'] > 0: break @@ -385,8 +415,6 @@ class XMLScorer: # 사용자 입력값이 mm단위인 경우 elif (category or "") == "mmSize": items = root.xpath(xpath) - - # 오차범위 설정 # 한글 프로그램 내부에서 드물게 0mm이지만 1pt로 저장되는 경우가 있음 # @@ -661,23 +689,11 @@ class XMLScorer: self.evaluate_answer(scoring, user_answer, right_answer, 0, method="equal") elif (category or "") == "LineSpacing": - # //SECTION[1](1페이지의) 모든 P요소 - all_p_tags = root.xpath("//SECTION[1]/P") - - # 구역이 나뉘어 있지 않은 답안의 처리 - # 수험자가 구역 나눔을 적용하지 않고 2페이지 답안을 처리하기 위해서 - # [Control+Enter]를 이용해 쪽 나눔을 적용하는 부분을 검색 - # P태그의 PageBreak속성값이 'true'가 나오기 전까지의 P태그만 확인 - p_tags_before_pagebreak = [] - for p in all_p_tags: - if p.get('PageBreak') == 'true': - break - else: - p_tags_before_pagebreak.append(p) + page1_ptags = pages.get('Page_1', []) # 줄간격이 하나라도 일치하지 않을 경우 오답처리 linespacing_match = True - for p in p_tags_before_pagebreak: + for p in page1_ptags: parashape_id = p.get('ParaShape') xpath = xpath.replace('{parashape_id}', parashape_id) linespacing = root.xpath(xpath) @@ -784,125 +800,18 @@ class XMLScorer: # 다단 확인 [2-3]문항 elif (category or "") == "TwoColumn": - has_section2 = root.xpath('//SECTION[2]') + page2_ptags = pages.get('Page_2', []) - # 구역 나눔이 적용 되어 있지 않은 경우 - # (= SECTION[2]가 없을 경우) - if not has_section2: - - # 모든

요소 가져오기 - p_elements = root.xpath('//SECTION/P') - - # PageBreak='true' 속성을 가진 P태그 인덱스 - # [=쪽나눔 이후 페이지의 첫 문단들] - pagebreak_index_list = [] - for i, p in enumerate(p_elements): - xml_index = i + 1 - if p.get("PageBreak") == "true": - pagebreak_index_list.append(xml_index) - - # 페이지 별 시작 문단~끝 문단 구간 저장 - page_ranges = [] - start = 1 # XML은 1-based index - # pagebreak_index_list에 따라 구간 나누기 - for index in pagebreak_index_list: - end = index - 1 - page_ranges.append((start, end)) - start = index - - # 마지막 페이지 구간 추가 - page_ranges.append((start, len(p_elements))) # 끝까지 - - # 출력 확인 - # for i, (start, end) in enumerate(page_ranges, 1): - # print(f"📄 Page {i}: {start} ~ {end}") + for p in page2_ptags: + column_count = p.xpath(xpath) + user_answer = column_count[0] if column_count else '0' - # 단수 구간 결과를 저장할 리스트 - column_sections = [] - - current_count = None - start_index = None - - # 모든 P태그를 순회하며 단 나눔이 1단인 구간과 2단인 구간을 저장 - for i, p in enumerate(p_elements): - xml_index = i + 1 # XML 기준 1-based index - coldef = p.xpath('.//COLDEF') - - if coldef: - # 다단 수(2단) - column_count = coldef[0].get('Count') - - # 첫 번째 Count 발견 시 시작점 설정 - if current_count is None: - current_count = column_count - start_index = i - - # Count 값이 변경되었을 때 이전 구간을 저장 - elif column_count != current_count: - column_sections.append((start_index, i - 1, current_count)) - # 새 구간 시작 - current_count = column_count - start_index = i - - # 마지막 구간 저장 - if current_count is not None and start_index is not None: - column_sections.append((start_index, len(p_elements) - 1, current_count)) - - # 결과 출력 - # for start, end, count in column_sections: - # xml_start = start + 1 # XML 기준 1-based index - # xml_end = end + 1 - # print(f"📄 {count}단 구간: P[{xml_start}] ~ P[{xml_end}]") - - # 2페이지 구간 가져오기 (인덱스는 0-based지만 값은 1-based) - if len(page_ranges) > 1: - second_page_start, second_page_end = page_ranges[1] - - # 2페이지가 없을 경우 1페이지(문서 전체) 내용으로 대체 - # 문서 전체에서 2단 문단이 있을 경우는 정답 - else: - second_page_start, second_page_end = page_ranges[0] - # 2페이지가 없을 경우 오답 처리 - # else: - # user_answer = None - - # 2단 포함 여부 확인 변수 - has_two_column_in_page2 = False - - # 2단 구간이 2페이지 범위와 겹치는지 확인 - # col_start : 다단 시작 P태그 인덱스 - # col_end : 다단 끝 P태그 인덱스 - # col_count : 다단 수 - for col_start, col_end, col_count in column_sections: - two_col_start = col_start + 1 # 1-based - two_col_end = col_end + 1 - - if col_count == '2': - # 구간이 겹치는지 확인 - if two_col_end >= second_page_start and two_col_start <= second_page_end: - has_two_column_in_page2 = True - user_answer = col_count - break - - # print("✅ 2페이지에 2단 있음" if has_two_column_in_page2 else "❌ 2페이지에 2단 없음") - - if has_two_column_in_page2: + if user_answer == right_answer: self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") - - # SECTION[2]가 존재하는 경우 - else: # has_section2 - coldef_in_section2 = has_section2[0].xpath('//COLDEF') - has_correct_column_count = False - - for coldef in coldef_in_section2: - column_count = coldef.get('Count') - user_answer = column_count - if user_answer == right_answer: - has_correct_column_count = True + + # P태그들 중 하나라도 다단이 존재할 경우 정답처리 + if scoring['points'] > 0: break - - if has_correct_column_count: - self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal") # 한자 elif (category or "") == "Hanja": @@ -1031,17 +940,21 @@ class XMLScorer: 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('/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'}) + chart_title = chart_xml_tree.xpath(xpath_expr, namespaces=ns) # 차트 제목이 존재하는 경우 - if chart_title: - user_chart_title = chart_title[0].text - correct_chart_title = self.scoring_criteria["2"]["50"]["searchValue"] + user_chart_title = chart_title[0].text if chart_title else "" try : ignore_word = self.scoring_criteria["2"]["29"]["ignoreWord"] @@ -1296,8 +1209,8 @@ class XMLScorer: def main(): # 시험회차 및 유형 - # exam_round = '2505' - exam_round = '2506_3' + exam_round = '2505' + # exam_round = '2506_3' # 채점하고자 하는 유형은 주석 해제 exam_types = [ diff --git a/zzz.xbook b/zzz.xbook index c134c20..66bf55a 100644 --- a/zzz.xbook +++ b/zzz.xbook @@ -1 +1 @@ -[{"kind":2,"language":"xpath","value":"//a:t[text()='클라우드 보안투자']/ancestor::a:r//a:ea/@typeface"},{"kind":2,"language":"xpath","value":"boolean(//FONTFACE[@Lang='Hangul']/FONT[@Id=//CHARSHAPE/FONTID/@Hangul]/@Name='바탕' and //CHARSHAPE/@Height='1000' and //PARASHAPE/PARAMARGIN/@LineSpacing='160' and //PARASHAPE/@Align='Justify')"},{"kind":2,"language":"xpath","value":"//FONTFACE[@Lang='Hangul']/FONT[@Id=//CHARSHAPE/FONTID/@Hangul]/@Name='바탕'"},{"kind":2,"language":"xpath","value":"//FONTFACE[@Lang='Hangul']/FONT[@Id=//CHARSHAPE/FONTID/@Hangul]/@Name='바탕' and //CHARSHAPE/@Height='1000' and //PARASHAPE/PARAMARGIN/@LineSpacing='160' and //PARASHAPE/@Align='Justify')"},{"kind":2,"language":"xpath","value":"/HWPML/BODY/SECTION/P[19]"},{"kind":2,"language":"xpath","value":"//SECTION"},{"kind":2,"language":"xpath","value":"//P"},{"kind":2,"language":"xpath","value":"//P[.//FIELDBEGIN[@Type='Hyperlink'] and .//CHAR[contains(., 'http')]]"},{"kind":2,"language":"xpath","value":"//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true')]/@HorzOffset"},{"kind":2,"language":"xpath","value":"//CHARSHAPE[@Id=//TEXT[CHAR[text()='지']]/@CharShape]/@Height"},{"kind":2,"language":"xpath","value":"//TABLE//CHAR//text()"}] \ No newline at end of file +[{"kind":2,"language":"xpath","value":"//a:t[text()='클라우드 보안투자']/ancestor::a:r//a:ea/@typeface"},{"kind":2,"language":"xpath","value":"boolean(//FONTFACE[@Lang='Hangul']/FONT[@Id=//CHARSHAPE/FONTID/@Hangul]/@Name='바탕' and //CHARSHAPE/@Height='1000' and //PARASHAPE/PARAMARGIN/@LineSpacing='160' and //PARASHAPE/@Align='Justify')"},{"kind":2,"language":"xpath","value":"//FONTFACE[@Lang='Hangul']/FONT[@Id=//CHARSHAPE/FONTID/@Hangul]/@Name='바탕'"},{"kind":2,"language":"xpath","value":"//FONTFACE[@Lang='Hangul']/FONT[@Id=//CHARSHAPE/FONTID/@Hangul]/@Name='바탕' and //CHARSHAPE/@Height='1000' and //PARASHAPE/PARAMARGIN/@LineSpacing='160' and //PARASHAPE/@Align='Justify')"},{"kind":2,"language":"xpath","value":"/HWPML/BODY/SECTION/P[19]"},{"kind":2,"language":"xpath","value":"//SECTION"},{"kind":2,"language":"xpath","value":"//P"},{"kind":2,"language":"xpath","value":"//P[.//FIELDBEGIN[@Type='Hyperlink'] and .//CHAR[contains(., 'http')]]"},{"kind":2,"language":"xpath","value":"//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true')]/@HorzOffset"},{"kind":2,"language":"xpath","value":"//P//COLDEF/@Count"},{"kind":2,"language":"xpath","value":"//P[.//BOOKMARK/@Name=\"Page_2_start\"]"}] \ No newline at end of file