차트 없는 친구들 xml파일 생성안되고 채점 상세 내역에 추가되지 않음음
This commit is contained in:
126
score5.py
126
score5.py
@@ -6,11 +6,9 @@ from lxml import etree as ET
|
||||
import re
|
||||
from difflib import SequenceMatcher
|
||||
import pandas as pd
|
||||
import base64
|
||||
# from xpathSearch import XMLPathHandler
|
||||
|
||||
from binaryToChartxml import binaryToChartxml
|
||||
|
||||
|
||||
class XMLScorer:
|
||||
# 채점 기준 경로 초기화
|
||||
def __init__(self, scoring_criteria_path):
|
||||
@@ -24,31 +22,44 @@ class XMLScorer:
|
||||
|
||||
# XML 파일에서 element의 값을 찾아 반환
|
||||
def query_xml(self, root, *args):
|
||||
first_xpath = args[0]
|
||||
second_xpath = args[1]
|
||||
points = args[2]
|
||||
if args[1] is not None:
|
||||
|
||||
if second_xpath is not None:
|
||||
try:
|
||||
result = root.xpath(args[0])
|
||||
result = root.xpath(first_xpath)
|
||||
if type(result) is list and len(result) == 0:
|
||||
return None
|
||||
elif result < points:
|
||||
result = root.xpath(args[1])
|
||||
result = root.xpath(second_xpath)
|
||||
return result
|
||||
else:
|
||||
return result
|
||||
# result = root.xpath(args[1])
|
||||
# result = root.xpath(second_xpath)
|
||||
# print(f'result : {result}')
|
||||
# return result
|
||||
except ET.XPathEvalError as e:
|
||||
return None
|
||||
else:
|
||||
try:
|
||||
result = root.xpath(args[0])
|
||||
result = root.xpath(first_xpath)
|
||||
if type(result) is list and len(result) == 0:
|
||||
return None
|
||||
|
||||
return result
|
||||
except ET.XPathEvalError as e:
|
||||
return None
|
||||
|
||||
def chart_query_xml(self, tree, xpath, namespaces):
|
||||
try:
|
||||
result = tree.xpath(xpath, namespaces=namespaces)
|
||||
if type(result) is list and len(result) == 0:
|
||||
return None
|
||||
|
||||
return result
|
||||
except ET.XPathEvalError as e:
|
||||
return None
|
||||
|
||||
# 유사한 텍스트 찾기
|
||||
def find_similar_text(self, root, target_text, threshold=0.5):
|
||||
@@ -86,23 +97,49 @@ class XMLScorer:
|
||||
return None
|
||||
|
||||
# 하나의 XML 파일 채점
|
||||
def _score_xml_file(self, xml_path):
|
||||
def _score_xml_file(self, xml_path, chart_xml):
|
||||
try:
|
||||
tree = ET.parse(xml_path)
|
||||
root = tree.getroot()
|
||||
|
||||
# 네임스페이스 정의
|
||||
namespaces = {
|
||||
'a': 'http://schemas.openxmlformats.org/drawingml/2006/main',
|
||||
'c': 'http://schemas.openxmlformats.org/drawingml/2006/chart'
|
||||
}
|
||||
|
||||
if chart_xml is None:
|
||||
chart_tree = ET.fromstring('')
|
||||
else:
|
||||
chart_tree = ET.fromstring(chart_xml)
|
||||
|
||||
total_score = 0
|
||||
partial_score = 0
|
||||
previous_first_digit = None
|
||||
|
||||
# 결과값을 Dictionary로 저장
|
||||
results = {
|
||||
'filename': os.path.basename(xml_path),
|
||||
'score_results': [],
|
||||
'total_score': 0,
|
||||
'partial_scores': []
|
||||
}
|
||||
|
||||
print(f"File name: {results['filename']}")
|
||||
|
||||
for criterion_id, criterion in self.scoring_criteria.items():
|
||||
|
||||
# 키값의 첫 숫자를 확인
|
||||
first_digit = criterion_id.split('-')[0]
|
||||
if (previous_first_digit is not None) and (first_digit != previous_first_digit):
|
||||
results['partial_scores'].append({
|
||||
'section': previous_first_digit,
|
||||
'score': partial_score
|
||||
})
|
||||
partial_score = 0
|
||||
|
||||
previous_first_digit = first_digit
|
||||
|
||||
xpath = criterion['path']
|
||||
xpath2 = criterion['path2']
|
||||
search_value = criterion['searchValue']
|
||||
@@ -120,8 +157,11 @@ class XMLScorer:
|
||||
else:
|
||||
xpath = xpath.replace('{searchValue}', simliar_text)
|
||||
|
||||
if "chart_xml" in category:
|
||||
result = self.chart_query_xml(chart_tree, xpath, namespaces)
|
||||
# xpath로 실제 작성 답안 찾기
|
||||
result = self.query_xml(root, xpath, xpath2, points)
|
||||
else:
|
||||
result = self.query_xml(root, xpath, xpath2, points)
|
||||
|
||||
# [ boolean 타입 ]
|
||||
# 1. 이텔릭체, 굵게, 밑줄 등 효과가 적용 여부에 따라
|
||||
@@ -173,10 +213,18 @@ class XMLScorer:
|
||||
# 점수 차감 이유 작성 (개발중)
|
||||
results['score_results'].append(scoring)
|
||||
total_score += scoring['points']
|
||||
partial_score += scoring['points']
|
||||
|
||||
print(f'scoring: {scoring}')
|
||||
|
||||
results['total_score'] = total_score
|
||||
|
||||
if previous_first_digit is not None:
|
||||
results['partial_scores'].append({
|
||||
'section': previous_first_digit,
|
||||
'score': partial_score
|
||||
})
|
||||
|
||||
return results
|
||||
|
||||
except ET.ParseError as e:
|
||||
@@ -185,8 +233,50 @@ class XMLScorer:
|
||||
'error': f"XML 파싱 오류: {str(e)}",
|
||||
'total_score': 0
|
||||
}
|
||||
# def binary_to_chartxml(self, xml_path):
|
||||
|
||||
def binary_to_chartxml(self, xml_path):
|
||||
try:
|
||||
print(f'binary_to_chartxml {xml_path}')
|
||||
tree = ET.parse(xml_path)
|
||||
root = tree.getroot()
|
||||
|
||||
binary_data = root.xpath('//BINDATA[@Id=//BINITEM[@Format="OLE"]/@BinData]/text()')
|
||||
if not binary_data:
|
||||
raise ValueError("No binary data found in the XML.")
|
||||
binary_data = binary_data[0].encode('utf-8')
|
||||
|
||||
# <BINDATA ...> 태그와 그 내부 내용을 삭제합니다.
|
||||
encoded_data = re.sub(b'<BINDATA.*?>', b'', binary_data)
|
||||
encoded_data = encoded_data.replace(b'</BINDATA>', b'')
|
||||
encoded_data = encoded_data.replace(b'\r\n', b'')
|
||||
|
||||
# base64 디코딩을 수행합니다.
|
||||
decoded_data = base64.b64decode(encoded_data+b'==')
|
||||
|
||||
# 디코딩된 데이터 내용 중 xml 형식만 추출할 때 <c:chartSpace>, </c:chartSpace> 사이의 데이터만 추출.
|
||||
start = decoded_data.find(b'<?xml')
|
||||
print(start)
|
||||
end = decoded_data.find(b'</c:chartSpace>')
|
||||
print(end)
|
||||
xml_data = decoded_data[start:end+len(b'</c:chartSpace>')]
|
||||
|
||||
# 디코딩된 데이터를 파일로 저장합니다.
|
||||
base_filename = os.path.splitext(xml_path)[0]
|
||||
new_filename = f'{base_filename}.xml'
|
||||
with open(new_filename, 'wb') as file:
|
||||
file.write(xml_data)
|
||||
|
||||
return xml_data
|
||||
|
||||
except ET.ParseError as e:
|
||||
print(f"XML 파싱 오류: {str(e)}")
|
||||
except IndexError as e:
|
||||
print(f"IndexError: {str(e)}")
|
||||
except ValueError as e:
|
||||
print(f"ValueError: {str(e)}")
|
||||
except Exception as e:
|
||||
print(f"Unexpected error: {str(e)}")
|
||||
|
||||
# XML 파일 채점
|
||||
def score_directory(self, xml_directory):
|
||||
|
||||
@@ -197,8 +287,8 @@ class XMLScorer:
|
||||
results = []
|
||||
|
||||
for xml_file in xml_files:
|
||||
self.binary_to_chartxml(xml_file)
|
||||
result = self._score_xml_file(xml_file)
|
||||
chart_xml = self.binary_to_chartxml(xml_file)
|
||||
result = self._score_xml_file(xml_file, chart_xml)
|
||||
results.append(result)
|
||||
return results
|
||||
|
||||
@@ -235,11 +325,15 @@ class XMLScorer:
|
||||
if 'score_results' in result:
|
||||
filename = {'파일명': result['filename']}
|
||||
number, name = self.parse_filename(filename)
|
||||
detail_row = {'수험자':f"{number}-{name}"}
|
||||
if (number or name) is None:
|
||||
detail_row = {'채점항목': result['filename'] }
|
||||
else:
|
||||
detail_row = {'채점항목':f"{number}-{name}"}
|
||||
|
||||
for i, scoring in enumerate(result['score_results']):
|
||||
detail_row[f'점수_{i+1}'] = scoring['points']
|
||||
|
||||
# detail_row[scoring['item']] = scoring['points']
|
||||
detail_row[f'{i+1}'] = scoring['points']
|
||||
|
||||
detail_row['총점'] = result.get('total_score', 0)
|
||||
detail_data.append(detail_row)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user