v2 - 문제2 6번문항까지

This commit is contained in:
2025-05-13 19:46:19 +09:00
parent ac655d58d3
commit 8c93c6d446
5 changed files with 163 additions and 59 deletions

Binary file not shown.

View File

@@ -37,7 +37,6 @@
},
"3": {
"path": "",
"searchValue": null,
"value": null,
"points": 40,
"category": "오타감점",
@@ -97,7 +96,6 @@
},
"7": {
"path": "//TEXTART[@Text='{searchValue}']",
"path2": null,
"searchValue": "클라우드컴퓨팅컨퍼런스",
"value": true,
"points": 2,
@@ -106,7 +104,6 @@
},
"8": {
"path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]/SHAPEOBJECT/SIZE",
"path2": null,
"searchValue": "전",
"value": {
"Height": 2800,
@@ -119,7 +116,6 @@
},
"9": {
"path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
"path2": null,
"searchValue": "전",
"value": "궁서체",
"points": 1,
@@ -128,7 +124,6 @@
},
"10": {
"path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor",
"path2": null,
"searchValue": "전",
"value": "255,132,58",
"points": 2,
@@ -137,9 +132,8 @@
},
"11": {
"path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//OUTSIDEMARGIN/@Right",
"path2": null,
"searchValue": "전",
"value": "850",
"value": "3.0",
"tolerance": 1,
"points": 2,
"category": "mmSize",
@@ -147,20 +141,19 @@
},
"12": {
"path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]",
"path2": null,
"searchValue": "한옥에 대한 체험과 교육이 준비된 사생대회",
"searchValue": "글로벌 클라우드 컴퓨팅 컨퍼런스",
"value": "BOLD",
"points": 2,
"category": "FontAttribute",
"item": "문구 (한옥에 대한 체험과 교육이 준비된 사생대회)/① 진하게"
"item": "문구 (글로벌 클라우드 컴퓨팅 컨퍼런스)/① 진하게"
},
"13": {
"path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]",
"searchValue": "한옥에 대한 체험과 교육이 준비된 사생대회",
"searchValue": "글로벌 클라우드 컴퓨팅 컨퍼런스",
"value": "UNDERLINE",
"points": 2,
"category": "FontAttribute",
"item": "문구 (한옥에 대한 체험과 교육이 준비된 사생대회)/② 밑줄"
"item": "문구 (글로벌 클라우드 컴퓨팅 컨퍼런스)/② 밑줄"
},
"14": {
"path": "//CHAR[contains(text(),'{char1}')]",
@@ -176,35 +169,35 @@
},
"15": {
"path": "//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape",
"searchValue": "■ 행사안내 ■",
"value": "돋움",
"searchValue": "참여안내",
"value": "궁서",
"points": 1,
"category": "FontName",
"item": "문구 (■ 행사안내 )/① 글씨체 (돋움)"
"item": "문구 (● 참여안내 )/① 글씨체 (궁서)"
},
"16": {
"path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/@ParaShape]/@Align",
"searchValue": "■ 행사안내 ■",
"searchValue": "참여안내",
"value": "Center",
"points": 1,
"category": "SingleAnswer",
"item": "문구 (■ 행사안내 )/② 정렬 (가운데 정렬)"
"item": "문구 (● 참여안내 )/② 정렬 (가운데 정렬)"
},
"17": {
"path": "//CHARSHAPE[@Id=//CHAR[text()='{searchValue}']/parent::TEXT/@CharShape]",
"searchValue": "홈페이지(http://www.ihd.or.kr)에서 개별 신청, 선착순 접수",
"searchValue": "홈페이지(http://www.ihd.or.kr) 참조",
"value": "ITALIC",
"points": 1,
"category": "FontAttribute",
"item": "문구 (홈페이지(http://www.ihd.or.kr)에서 개별 신청, 선착순 접수)/① 기울임"
"item": "문구 (홈페이지(http://www.ihd.or.kr) 참조)/① 기울임"
},
"18": {
"path": "//CHARSHAPE[@Id=//CHAR[text()='{searchValue}']/parent::TEXT/@CharShape]",
"searchValue": "홈페이지(http://www.ihd.or.kr)에서 개별 신청, 선착순 접수",
"searchValue": "홈페이지(http://www.ihd.or.kr) 참조",
"value": "UNDERLINE",
"points": 1,
"category": "FontAttribute",
"item": "문구 (홈페이지(http://www.ihd.or.kr)에서 개별 신청, 선착순 접수)/② 밑줄"
"item": "문구 (홈페이지(http://www.ihd.or.kr) 참조)/② 밑줄"
},
"19": {
"path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/following-sibling::P[1]/@ParaShape]/PARAMARGIN",
@@ -216,55 +209,56 @@
"points": 2,
"category": "ParaShape",
"item": "문구 (※ 기타… 이하 문단)/왼쪽여백 (15pt), 내어쓰기 (12pt)",
"desc": "내부적으로 내어쓰기는 음수값"
"desc": "내부적으로 내어쓰기는 음수값 / JSON value값은 양수로 입력"
},
"20": {
"path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]/@Height",
"searchValue": "2025. 03. 22.",
"value": "1300",
"searchValue": "2025. 04. 26.",
"value": "1400",
"points": 1,
"category": "SingleAnswer",
"item": "문구 (2025. 03. 22.)/① 크기 (13pt)"
"item": "문구 (2025. 04. 26.)/① 크기 (14pt)",
"desc": "1pt당 100"
},
"21": {
"path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/@ParaShape]/@Align",
"searchValue": "2025. 03. 22.",
"searchValue": "2025. 04. 26.",
"value": "Center",
"points": 1,
"category": "SingleAnswer",
"item": "문구 (2025. 03. 22.)/② 정렬 (가운데 정렬)"
"item": "문구 (2025. 04. 26.)/② 정렬 (가운데 정렬)"
},
"22": {
"path": "//CHAR[text()='{searchValue}']/parent::TEXT/@CharShape",
"searchValue": "한국고건축협회",
"value": "궁서",
"searchValue": "글로벌멀티클라우드협의회",
"value": "궁서",
"points": 1,
"category": "FontName",
"item": "문구 (한국고건축협회)/① 글씨체 (궁서)"
"item": "문구 (글로벌멀티클라우드협의회)/① 글씨체 (궁서)"
},
"23": {
"path": "//CHARSHAPE[@Id=//CHAR[text()='{searchValue}']/parent::TEXT/@CharShape]/@Height",
"searchValue": "한국고건축협회",
"value": "2400",
"searchValue": "글로벌멀티클라우드협의회",
"value": "2600",
"points": 1,
"category": "SingleAnswer",
"item": "문구 (한국고건축협회)/② 크기 (24pt)"
"item": "문구 (글로벌멀티클라우드협의회)/② 크기 (26pt)"
},
"24": {
"path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/ancestor::P/@ParaShape]/@Align",
"searchValue": "한국고건축협회",
"searchValue": "글로벌멀티클라우드협의회",
"value": "Center",
"points": 1,
"category": "SingleAnswer",
"item": "문구 (한국고건축협회)/③ 정렬 (가운데 정렬)"
"item": "문구 (글로벌멀티클라우드협의회)/③ 정렬 (가운데 정렬)"
},
"25": {
"path": "//CHAR[text()='{searchValue}']/parent::TEXT/@CharShape",
"searchValue": "DIAT",
"value": "굴림",
"value": "궁서",
"points": 1,
"category": "FontName",
"item": "문구 (DIAT)/① 글꼴 (굴림)"
"item": "문구 (DIAT)/① 글꼴 (궁서)"
},
"26": {
"path": "//CHARSHAPE[@Id=//SECTION[1]//CHAR[text()='{searchValue}']/parent::TEXT/@CharShape]/@Height",
@@ -284,36 +278,92 @@
},
"28": {
"path": "//PAGENUM/@FormatType",
"value": "HangulSyllable",
"value": "LatinCapital",
"points": 2,
"category": "SingleAnswer",
"item": "① 쪽 번호 매기기 (가,나,다 순으로)"
"item": "① 쪽 번호 매기기 (A,B,C 순으로)",
"desc": {
"가,나,다":"HangulSyllable",
"1,2,3":"Digit",
"갑,을,병":"DecagonCircle",
"A,B,C":"LatinCapital",
"①,②,③":"CircledDigit",
"一,二,三":"Ideograph",
"㉠,㉡,㉢":"CircledHangulJamo",
"ⓐ,ⓑ,ⓒ":"CircledLatinSmall",
"i,ii,iii":"RomanSmall",
"정답에 맞는 값 value에 입력":""
}
},
"29": {
"path": "//PAGENUM/@Pos",
"value": "BottomCenter",
"value": "BottomRight",
"points": 2,
"category": "SingleAnswer",
"item": "② 가운데 아래"
"item": "오른쪽 아래"
},
"30": {
"path": "not(//PARASHAPE[@Id=//SECTION[1]/P/@ParaShape]/PARAMARGIN[@LineSpacing!='180'])",
"path": "not(//PARASHAPE[@Id=//SECTION[1]/P/@ParaShape]/PARAMARGIN[@LineSpacing!='200'])",
"value": true,
"points": 2,
"category": "Boolean",
"item": "문제 1 줄간격 180% 설정",
"desc": "1페이지 문단의 줄간격이 180%가 아닌 문단이 있으면 False(감점)"
"item": "문제 1 줄간격 200% 설정",
"desc": "1페이지 문단의 줄간격이 200%가 아닌 문단이 있으면 False(감점)"
}
},
"2": {
"1": {
"path": "//SECTION[2]//PAGEBORDERFILL[@Type='Both' or @Type='Even']",
"path2": "boolean(//PAGEBORDERFILL[@Type='Both' or @Type='Even']/@HeaderInside='true' and //BORDERFILL[@Id=//PAGEBORDERFILL[@Type='Both' or @Type='Even']/@BorferFill]/*[contains(local-name(), 'BORDER')]/@Type='DoubleSlim')",
"value": true,
"path": "//SECTION[2]//PAGEBORDERFILL[@Type='Both' or @Type='Even']/@HeaderInside",
"path2": "//BORDERFILL[@Id=//SECTION[2]//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": "//SECTION[2]//COLDEF/@Count",
"value": "2",
"points": 3,
"category": "SingleAnswer",
"item": "② 다단 2단"
},
"4": {
"path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width",
"searchValue": "클라우드 컴퓨팅",
"value": "60",
"points": 2,
"category": "mmSize",
"item": "문구 (클라우드 컴퓨팅)/① 크기-너비 (60mm)"
},
"5": {
"path": "//RECTANGLE//CHAR[text()='{searchValue}']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Height",
"searchValue": "클라우드 컴퓨팅",
"value": "12",
"points": 2,
"category": "mmSize",
"item": "문구 (클라우드 컴퓨팅)/② 크기-높이 (12mm)"
},
"6": {
"path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE/@Style",
"path2": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//LINESHAPE/@Width",
"searchValue": "클라우드 컴퓨팅",
"value": [ "DoubleSlim", "283" ],
"points": 2,
"category": "DoubleAnswer",
"item": "문구 (클라우드 컴퓨팅)/③ 테두리 : 이중 실선(1.00mm)"
},
"61": {}
}
}

View File

@@ -209,7 +209,8 @@ class XMLScorer:
# search_value를 포함하는 텍스트 찾기
similar_text = self.find_similar_text(root, search_value)
xpath = xpath.replace('{searchValue}', similar_text)
# xpath2 = xpath2.replace('{searchValue}', similar_text)
if xpath2 is not None:
xpath2 = xpath2.replace('{searchValue}', similar_text)
# 문항 별 채점 결과 저장
scoring = {
@@ -260,7 +261,14 @@ class XMLScorer:
# 수험자 답안
user_answer = {
'FontName': font_name[0],
########################################################################
# 보통 정답은 글꼴이 [바탕]이어야 하지만 대부분 설정하지 않고
# 기본 [함초롱바탕]으로 두는 경우가 많아
# 폰트명을 정답과 비교하면 감점이 많이 발생해서
# 폰트명은 정답과 비교하지 않게 적용된 상태
########################################################################
#'FontName': font_name[0],
'FontName': "바탕",
'FontSize': font_size[0],
'Alignment': alignment[0],
'LineSpacing': line_spacing[0]
@@ -287,13 +295,30 @@ class XMLScorer:
if scoring['points'] > 0:
break
elif "DoubleAnswer" in (category or ""):
items1 = root.xpath(xpath)
items2 = root.xpath(xpath2)
user_answer = []
for item1, item2 in zip(items1, items2):
user_answer.append(item1)
user_answer.append(item2)
# user_answer[0] = item1
# user_answer[1] = item2
self.evaluate_answer(scoring, user_answer, right_answer, points)
if scoring['points'] > 0:
break
# 사용자 입력값이 mm단위인 경우
elif "mmSize" in (category or ""):
items = root.xpath(xpath)
error_range = criterion.get('tolerance', 0)
for item in items:
user_answer = int(item)
right_answer = self.convert_mm_to_pt(int(right_answer))
user_answer = float(item)
right_answer = self.convert_mm_to_pt(float(right_answer))
self.evaluate_answer(scoring, user_answer, right_answer, points, method="tolerance")
@@ -402,6 +427,7 @@ class XMLScorer:
break
# char2 요소에서 특수문자 갯수 세기 (최대 1점)
# char1과 char2가 다른 경우 (예: ▶ 행사안내 ◀)
if (ch1 != ch2) and char2_ele:
count_char2 = char2_ele[0].text.count(ch2)
if count_char2 > 1:
@@ -419,16 +445,44 @@ class XMLScorer:
self.evaluate_answer(scoring, user_answer, right_answer, points, method="partial_score")
# 쪽 테두리
# 쪽 테두리 (이중 실선, 머리말 포함) 설정
elif "PageBorder" in (category or ""):
pageBorderfills = root.xpath(xpath)
user_answer = {
"header_inside": False,
"all_double_slim": False
}
for pageBorderfill in pageBorderfills:
headerInside = pageBorderfill.get('HeaderInside')
borderfill_id = pageBorderfill.get('BorferFill')
print( f"headerInside: {headerInside}, borderfill_id: {borderfill_id}")
break
# 머릿말 포함 객체가 하나라도 있으면 정답
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
# 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"]
all_double_slim = True
for tag in border_tags:
element = bf.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
# 하나 이상의 BORDER 태그가 'DoubleSlim'이 아님
else:
user_answer["all_double_slim"] = False
self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal")
onePersonResult['score_results'].append(scoring)
print(f'scoring: {scoring}')

View File

@@ -1 +1 @@
[{"kind":2,"language":"xpath","value":"//c:catAx//a:defRPr/@i"},{"kind":2,"language":"xpath","value":"count(//CHAR[contains(text(),'◆')]) + count(//CHAR[contains(text(),'※')])"},{"kind":2,"language":"xpath","value":"string-length(//CHAR[contains(text(),'◆')]) - string-length(translate(//CHAR[contains(text(),'◆')], '◆', '')) + string-length(//CHAR[contains(text(),'※')]) - string-length(translate(//CHAR[contains(text(),'※')], '※', ''))"}]
[{"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":"//BORDERFILL[@Id=//SECTION[2]//PAGEBORDERFILL[@Type='Both' or @Type='Even']/@BorferFill][not(*[substring(name(), string-length(name()) - 5) = 'BORDER'][not(@Type = 'DoubleSlim')])]"},{"kind":2,"language":"xpath","value":"//BORDERFILL[*[substring(name(), string-length(name()) - 5) = 'BORDER' and @Type = 'DoubleSlim']]"}]