v2 - 검수중 (하이퍼링크 처리구문 추가)
This commit is contained in:
BIN
250519_DIW_2504회_A형_TEST.xlsx
Normal file
BIN
250519_DIW_2504회_A형_TEST.xlsx
Normal file
Binary file not shown.
BIN
250519_DIW_2504회_A형_채점결과.xlsx
Normal file
BIN
250519_DIW_2504회_A형_채점결과.xlsx
Normal file
Binary file not shown.
@@ -185,6 +185,7 @@
|
||||
},
|
||||
"17": {
|
||||
"path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]",
|
||||
"hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]",
|
||||
"searchValue": "홈페이지(http://www.ihd.or.kr) 참조",
|
||||
"value": "ITALIC",
|
||||
"points": 1,
|
||||
@@ -193,6 +194,7 @@
|
||||
},
|
||||
"18": {
|
||||
"path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]",
|
||||
"hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]",
|
||||
"searchValue": "홈페이지(http://www.ihd.or.kr) 참조",
|
||||
"value": "UNDERLINE",
|
||||
"points": 1,
|
||||
@@ -280,9 +282,9 @@
|
||||
"path": "//PAGENUM/@FormatType",
|
||||
"value": "LatinCapital",
|
||||
"points": 2,
|
||||
"category": "OneAnswer",
|
||||
"category": "PageNumber",
|
||||
"item": "① 쪽 번호 매기기 (A,B,C 순으로)",
|
||||
"desc": {
|
||||
"desc1": {
|
||||
"가,나,다":"HangulSyllable",
|
||||
"1,2,3":"Digit",
|
||||
"갑,을,병":"DecagonCircle",
|
||||
@@ -293,14 +295,16 @@
|
||||
"ⓐ,ⓑ,ⓒ":"CircledLatinSmall",
|
||||
"i,ii,iii":"RomanSmall",
|
||||
"정답에 맞는 값 value에 입력":""
|
||||
}
|
||||
},
|
||||
"desc2": "1, 2페이지 모두 정답이어야 점수 부여"
|
||||
},
|
||||
"29": {
|
||||
"path": "//PAGENUM/@Pos",
|
||||
"value": "BottomRight",
|
||||
"points": 2,
|
||||
"category": "OneAnswer",
|
||||
"item": "오른쪽 아래"
|
||||
"category": "PageNumber",
|
||||
"item": "오른쪽 아래",
|
||||
"desc": "1, 2페이지 모두 정답이어야 점수 부여"
|
||||
},
|
||||
"30": {
|
||||
"path": "not(//PARASHAPE[@Id=//SECTION[1]/P/@ParaShape]/PARAMARGIN[@LineSpacing!='200'])",
|
||||
|
||||
129
diwScoring2.py
129
diwScoring2.py
@@ -43,7 +43,7 @@ class XMLScorer:
|
||||
return pt
|
||||
|
||||
# 유사한 텍스트 찾기
|
||||
def find_similar_text(self, root, target_text, threshold=0.7):
|
||||
def find_similar_text(self, root, chart_tree, target_text, threshold=0.7):
|
||||
"""
|
||||
전체 문서에서 유사한 텍스트를 찾아 반환
|
||||
|
||||
@@ -64,7 +64,10 @@ class XMLScorer:
|
||||
'c': 'http://schemas.openxmlformats.org/drawingml/2006/chart'
|
||||
}
|
||||
|
||||
all_text = root.xpath(f"//BODY//text() | //TEXTART/@Text | //c:chart//text()", namespaces=namespaces)
|
||||
hwp_text = root.xpath(f"//BODY//text() | //TEXTART/@Text")
|
||||
chart_text = chart_tree.xpath(f"//c:chart//text()", namespaces=namespaces) if chart_tree is not None else []
|
||||
|
||||
all_text = hwp_text + chart_text
|
||||
|
||||
# 유사도 비교
|
||||
max_score = 0
|
||||
@@ -161,7 +164,7 @@ class XMLScorer:
|
||||
# search_value가 있는 경우
|
||||
if search_value is not None:
|
||||
# search_value를 포함하는 텍스트 찾기
|
||||
similar_text = self.find_similar_text(root, search_value)
|
||||
similar_text = self.find_similar_text(root, chart_tree, search_value)
|
||||
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 ""
|
||||
@@ -237,6 +240,23 @@ class XMLScorer:
|
||||
|
||||
self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal")
|
||||
|
||||
# 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()
|
||||
@@ -388,9 +408,10 @@ class XMLScorer:
|
||||
if right_answer in ["견고딕", "중고딕"]:
|
||||
user_answer = user_answer.replace("한양", "")
|
||||
|
||||
# 하나라도 다르면 바로 오답 처리
|
||||
if user_answer != right_answer:
|
||||
all_match = False
|
||||
break # 하나라도 다르면 바로 오답 처리
|
||||
break
|
||||
|
||||
if all_match:
|
||||
self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal")
|
||||
@@ -399,18 +420,96 @@ class XMLScorer:
|
||||
|
||||
# 폰트 속성
|
||||
elif (category or "") == "FontAttribute":
|
||||
charshape = root.xpath(xpath)
|
||||
if not charshape:
|
||||
charshape = None
|
||||
user_answer = None
|
||||
else:
|
||||
font_attribute = charshape[0].find(right_answer)
|
||||
if font_attribute is not None:
|
||||
user_answer = font_attribute.tag
|
||||
else:
|
||||
user_answer = None
|
||||
# 하이퍼링크 처리
|
||||
hyperlink_ptag = criterion.get('hyperlink_ptag', None)
|
||||
has_ptag = root.xpath(hyperlink_ptag) if hyperlink_ptag else False
|
||||
|
||||
# hyperlink가 아닌 경우(일반적인 텍스트 일 경우)
|
||||
if not has_ptag:
|
||||
charshape = root.xpath(xpath)
|
||||
if not charshape:
|
||||
charshape = None
|
||||
user_answer = None
|
||||
else:
|
||||
font_attribute = charshape[0].find(right_answer)
|
||||
if font_attribute is not None:
|
||||
user_answer = font_attribute.tag
|
||||
else:
|
||||
user_answer = None
|
||||
|
||||
self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal")
|
||||
|
||||
# 하이퍼링크인 경우
|
||||
elif has_ptag:
|
||||
hyperlink_text = search_value.replace(" ", "")
|
||||
|
||||
p_elements = has_ptag
|
||||
|
||||
for p in p_elements:
|
||||
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():
|
||||
# 시작 지점 확인
|
||||
if elem.tag == "FIELDBEGIN":
|
||||
inside_field = True
|
||||
elif elem.tag == "FIELDEND":
|
||||
inside_field = False
|
||||
elif inside_field and elem.tag == "TEXT":
|
||||
charshape = elem.get("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")
|
||||
|
||||
|
||||
|
||||
self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal")
|
||||
|
||||
# 특수문자 갯수 채점
|
||||
elif (category or "") == "SpecialChar":
|
||||
|
||||
@@ -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":"//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"}]
|
||||
[{"kind":2,"language":"xpath","value":"//a:t[text()='클라우드 보안투자']/ancestor::a:r//a:ea/@typeface"}]
|
||||
Binary file not shown.
12
오류및문제점.md
Normal file
12
오류및문제점.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# 오류 및 문제점
|
||||
|
||||
## 1. 원인 파악이나 해결이 어려운 경우
|
||||
|
||||
### 한글문서(.hwpx)에 수험자가 차트 텍스트 속성을 변경해서 저장했지만 차트 xml파일에 옵션이 적용되지 않는 경우가 있음
|
||||
|
||||
1. 정상적으로 텍스트 속성이 적용되는 수험자의 차트를 복사
|
||||
2. 텍스트 속성이 적용되지 않는 수험자의 한글 파일에 차트를 붙여넣을 경우
|
||||
3. 정상적으로 XML파일에 텍스트 속성이 적용
|
||||
|
||||
- 이로 미루어 볼 때, 차트객체의 문제일 것으로 판단되지만 해결 방안은 없음
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user