diff --git a/250901_DIW_2508D_TEST.xlsx b/250901_DIW_2508D_TEST.xlsx
new file mode 100644
index 0000000..2d4a373
Binary files /dev/null and b/250901_DIW_2508D_TEST.xlsx differ
diff --git a/250902_DIW_2508C_TEST.xlsx b/250902_DIW_2508C_TEST.xlsx
new file mode 100644
index 0000000..4301f78
Binary files /dev/null and b/250902_DIW_2508C_TEST.xlsx differ
diff --git a/250902_DIW_2508D_TEST.xlsx b/250902_DIW_2508D_TEST.xlsx
new file mode 100644
index 0000000..5c837fd
Binary files /dev/null and b/250902_DIW_2508D_TEST.xlsx differ
diff --git a/DIW_2508A.json b/DIW_2508A.json
index aee84eb..9ea62c4 100644
--- a/DIW_2508A.json
+++ b/DIW_2508A.json
@@ -255,27 +255,27 @@
"item": "문구 (시니어클럽)/③ 정렬 (가운데 정렬)"
},
"25": {
- "path": "//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
+ "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
"searchValue": "DIAT",
"value": "굴림",
"points": 1,
- "category": "FontName",
+ "category": "FontName.Header",
"item": "문구 (DIAT)/① 글꼴 (굴림)"
},
"26": {
- "path": "//CHARSHAPE[@Id=//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
+ "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
"searchValue": "DIAT",
"value": "900",
"points": 1,
- "category": "OneAnswer",
+ "category": "OneAnswer.Header",
"item": "문구 (DIAT)/② 크기 (9pt)"
},
"27": {
- "path": "//PARASHAPE[@Id=//SECTION[1]//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align",
+ "path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align",
"searchValue": "DIAT",
"value": "Right",
"points": 1,
- "category": "OneAnswer",
+ "category": "OneAnswer.Header",
"item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)"
},
"28": {
@@ -436,7 +436,7 @@
"item": "문구 (노인일자리)/⑩ 정렬 (가운데 정렬)"
},
"14": {
- "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG']",
+ "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG' or @Format='JPEG']",
"value": true,
"points": 2,
"category": "Boolean",
@@ -444,28 +444,28 @@
"desc": "첨부 이미지 파일명 손상으로 정상적인 채점이 불가한 경우가 발견되어서 이미지 첨부 여부로 채점 방식 변경 (7/3)"
},
"15": {
- "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/SIZE/@Width",
+ "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']/@BinData]]/SHAPEOBJECT/SIZE/@Height",
+ "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']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@HorzOffset",
+ "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']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@VertOffset",
+ "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",
diff --git a/DIW_2508B.json b/DIW_2508B.json
index 45dde3b..bb67be2 100644
--- a/DIW_2508B.json
+++ b/DIW_2508B.json
@@ -255,27 +255,27 @@
"item": "문구 (기능경진대회운영위원회)/③ 정렬 (가운데 정렬)"
},
"25": {
- "path": "//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
+ "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
"searchValue": "DIAT",
"value": "굴림",
"points": 1,
- "category": "FontName",
+ "category": "FontName.Header",
"item": "문구 (DIAT)/① 글꼴 (굴림)"
},
"26": {
- "path": "//CHARSHAPE[@Id=//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
+ "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
"searchValue": "DIAT",
"value": "900",
"points": 1,
- "category": "OneAnswer",
+ "category": "OneAnswer.Header",
"item": "문구 (DIAT)/② 크기 (9pt)"
},
"27": {
- "path": "//PARASHAPE[@Id=//SECTION[1]//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align",
+ "path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align",
"searchValue": "DIAT",
"value": "Right",
"points": 1,
- "category": "OneAnswer",
+ "category": "OneAnswer.Header",
"item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)"
},
"28": {
@@ -436,7 +436,7 @@
"item": "문구 (기능경진대회)/⑩ 정렬 (가운데 정렬)"
},
"14": {
- "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG']",
+ "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG' or @Format='JPEG']",
"value": true,
"points": 2,
"category": "Boolean",
@@ -444,28 +444,28 @@
"desc": "첨부 이미지 파일명 손상으로 정상적인 채점이 불가한 경우가 발견되어서 이미지 첨부 여부로 채점 방식 변경 (7/3)"
},
"15": {
- "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/SIZE/@Width",
+ "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']/@BinData]]/SHAPEOBJECT/SIZE/@Height",
+ "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']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@HorzOffset",
+ "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']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@VertOffset",
+ "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",
diff --git a/DIW_2508C.json b/DIW_2508C.json
index bc8af8c..3df41c9 100644
--- a/DIW_2508C.json
+++ b/DIW_2508C.json
@@ -255,27 +255,28 @@
"item": "문구 (밝은미소구강센터)/③ 정렬 (가운데 정렬)"
},
"25": {
- "path": "//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
+ "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
+ "page": 1,
"searchValue": "DIAT",
"value": "궁서",
"points": 1,
- "category": "FontName",
+ "category": "FontName.Header",
"item": "문구 (DIAT)/① 글꼴 (궁서)"
},
"26": {
- "path": "//CHARSHAPE[@Id=//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
+ "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
"searchValue": "DIAT",
"value": "900",
"points": 1,
- "category": "OneAnswer",
+ "category": "OneAnswer.Header",
"item": "문구 (DIAT)/② 크기 (9pt)"
},
"27": {
- "path": "//PARASHAPE[@Id=//SECTION[1]//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align",
+ "path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align",
"searchValue": "DIAT",
"value": "Right",
"points": 1,
- "category": "OneAnswer",
+ "category": "OneAnswer.Header",
"item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)"
},
"28": {
@@ -436,7 +437,7 @@
"item": "문구 (구강건강관리)/⑩ 정렬 (가운데 정렬)"
},
"14": {
- "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG']",
+ "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG' or @Format='JPEG']",
"value": true,
"points": 2,
"category": "Boolean",
@@ -444,28 +445,28 @@
"desc": "첨부 이미지 파일명 손상으로 정상적인 채점이 불가한 경우가 발견되어서 이미지 첨부 여부로 채점 방식 변경 (7/3)"
},
"15": {
- "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/SIZE/@Width",
+ "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG']/@BinData]]/SHAPEOBJECT/SIZE/@Width",
"value": "80",
"points": 2,
"category": "mmSize",
"item": "② 크기-너비 (80 mm)"
},
"16": {
- "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/SIZE/@Height",
+ "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']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@HorzOffset",
+ "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']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@VertOffset",
+ "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",
diff --git a/DIW_2508D.json b/DIW_2508D.json
index 50150c5..684479e 100644
--- a/DIW_2508D.json
+++ b/DIW_2508D.json
@@ -255,27 +255,27 @@
"item": "문구 (중앙문화지역센터)/③ 정렬 (가운데 정렬)"
},
"25": {
- "path": "//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
+ "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
"searchValue": "DIAT",
"value": "궁서",
"points": 1,
- "category": "FontName",
+ "category": "FontName.Header",
"item": "문구 (DIAT)/① 글꼴 (궁서)"
},
"26": {
- "path": "//CHARSHAPE[@Id=//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
+ "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
"searchValue": "DIAT",
"value": "900",
"points": 1,
- "category": "OneAnswer",
+ "category": "OneAnswer.Header",
"item": "문구 (DIAT)/② 크기 (9pt)"
},
"27": {
- "path": "//PARASHAPE[@Id=//SECTION[1]//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align",
+ "path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align",
"searchValue": "DIAT",
"value": "Right",
"points": 1,
- "category": "OneAnswer",
+ "category": "OneAnswer.Header",
"item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)"
},
"28": {
@@ -436,7 +436,7 @@
"item": "문구 (매력적인 강원도)/⑩ 정렬 (가운데 정렬)"
},
"14": {
- "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG']",
+ "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG' or @Format='JPEG']",
"value": true,
"points": 2,
"category": "Boolean",
@@ -444,28 +444,28 @@
"desc": "첨부 이미지 파일명 손상으로 정상적인 채점이 불가한 경우가 발견되어서 이미지 첨부 여부로 채점 방식 변경 (7/3)"
},
"15": {
- "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/SIZE/@Width",
+ "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']/@BinData]]/SHAPEOBJECT/SIZE/@Height",
+ "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']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@HorzOffset",
+ "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']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@VertOffset",
+ "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",
diff --git a/diwScoring2.py b/diwScoring2.py
index ceb2e6e..56381f1 100644
--- a/diwScoring2.py
+++ b/diwScoring2.py
@@ -218,6 +218,7 @@ class XMLScorer:
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가 있는 경우
@@ -247,683 +248,724 @@ class XMLScorer:
'points': 0, # 점수
}
- 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)),
+ 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)),
}
-
- 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]
+ right_answer = {
+ k: self.convert_mm_to_pt(v)
+ for k, v in right_answer.items()
}
- # 정답과 수험자 답안 비교
- 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 "") == "OneAnswer":
- elif (category or "") in ["OneAnswer", "ChartOneAnswer"]:
- items = root.xpath(xpath) if xpath else []
- items2 = root.xpath(xpath2) if xpath2 else []
-
- # 차트 XML에서 정답을 찾는 경우
- # 차트 종류가
- # 세로막대형이면 x축이 카테고리(catAx) y축이 값(valAx)
- # 가로막대형이면 x축이 값(valAx) y축이 카테고리(catAx)
- if category == "ChartOneAnswer":
- # 하드코딩이라 [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":
- line_shapes = root.xpath(xpath) if xpath else []
-
- user_answer = {
- 'Style': None,
- 'Width': None
- }
-
- 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":
- items = root.xpath(xpath)
- # 오차범위 설정
- # 한글 프로그램 내부에서 드물게 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)
+ 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
-
- 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":
- items = root.xpath(xpath) if xpath else []
- items2 = root.xpath(xpath2) if xpath2 else []
-
- 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 (category or "") in ["FontName", "TableFontName"]:
- charshape_list = root.xpath(xpath)
-
- # 문자속성이 없는 경우
- if not charshape_list:
- user_answer = ""
- self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal")
- else:
- require_all_match = (category == "TableFontName")
- any_match = False
+ # 1, 2페이지 모두 정답이어야 함
+ elif (category or "") == "PageNumber":
+ items = root.xpath(xpath) if xpath else []
+
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:
+ for item in chain(items):
+ user_answer = item
+ if right_answer != user_answer:
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
+ break
- self.evaluate_answer(scoring, user_answer, right_answer, points, method="equal")
+ 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:
+ def has_elements(ptags, xpath):
+ for p in ptags:
+ charshape_list = p.xpath(xpath) if xpath else []
+ if charshape_list:
+ return True
+ return False
+
+ 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
+
+ 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":
+ line_shapes = root.xpath(xpath) if xpath else []
+
+ user_answer = {
+ 'Style': None,
+ 'Width': None
+ }
+
+ 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":
+ items = root.xpath(xpath)
+ # 오차범위 설정
+ # 한글 프로그램 내부에서 드물게 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 hyperlink_ptag and search_in_hyperlink:
- else:
- p_elements = hyperlink_ptag
+
+ elif (category or "") == "ParaShape":
+ items = root.xpath(xpath)
- 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]
+ for item in items:
+ user_answer = {
+ 'Left': float(item.get('Left', 0)) / 200,
+ 'Indent': float(item.get('Indent', 0)) / -200,
+ }
- # 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")
+
+ 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
- # P태그들 중 하나라도 다단이 존재할 경우 정답처리
+ 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":
+ items = root.xpath(xpath) if xpath else []
+ items2 = root.xpath(xpath2) if xpath2 else []
+
+ 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 "") == "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)
+ # 문단 첫글자 장식 채점
+ 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 matched:
- score += score_per_pair
+ if scoring['points'] > 0:
+ break
+
+ # 폰트명
+ elif "FontName" in (category or ""):
+ # 'DIAT' 머릿말 문항 1,2페이지 둘 중 하나라도 없으면 0점 처리
+ if "Header" in category:
+ def has_charshape(ptags, xpath):
+ for p in ptags:
+ charshape_list = p.xpath(xpath) if xpath else []
+ if charshape_list:
+ return True
+ return False
+
+ page1_ptags = pages.get('Page_1', [])
+ page2_ptags = pages.get('Page_2', [])
+ header_xpath = "//HEADER//P"
+ has_page1_element = has_charshape(page1_ptags, header_xpath)
+ has_page2_element = has_charshape(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
+
+ charshape_list = root.xpath(xpath)
- # 최대 점수 초과 방지
- 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]
+ # 문자속성이 없는 경우
+ 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를 기억
- # xpath를 사용하여 차트 요소가 있는지 확인
- user_answer = bool(chart_tree.xpath(chart_xpath, namespaces=namespaces))
- self.evaluate_answer(scoring, user_answer, right_answer, points)
-
- # 문항 채점 결과를 리스트에 입력
- onePersonResult['score_results'].append(scoring)
- print(f'scoring: {scoring}')
+ 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,
@@ -1278,13 +1320,13 @@ def main():
# 채점하고자 하는 유형은 주석 해제
exam_types = [
# 'A',
- 'B',
+ # 'B',
# 'C',
- # 'D',
+ 'D',
]
- test_mode = False
- # test_mode = True #/TEST 폴더 채점시
+ # test_mode = False
+ test_mode = True #/TEST 폴더 채점시
output_excel_paths = []
for exam_type in exam_types:
diff --git a/zzz.xbook b/zzz.xbook
index 3751ad3..0b62787 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":"//CHAR[contains(text(),'각도')][contains(text(),'角度')]角度"},{"kind":2,"language":"xpath","value":"//CHAR[contains(text(),'예방')][contains(text(),'豫防')]"},{"kind":2,"language":"xpath","value":"//CHAR[contains(text(),'예방')]"},{"kind":2,"language":"xpath","value":"//c:majorGridlines"},{"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":"//CHAR[contains(string(.), '※')]/descendant-or-self::text()"},{"kind":2,"language":"xpath","value":"//P[@ParaShape=\"17\"]/TEXT[@CharShape='7']//CHAR[string(.)]"},{"kind":2,"language":"xpath","value":"//CHAR[contains(string(.), '기타')]/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":"//RECTANGLE//CHAR[text()='구강건강관거리']/ancestor::RECTANGLE/SHAPEOBJECT/SIZE/@Width"},{"kind":2,"language":"xpath","value":"//CHAR[contains(text(),'예방')][contains(text(),'豫防')]"},{"kind":2,"language":"xpath","value":"//TEXT[CHAR[text()='DIAT']]"},{"kind":2,"language":"xpath","value":"//HEADER//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":"//CHAR[contains(string(.), '※')]/descendant-or-self::text()"},{"kind":2,"language":"xpath","value":"//P[@ParaShape=\"17\"]/TEXT[@CharShape='7']//CHAR[string(.)]"},{"kind":2,"language":"xpath","value":"//CHAR[contains(string(.), '기타')]/text()"}]
\ No newline at end of file
diff --git a/회차별채점자료/2508/DIW_2508A.json b/회차별채점자료/2508/DIW_2508A.json
index 59679dc..9ea62c4 100644
--- a/회차별채점자료/2508/DIW_2508A.json
+++ b/회차별채점자료/2508/DIW_2508A.json
@@ -255,27 +255,27 @@
"item": "문구 (시니어클럽)/③ 정렬 (가운데 정렬)"
},
"25": {
- "path": "//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
+ "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
"searchValue": "DIAT",
"value": "굴림",
"points": 1,
- "category": "FontName",
+ "category": "FontName.Header",
"item": "문구 (DIAT)/① 글꼴 (굴림)"
},
"26": {
- "path": "//CHARSHAPE[@Id=//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
+ "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
"searchValue": "DIAT",
"value": "900",
"points": 1,
- "category": "OneAnswer",
+ "category": "OneAnswer.Header",
"item": "문구 (DIAT)/② 크기 (9pt)"
},
"27": {
- "path": "//PARASHAPE[@Id=//SECTION[1]//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align",
+ "path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align",
"searchValue": "DIAT",
"value": "Right",
"points": 1,
- "category": "OneAnswer",
+ "category": "OneAnswer.Header",
"item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)"
},
"28": {
@@ -436,7 +436,7 @@
"item": "문구 (노인일자리)/⑩ 정렬 (가운데 정렬)"
},
"14": {
- "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG']",
+ "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG' or @Format='JPEG']",
"value": true,
"points": 2,
"category": "Boolean",
@@ -444,28 +444,28 @@
"desc": "첨부 이미지 파일명 손상으로 정상적인 채점이 불가한 경우가 발견되어서 이미지 첨부 여부로 채점 방식 변경 (7/3)"
},
"15": {
- "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/SIZE/@Width",
+ "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']/@BinData]]/SHAPEOBJECT/SIZE/@Height",
+ "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']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@HorzOffset",
+ "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']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@VertOffset",
+ "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",
@@ -608,10 +608,10 @@
"33": {
"path": "//TEXT[CHAR[contains(text(),'{searchValue}')]]/@CharShape",
"searchValue": "노인일자리 창출 현황(예산:십억원)",
- "value": "맑은 고딕",
+ "value": "굴림체",
"points": 1,
"category": "FontName",
- "item": "제목 문구 (노인일자리 창출 현황(예산:십억원))/① 글씨체 (맑은 고딕)"
+ "item": "제목 문구 (노인일자리 창출 현황(예산:십억원))/① 글씨체 (굴림체)"
},
"34": {
"path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
@@ -672,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": {
diff --git a/회차별채점자료/2508/DIW_2508B.json b/회차별채점자료/2508/DIW_2508B.json
index 45dde3b..bb67be2 100644
--- a/회차별채점자료/2508/DIW_2508B.json
+++ b/회차별채점자료/2508/DIW_2508B.json
@@ -255,27 +255,27 @@
"item": "문구 (기능경진대회운영위원회)/③ 정렬 (가운데 정렬)"
},
"25": {
- "path": "//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
+ "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
"searchValue": "DIAT",
"value": "굴림",
"points": 1,
- "category": "FontName",
+ "category": "FontName.Header",
"item": "문구 (DIAT)/① 글꼴 (굴림)"
},
"26": {
- "path": "//CHARSHAPE[@Id=//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
+ "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
"searchValue": "DIAT",
"value": "900",
"points": 1,
- "category": "OneAnswer",
+ "category": "OneAnswer.Header",
"item": "문구 (DIAT)/② 크기 (9pt)"
},
"27": {
- "path": "//PARASHAPE[@Id=//SECTION[1]//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align",
+ "path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align",
"searchValue": "DIAT",
"value": "Right",
"points": 1,
- "category": "OneAnswer",
+ "category": "OneAnswer.Header",
"item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)"
},
"28": {
@@ -436,7 +436,7 @@
"item": "문구 (기능경진대회)/⑩ 정렬 (가운데 정렬)"
},
"14": {
- "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG']",
+ "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG' or @Format='JPEG']",
"value": true,
"points": 2,
"category": "Boolean",
@@ -444,28 +444,28 @@
"desc": "첨부 이미지 파일명 손상으로 정상적인 채점이 불가한 경우가 발견되어서 이미지 첨부 여부로 채점 방식 변경 (7/3)"
},
"15": {
- "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/SIZE/@Width",
+ "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']/@BinData]]/SHAPEOBJECT/SIZE/@Height",
+ "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']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@HorzOffset",
+ "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']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@VertOffset",
+ "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",
diff --git a/회차별채점자료/2508/DIW_2508C.json b/회차별채점자료/2508/DIW_2508C.json
index bc8af8c..3df41c9 100644
--- a/회차별채점자료/2508/DIW_2508C.json
+++ b/회차별채점자료/2508/DIW_2508C.json
@@ -255,27 +255,28 @@
"item": "문구 (밝은미소구강센터)/③ 정렬 (가운데 정렬)"
},
"25": {
- "path": "//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
+ "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
+ "page": 1,
"searchValue": "DIAT",
"value": "궁서",
"points": 1,
- "category": "FontName",
+ "category": "FontName.Header",
"item": "문구 (DIAT)/① 글꼴 (궁서)"
},
"26": {
- "path": "//CHARSHAPE[@Id=//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
+ "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
"searchValue": "DIAT",
"value": "900",
"points": 1,
- "category": "OneAnswer",
+ "category": "OneAnswer.Header",
"item": "문구 (DIAT)/② 크기 (9pt)"
},
"27": {
- "path": "//PARASHAPE[@Id=//SECTION[1]//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align",
+ "path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align",
"searchValue": "DIAT",
"value": "Right",
"points": 1,
- "category": "OneAnswer",
+ "category": "OneAnswer.Header",
"item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)"
},
"28": {
@@ -436,7 +437,7 @@
"item": "문구 (구강건강관리)/⑩ 정렬 (가운데 정렬)"
},
"14": {
- "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG']",
+ "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG' or @Format='JPEG']",
"value": true,
"points": 2,
"category": "Boolean",
@@ -444,28 +445,28 @@
"desc": "첨부 이미지 파일명 손상으로 정상적인 채점이 불가한 경우가 발견되어서 이미지 첨부 여부로 채점 방식 변경 (7/3)"
},
"15": {
- "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/SIZE/@Width",
+ "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG']/@BinData]]/SHAPEOBJECT/SIZE/@Width",
"value": "80",
"points": 2,
"category": "mmSize",
"item": "② 크기-너비 (80 mm)"
},
"16": {
- "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/SIZE/@Height",
+ "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']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@HorzOffset",
+ "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']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@VertOffset",
+ "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",
diff --git a/회차별채점자료/2508/DIW_2508D.json b/회차별채점자료/2508/DIW_2508D.json
index 50150c5..684479e 100644
--- a/회차별채점자료/2508/DIW_2508D.json
+++ b/회차별채점자료/2508/DIW_2508D.json
@@ -255,27 +255,27 @@
"item": "문구 (중앙문화지역센터)/③ 정렬 (가운데 정렬)"
},
"25": {
- "path": "//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
+ "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
"searchValue": "DIAT",
"value": "궁서",
"points": 1,
- "category": "FontName",
+ "category": "FontName.Header",
"item": "문구 (DIAT)/① 글꼴 (궁서)"
},
"26": {
- "path": "//CHARSHAPE[@Id=//SECTION[1]//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
+ "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]/@Height",
"searchValue": "DIAT",
"value": "900",
"points": 1,
- "category": "OneAnswer",
+ "category": "OneAnswer.Header",
"item": "문구 (DIAT)/② 크기 (9pt)"
},
"27": {
- "path": "//PARASHAPE[@Id=//SECTION[1]//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align",
+ "path": "//PARASHAPE[@Id=//CHAR[text()='{searchValue}']/parent::TEXT/parent::P/@ParaShape]/@Align",
"searchValue": "DIAT",
"value": "Right",
"points": 1,
- "category": "OneAnswer",
+ "category": "OneAnswer.Header",
"item": "문구 (DIAT)/③ 정렬 (오른쪽 정렬)"
},
"28": {
@@ -436,7 +436,7 @@
"item": "문구 (매력적인 강원도)/⑩ 정렬 (가운데 정렬)"
},
"14": {
- "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG']",
+ "path": "//BINITEM[@BinData=//PICTURE/IMAGE/@BinItem][@Format='JPG' or @Format='JPEG']",
"value": true,
"points": 2,
"category": "Boolean",
@@ -444,28 +444,28 @@
"desc": "첨부 이미지 파일명 손상으로 정상적인 채점이 불가한 경우가 발견되어서 이미지 첨부 여부로 채점 방식 변경 (7/3)"
},
"15": {
- "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG']/@BinData]]/SHAPEOBJECT/SIZE/@Width",
+ "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']/@BinData]]/SHAPEOBJECT/SIZE/@Height",
+ "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']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@HorzOffset",
+ "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']/@BinData]]/SHAPEOBJECT/POSITION[not(@TreatAsChar='true') and @HorzRelTo='Page']/@VertOffset",
+ "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",
diff --git a/회차별채점자료/2508/_DIW_2508A.json b/회차별채점자료/2508/_DIW_2508A.json
new file mode 100644
index 0000000..d8f0f4d
--- /dev/null
+++ b/회차별채점자료/2508/_DIW_2508A.json
@@ -0,0 +1,840 @@
+{
+ "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/회차별채점자료/2508/_DIW_2508B.json b/회차별채점자료/2508/_DIW_2508B.json
new file mode 100644
index 0000000..d6109db
--- /dev/null
+++ b/회차별채점자료/2508/_DIW_2508B.json
@@ -0,0 +1,841 @@
+{
+ "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": "84,139,241",
+ "points": 2,
+ "category": "Color",
+ "item": "문구 (기능경진대회참가안내)/② 채우기 : 색상(RGB:84,139,241)"
+ },
+ "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": "2",
+ "value": {
+ "Height": 2800,
+ "Width": 2800
+ },
+ "tolerance": 200,
+ "points": 1,
+ "category": "TwoLineSize",
+ "item": "2/① 모양 (2줄)"
+ },
+ "9": {
+ "path": "//TEXT[CHAR[text()='{searchValue}']]/@CharShape",
+ "searchValue": "2",
+ "value": "맑은 고딕",
+ "points": 1,
+ "category": "FontName",
+ "item": "2/② 글씨체 (맑은 고딕)"
+ },
+ "10": {
+ "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor",
+ "searchValue": "2",
+ "value": "240,223,102",
+ "points": 2,
+ "category": "Color",
+ "item": "2/③ 면색 : 색상(RGB:240,223,102)"
+ },
+ "11": {
+ "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//OUTSIDEMARGIN/@Right",
+ "searchValue": "2",
+ "value": "3.0",
+ "tolerance": 1,
+ "points": 2,
+ "category": "mmSize",
+ "item": "2/④ 본문과의 간격 : 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": "문구 (※ 기타… 이하 문단)/왼쪽여백 (15pt), 내어쓰기 (12pt)",
+ "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": "190",
+ "first_word": "2",
+ "points": 2,
+ "category": "LineSpacing",
+ "item": "문제 1 줄간격 190% 설정",
+ "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": "202,86,167",
+ "points": 2,
+ "category": "Color",
+ "item": "문구 (기능경진대회)/⑤ 채우기 : 색상(RGB:202,86,167)"
+ },
+ "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": "① 파일명 \"그림B.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. 대회목적)/② 크기 (12pt)"
+ },
+ "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": "CircledLatinCapital",
+ "points": 2,
+ "category": "OneAnswer",
+ "item": "문구 (전당)/④ 각주 번호모양",
+ "desc": {
+ "가,나,다": "HangulSyllable",
+ "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",
+ "甲,乙,丙": "DecagonCircleHanja",
+ "+,++,+++": "UserChar",
+ "정답에 맞는 값 value에 입력": ""
+ }
+ },
+ "29": {
+ "path": "boolean(//CHAR[contains(text(),'Interior')])",
+ "ignoreWord": "Interior",
+ "value": true,
+ "points": 3,
+ "category": "Boolean",
+ "item": "Interior/영단어 미입력, 대소문자/오타 시 전체 감점",
+ "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": "144,210,67",
+ "points": 2,
+ "category": "Color",
+ "item": "위쪽 제목 셀/① 색상(RGB:144,210,67)"
+ },
+ "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/회차별채점자료/2508/_DIW_2508C.json b/회차별채점자료/2508/_DIW_2508C.json
new file mode 100644
index 0000000..4be4d45
--- /dev/null
+++ b/회차별채점자료/2508/_DIW_2508C.json
@@ -0,0 +1,840 @@
+{
+ "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": "183,29,167",
+ "points": 2,
+ "category": "Color",
+ "item": "문구 (치아건강특별강연회)/② 채우기 : 색상(RGB:183,29,167)"
+ },
+ "3": {
+ "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Width",
+ "searchValue": "치아건강특별강연회",
+ "value": "125",
+ "tolerance": 1,
+ "points": 2,
+ "category": "mmSize",
+ "item": "문구 (치아건강특별강연회)/③ 크기-너비 (125 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": "149,180,174",
+ "points": 2,
+ "category": "Color",
+ "item": "현/③ 면색 : 색상(RGB:149,180,174)"
+ },
+ "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": "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": "◎",
+ "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": "경복궁역 8번 출구 도보 5분",
+ "value": "ITALIC",
+ "points": 1,
+ "category": "FontAttribute",
+ "item": "문구 (경복궁역 8번 출구 도보 5분)/① ITALIC"
+ },
+ "18": {
+ "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]",
+ "hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]",
+ "searchValue": "경복궁역 8번 출구 도보 5분",
+ "value": "UNDERLINE",
+ "points": 1,
+ "category": "FontAttribute",
+ "item": "문구 (경복궁역 8번 출구 도보 5분)/② UNDERLINE"
+ },
+ "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": "문구 (※ 기타… 이하 문단)/왼쪽여백 (15pt), 내어쓰기 (12pt)",
+ "desc": "내부적으로 내어쓰기는 음수값 / JSON value값은 양수로 입력"
+ },
+ "20": {
+ "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]/@Height",
+ "searchValue": "2025. 8. 23.",
+ "value": "1400",
+ "points": 1,
+ "category": "OneAnswer",
+ "item": "문구 (2025. 8. 23.)/① 크기 (1400)",
+ "desc": "1pt당 100"
+ },
+ "21": {
+ "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/@ParaShape]/@Align",
+ "searchValue": "2025. 8. 23.",
+ "value": "Center",
+ "points": 1,
+ "category": "OneAnswer",
+ "item": "문구 (2025. 8. 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": "BottomRight",
+ "points": 2,
+ "category": "PageNumber",
+ "item": "오른쪽 아래",
+ "desc": "1, 2페이지 모두 정답이어야 점수 부여",
+ "desc2": {
+ "가운데 아래": "BottomCenter",
+ "오른쪽 아래": "BottomRight"
+ }
+ },
+ "30": {
+ "path": "//PARASHAPE[@Id='{parashape_id}']/PARAMARGIN/@LineSpacing",
+ "value": "200",
+ "first_word": "현",
+ "points": 2,
+ "category": "LineSpacing",
+ "item": "문제 1 줄간격 200% 설정",
+ "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": "20",
+ "points": 2,
+ "category": "OneAnswer",
+ "item": "문구 (구강건강관리)/④ 글상자 모서리 (반원)",
+ "desc": "모서리 비율 반원:50 / 둥근모양:20"
+ },
+ "8": {
+ "path": "//RECTANGLE[.//CHAR[text()='{searchValue}']]//WINDOWBRUSH/@FaceColor",
+ "searchValue": "구강건강관리",
+ "value": "187,140,209",
+ "points": 2,
+ "category": "Color",
+ "item": "문구 (구강건강관리)/⑤ 채우기 : 색상(RGB:187,140,209)"
+ },
+ "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": "2300",
+ "points": 1,
+ "category": "OneAnswer",
+ "item": "문구 (구강건강관리)/⑨ 글씨크기 (2300)",
+ "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": "① 파일명 \"그림C.jpg\" 삽입",
+ "desc": "첨부 이미지 파일명 손상으로 정상적인 채점이 불가한 경우가 발견되어서 이미지 첨부 여부로 채점 방식 변경 (7/3)"
+ },
+ "15": {
+ "path": "//PICTURE[./IMAGE[@BinItem=//BINITEM[@Format='JPG' or @Format='JPEG']/@BinData]]/SHAPEOBJECT/SIZE/@Width",
+ "value": "80",
+ "points": 2,
+ "category": "mmSize",
+ "item": "② 크기-너비 (80 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. 구강건강관리)/② 크기 (12pt)"
+ },
+ "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": "DecagonCircle",
+ "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(),'Fluoride')])",
+ "ignoreWord": "Fluoride",
+ "value": true,
+ "points": 3,
+ "category": "Boolean",
+ "item": "Fluoride/영단어 미입력, 대소문자/오타 시 전체 감점",
+ "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": "문구 (…칫솔질은 창아와 잇몸 경계에 45도…)>'창' → '치' 글자바꿈"
+ },
+ "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": "210,191,27",
+ "points": 2,
+ "category": "Color",
+ "item": "위쪽 제목 셀/① 색상(RGB:210,191,27)"
+ },
+ "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": "AVG",
+ "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/회차별채점자료/2508/_DIW_2508D.json b/회차별채점자료/2508/_DIW_2508D.json
new file mode 100644
index 0000000..2c6a978
--- /dev/null
+++ b/회차별채점자료/2508/_DIW_2508D.json
@@ -0,0 +1,841 @@
+{
+ "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": "230,47,199",
+ "points": 2,
+ "category": "Color",
+ "item": "문구 (강원도지역문화체험안내)/② 채우기 : 색상(RGB:230,47,199)"
+ },
+ "3": {
+ "path": "//TEXTART[@Text='{searchValue}']/SHAPEOBJECT/SIZE/@Width",
+ "searchValue": "강원도지역문화체험안내",
+ "value": "125",
+ "tolerance": 1,
+ "points": 2,
+ "category": "mmSize",
+ "item": "문구 (강원도지역문화체험안내)/③ 크기-너비 (125 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": "231,215,17",
+ "points": 2,
+ "category": "Color",
+ "item": "자/③ 면색 : 색상(RGB:231,215,17)"
+ },
+ "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": "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": "◀",
+ "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": "ITALIC",
+ "points": 1,
+ "category": "FontAttribute",
+ "item": "문구 (강원도 춘천시 중앙문화지역센터 및 인근 공원)/① ITALIC"
+ },
+ "18": {
+ "path": "//CHARSHAPE[@Id=//TEXT[CHAR[text()='{searchValue}']]/@CharShape]",
+ "hyperlink_ptag": "//P[.//FIELDBEGIN[@Type='Hyperlink']]",
+ "searchValue": "강원도 춘천시 중앙문화지역센터 및 인근 공원",
+ "value": "UNDERLINE",
+ "points": 1,
+ "category": "FontAttribute",
+ "item": "문구 (강원도 춘천시 중앙문화지역센터 및 인근 공원)/② UNDERLINE"
+ },
+ "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": "문구 (※ 기타… 이하 문단)/왼쪽여백 (15pt), 내어쓰기 (12pt)",
+ "desc": "내부적으로 내어쓰기는 음수값 / JSON value값은 양수로 입력"
+ },
+ "20": {
+ "path": "//CHARSHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/parent::TEXT/@CharShape]/@Height",
+ "searchValue": "2025. 8. 23.",
+ "value": "1400",
+ "points": 1,
+ "category": "OneAnswer",
+ "item": "문구 (2025. 8. 23.)/① 크기 (1400)",
+ "desc": "1pt당 100"
+ },
+ "21": {
+ "path": "//PARASHAPE[@Id=//CHAR[contains(text(),'{searchValue}')]/ancestor::P/@ParaShape]/@Align",
+ "searchValue": "2025. 8. 23.",
+ "value": "Center",
+ "points": 1,
+ "category": "OneAnswer",
+ "item": "문구 (2025. 8. 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": "2500",
+ "points": 1,
+ "category": "OneAnswer",
+ "item": "문구 (중앙문화지역센터)/② 크기 (2500)"
+ },
+ "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": "Digit",
+ "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": "200",
+ "first_word": "자",
+ "points": 2,
+ "category": "LineSpacing",
+ "item": "문제 1 줄간격 200% 설정",
+ "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": "68",
+ "points": 2,
+ "category": "mmSize",
+ "item": "문구 (매력적인 강원도)/① 크기-너비 (68 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": "130,159,32",
+ "points": 2,
+ "category": "Color",
+ "item": "문구 (매력적인 강원도)/⑤ 채우기 : 색상(RGB:130,159,32)"
+ },
+ "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": "2300",
+ "points": 1,
+ "category": "OneAnswer",
+ "item": "문구 (매력적인 강원도)/⑨ 글씨크기 (2300)",
+ "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": "① 파일명 \"그림D.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. 지역적 특성)/② 크기 (12pt)"
+ },
+ "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": "Digit",
+ "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",
+ "ⓐ,ⓑ,ⓒ": "CircledLatinSmall",
+ "i,ii,iii": "RomanSmall",
+ "I,II,III": "RomanCapital",
+ "甲,乙,丙": "DecagonCircleHanja",
+ "+,++,+++": "UserChar",
+ "정답에 맞는 값 value에 입력": ""
+ }
+ },
+ "29": {
+ "path": "boolean(//CHAR[contains(text(),'Tourism')])",
+ "ignoreWord": "Tourism",
+ "value": true,
+ "points": 3,
+ "category": "Boolean",
+ "item": "Tourism/영단어 미입력, 대소문자/오타 시 전체 감점",
+ "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": "87,215,182",
+ "points": 2,
+ "category": "Color",
+ "item": "위쪽 제목 셀/① 색상(RGB:87,215,182)"
+ },
+ "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": "AVG",
+ "value": true,
+ "points": 4,
+ "category": "Boolean",
+ "item": "블록 계산식/AVG",
+ "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"
+ }
+ }
+}