init
This commit is contained in:
12
hwp_conversion.log
Normal file
12
hwp_conversion.log
Normal file
@@ -0,0 +1,12 @@
|
||||
2024-11-06 15:06:07,560 - INFO - 변환 성공: 1.hwp -> 1.xml
|
||||
2024-11-06 15:06:07,857 - INFO - 변환 성공: 2.hwp -> 2.xml
|
||||
2024-11-06 15:28:35,640 - INFO - 변환 성공: 1.hwp -> 1.xml
|
||||
2024-11-06 15:28:35,654 - INFO - BINDATA 섹션 제거 완료: C:\Users\gzero-ser7-win11\Documents\hwpTest\Output\1.xml
|
||||
2024-11-06 15:28:35,933 - INFO - 변환 성공: 2.hwp -> 2.xml
|
||||
2024-11-06 15:28:35,948 - INFO - BINDATA 섹션 제거 완료: C:\Users\gzero-ser7-win11\Documents\hwpTest\Output\2.xml
|
||||
2024-11-06 15:31:54,423 - INFO - 변환 성공: 1.hwp -> 1.xml
|
||||
2024-11-06 15:31:54,437 - INFO - BINDATASTORAGE 섹션 제거 완료: C:\Users\gzero-ser7-win11\Documents\hwpTest\Output\1.xml
|
||||
2024-11-06 15:31:54,697 - INFO - 변환 성공: 2.hwp -> 2.xml
|
||||
2024-11-06 15:31:54,711 - INFO - BINDATASTORAGE 섹션 제거 완료: C:\Users\gzero-ser7-win11\Documents\hwpTest\Output\2.xml
|
||||
2024-11-06 15:34:34,911 - INFO - 변환 성공: 1.hwp -> 1.xml
|
||||
2024-11-06 15:34:35,179 - INFO - 변환 성공: 2.hwp -> 2.xml
|
||||
227
score.py
Normal file
227
score.py
Normal file
@@ -0,0 +1,227 @@
|
||||
import json
|
||||
import xml.etree.ElementTree as ET
|
||||
import os
|
||||
from pathlib import Path
|
||||
import pandas as pd
|
||||
from datetime import datetime
|
||||
|
||||
class XMLScorer:
|
||||
def __init__(self, scoring_criteria_path):
|
||||
"""
|
||||
채점 기준표 JSON 파일을 로드하여 초기화합니다.
|
||||
|
||||
Args:
|
||||
scoring_criteria_path (str): 채점 기준표 JSON 파일 경로
|
||||
"""
|
||||
self.scoring_criteria = self._load_scoring_criteria(scoring_criteria_path)
|
||||
|
||||
def _load_scoring_criteria(self, file_path):
|
||||
"""
|
||||
JSON 채점 기준표를 로드합니다.
|
||||
|
||||
Args:
|
||||
file_path (str): JSON 파일 경로
|
||||
|
||||
Returns:
|
||||
dict: 채점 기준표 데이터
|
||||
"""
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
|
||||
def _find_element_value(self, root, element_name, attribute_name):
|
||||
"""
|
||||
XML에서 특정 요소와 속성값을 찾습니다.
|
||||
|
||||
Args:
|
||||
root (Element): XML 루트 요소
|
||||
element_name (str): 찾을 요소 이름
|
||||
attribute_name (str): 찾을 속성 이름
|
||||
|
||||
Returns:
|
||||
str: 찾은 속성값 또는 None
|
||||
"""
|
||||
element = root.find(f".//{element_name}")
|
||||
if element is not None:
|
||||
return element.get(attribute_name)
|
||||
return None
|
||||
|
||||
def score_xml_file(self, xml_path):
|
||||
"""
|
||||
단일 XML 파일을 채점합니다.
|
||||
|
||||
Args:
|
||||
xml_path (str): XML 파일 경로
|
||||
|
||||
Returns:
|
||||
dict: 채점 결과
|
||||
"""
|
||||
try:
|
||||
tree = ET.parse(xml_path)
|
||||
root = tree.getroot()
|
||||
|
||||
total_score = 0
|
||||
results = {
|
||||
'filename': os.path.basename(xml_path),
|
||||
'criteria_matches': [],
|
||||
'total_score': 0
|
||||
}
|
||||
|
||||
# 각 채점 기준에 대해 검사
|
||||
for criterion_id, criterion in self.scoring_criteria.items():
|
||||
element_name = criterion['ele']
|
||||
attribute_name = criterion['arg']
|
||||
expected_value = criterion['value']
|
||||
points = criterion['points']
|
||||
|
||||
actual_value = self._find_element_value(root, element_name, attribute_name)
|
||||
|
||||
match = {
|
||||
'criterion': f"{element_name}.{attribute_name}",
|
||||
'expected': expected_value,
|
||||
'actual': actual_value,
|
||||
'points': 0
|
||||
}
|
||||
|
||||
# 값이 일치하면 점수 부여
|
||||
if actual_value == expected_value:
|
||||
total_score += points
|
||||
match['points'] = points
|
||||
|
||||
results['criteria_matches'].append(match)
|
||||
|
||||
results['total_score'] = total_score
|
||||
return results
|
||||
|
||||
except ET.ParseError as e:
|
||||
return {
|
||||
'filename': os.path.basename(xml_path),
|
||||
'error': f"XML 파싱 오류: {str(e)}",
|
||||
'total_score': 0
|
||||
}
|
||||
|
||||
def export_to_excel(self, results, output_path=None):
|
||||
"""
|
||||
채점 결과를 엑셀 파일로 저장합니다.
|
||||
|
||||
Args:
|
||||
results (list): 채점 결과 리스트
|
||||
output_path (str, optional): 출력 파일 경로.
|
||||
None이면 현재 시간으로 파일명 생성
|
||||
|
||||
Returns:
|
||||
str: 저장된 엑셀 파일 경로
|
||||
"""
|
||||
if output_path is None:
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
output_path = f"scoring_results_{timestamp}.xlsx"
|
||||
|
||||
# 요약 시트용 데이터 준비
|
||||
summary_data = []
|
||||
detail_data = []
|
||||
|
||||
for result in results:
|
||||
# 요약 정보
|
||||
summary_row = {
|
||||
'파일명': result['filename'],
|
||||
'총점': result.get('total_score', 0)
|
||||
}
|
||||
if 'error' in result:
|
||||
summary_row['오류'] = result['error']
|
||||
summary_data.append(summary_row)
|
||||
|
||||
# 상세 정보
|
||||
if 'criteria_matches' in result:
|
||||
for match in result['criteria_matches']:
|
||||
detail_row = {
|
||||
'파일명': result['filename'],
|
||||
'채점항목': match['criterion'],
|
||||
'기대값': match['expected'],
|
||||
'실제값': match['actual'],
|
||||
'획득점수': match['points']
|
||||
}
|
||||
detail_data.append(detail_row)
|
||||
|
||||
# DataFrame 생성
|
||||
summary_df = pd.DataFrame(summary_data)
|
||||
detail_df = pd.DataFrame(detail_data)
|
||||
|
||||
# ExcelWriter 객체 생성
|
||||
with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
|
||||
# 요약 시트 작성
|
||||
summary_df.to_excel(writer, sheet_name='채점결과요약', index=False)
|
||||
|
||||
# 상세 시트 작성
|
||||
detail_df.to_excel(writer, sheet_name='채점상세내역', index=False)
|
||||
|
||||
# 열 너비 자동 조정
|
||||
for sheet_name in writer.sheets:
|
||||
worksheet = writer.sheets[sheet_name]
|
||||
for column in worksheet.columns:
|
||||
max_length = 0
|
||||
column = [cell for cell in column]
|
||||
for cell in column:
|
||||
try:
|
||||
if len(str(cell.value)) > max_length:
|
||||
max_length = len(str(cell.value))
|
||||
except:
|
||||
pass
|
||||
adjusted_width = (max_length + 2)
|
||||
worksheet.column_dimensions[column[0].column_letter].width = adjusted_width
|
||||
|
||||
return output_path
|
||||
|
||||
|
||||
def score_directory(self, xml_directory):
|
||||
"""
|
||||
디렉토리 내의 모든 XML 파일을 채점합니다.
|
||||
|
||||
Args:
|
||||
xml_directory (str): XML 파일들이 있는 디렉토리 경로
|
||||
|
||||
Returns:
|
||||
list: 모든 파일의 채점 결과
|
||||
"""
|
||||
results = []
|
||||
xml_files = Path(xml_directory).glob('*.xml')
|
||||
|
||||
for xml_file in xml_files:
|
||||
result = self.score_xml_file(str(xml_file))
|
||||
results.append(result)
|
||||
|
||||
return results
|
||||
|
||||
# 사용 예시
|
||||
def main():
|
||||
# 채점기준표 파일 경로
|
||||
scoring_criteria_path = "scoring_criteria.json"
|
||||
# XML 파일들이 있는 디렉토리 경로
|
||||
xml_directory = r"C:\Users\gzero-ser7-win11\Documents\hwpTest\Output"
|
||||
|
||||
# 채점기 초기화
|
||||
scorer = XMLScorer(scoring_criteria_path)
|
||||
|
||||
# 디렉토리 내 모든 XML 파일 채점
|
||||
results = scorer.score_directory(xml_directory)
|
||||
|
||||
# 결과 출력
|
||||
for result in results:
|
||||
print(f"\n파일: {result['filename']}")
|
||||
if 'error' in result:
|
||||
print(f"오류: {result['error']}")
|
||||
continue
|
||||
|
||||
print(f"총점: {result['total_score']}")
|
||||
print("\n채점 세부사항:")
|
||||
for match in result['criteria_matches']:
|
||||
print(f"기준: {match['criterion']}")
|
||||
print(f"기대값: {match['expected']}")
|
||||
print(f"실제값: {match['actual']}")
|
||||
print(f"획득 점수: {match['points']}")
|
||||
print("---")
|
||||
|
||||
# 결과를 엑셀 파일로 저장
|
||||
excel_path = scorer.export_to_excel(results)
|
||||
print(f"\n채점 결과가 다음 경로에 저장되었습니다: {excel_path}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
20
scoring_criteria.json
Normal file
20
scoring_criteria.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"0": {
|
||||
"ele": "TEXTART",
|
||||
"arg": "Text",
|
||||
"value": "즐거운컬러푸드영양교실",
|
||||
"points": 10
|
||||
},
|
||||
"1": {
|
||||
"ele": "TEXTARTSHAPE",
|
||||
"arg": "FontName",
|
||||
"value": "궁서체",
|
||||
"points": 2
|
||||
},
|
||||
"2": {
|
||||
"ele": "TEXTARTSHAPE",
|
||||
"arg": "Align",
|
||||
"value": "Center",
|
||||
"points": 2
|
||||
}
|
||||
}
|
||||
3
scoring_results/scoring_results_20241106_224444.csv
Normal file
3
scoring_results/scoring_results_20241106_224444.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
filename,total_score,textart_score,textartshape_score,status
|
||||
1.xml,0,0,0,error: 'textart_values'
|
||||
2.xml,0,0,0,error: 'textart_values'
|
||||
|
22
scoring_results/scoring_summary_20241106_224444.json
Normal file
22
scoring_results/scoring_summary_20241106_224444.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"timestamp": "20241106_224444",
|
||||
"total_files": 2,
|
||||
"successful_files": 0,
|
||||
"average_score": 0.0,
|
||||
"results": [
|
||||
{
|
||||
"filename": "1.xml",
|
||||
"total_score": 0,
|
||||
"textart_score": 0,
|
||||
"textartshape_score": 0,
|
||||
"status": "error: 'textart_values'"
|
||||
},
|
||||
{
|
||||
"filename": "2.xml",
|
||||
"total_score": 0,
|
||||
"textart_score": 0,
|
||||
"textartshape_score": 0,
|
||||
"status": "error: 'textart_values'"
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
scoring_results_20241107_170410.xlsx
Normal file
BIN
scoring_results_20241107_170410.xlsx
Normal file
Binary file not shown.
BIN
scoring_results_20241107_170915.xlsx
Normal file
BIN
scoring_results_20241107_170915.xlsx
Normal file
Binary file not shown.
98
test.py
Normal file
98
test.py
Normal file
@@ -0,0 +1,98 @@
|
||||
# from pyhwpx import Hwp # 임포트
|
||||
|
||||
# hwp = Hwp() # 아래아한글 실행(프로그램이 실행되어 있는 경우, 기존 한/글 프로그램에 연결됨)
|
||||
# hwp.insert_text("Hello world!\r\n") # 문자열 삽입
|
||||
# hwp.create_table(5, 5, treat_as_char=True) # 5행5열의 표 삽입(글자처럼 취급)
|
||||
|
||||
# for i in range(25): # 표에 내용 삽입
|
||||
# hwp.insert_text(i)
|
||||
# hwp.TableRightCell()
|
||||
|
||||
# hwp.MoveDown()
|
||||
|
||||
# hwp.insert_picture("https://ultralytics.com/images/zidane.jpg") # 이미지 삽입
|
||||
# hwp.ShapeObjAttachCaption() # 캡션 삽입
|
||||
# hwp.insert_text("Zidane") # 캡션 문자열 입력
|
||||
# hwp.ParagraphShapeAlignCenter() # 캡션 가운데정렬
|
||||
# hwp.SelectAll() # 캡션 전체선택
|
||||
# hwp.set_font(Bold=True, FaceName="돋움", Height=20, TextColor="Red") # 캡션 글자모양 변경
|
||||
# hwp.Cancel() # 선택해제
|
||||
# hwp.Close() # 캡션 편집 종료
|
||||
|
||||
import win32com.client
|
||||
import os
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
def setup_logging():
|
||||
"""로깅 설정"""
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
handlers=[
|
||||
logging.FileHandler('hwp_conversion.log'),
|
||||
logging.StreamHandler()
|
||||
]
|
||||
)
|
||||
|
||||
def convert_hwp_to_xml(input_folder, output_folder):
|
||||
"""
|
||||
지정된 폴더 내의 모든 HWP 파일을 XML로 변환
|
||||
|
||||
Args:
|
||||
input_folder (str): HWP 파일이 있는 폴더 경로
|
||||
output_folder (str): XML 파일을 저장할 폴더 경로
|
||||
"""
|
||||
try:
|
||||
# 한글 애플리케이션 객체 생성
|
||||
hwp = win32com.client.Dispatch("HWPFrame.HwpObject")
|
||||
|
||||
# 자동화 보안 설정
|
||||
hwp.XHwpWindows.Item(0).Visible = False
|
||||
hwp.RegisterModule("FilePathCheckDLL", "FilePathCheckerModule")
|
||||
|
||||
# 출력 폴더가 없으면 생성
|
||||
os.makedirs(output_folder, exist_ok=True)
|
||||
|
||||
# HWP 파일 검색 및 변환
|
||||
input_path = Path(input_folder)
|
||||
for hwp_file in input_path.glob("*.hwp"):
|
||||
try:
|
||||
# 파일 열기
|
||||
hwp.Open(str(hwp_file))
|
||||
|
||||
# XML 파일 경로 설정
|
||||
xml_filename = hwp_file.stem + ".xml"
|
||||
xml_path = os.path.join(output_folder, xml_filename)
|
||||
|
||||
# XML로 저장
|
||||
hwp.SaveAs(xml_path, "HWPML2X")
|
||||
logging.info(f"변환 성공: {hwp_file.name} -> {xml_filename}")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"파일 변환 실패: {hwp_file.name} - {str(e)}")
|
||||
|
||||
finally:
|
||||
# 현재 문서 닫기
|
||||
hwp.Clear(3)
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"프로그램 실행 오류: {str(e)}")
|
||||
|
||||
finally:
|
||||
# 한글 프로그램 종료
|
||||
try:
|
||||
hwp.Quit()
|
||||
except:
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 로깅 설정
|
||||
setup_logging()
|
||||
|
||||
# 변환할 폴더 경로 설정
|
||||
input_folder = r"C:\Users\gzero-ser7-win11\Documents\hwpTest\Input" # HWP 파일이 있는 폴더
|
||||
output_folder = r"C:\Users\gzero-ser7-win11\Documents\hwpTest\Output" # XML 파일을 저장할 폴더
|
||||
|
||||
# 변환 실행
|
||||
convert_hwp_to_xml(input_folder, output_folder)
|
||||
BIN
~$scoring_results_20241107_170915.xlsx
Normal file
BIN
~$scoring_results_20241107_170915.xlsx
Normal file
Binary file not shown.
Reference in New Issue
Block a user