from lxml import etree from difflib import SequenceMatcher import json class XMLPathHandler: def __init__(self, xml_file_path): """ XML 파일을 로드하고 처리하는 핸들러 :param xml_file_path: XML 파일 경로 """ self.tree = etree.parse(xml_file_path) self.root = self.tree.getroot() def similar(self, a, b): """ 두 문자열의 유사도를 계산 :return: 유사도 점수 (0~1) """ return SequenceMatcher(None, a, b).ratio() def find_similar_text(self, search_value, element_name, arg_name, threshold=0.8): """ XML에서 유사한 텍스트를 찾음 :param search_value: 찾고자 하는 텍스트 :param element_name: 검색할 요소 이름 :param arg_name: 검색할 속성 이름 :param threshold: 유사도 임계값 :return: 가장 유사한 텍스트와 점수 """ # 특정 요소의 특정 속성을 가진 모든 요소 검색 xpath = f"//{element_name}[@{arg_name}]" elements = self.root.xpath(xpath) best_match = None best_score = 0 for element in elements: attr_value = element.get(arg_name) if attr_value is not None: score = self.similar(search_value, attr_value) if score > threshold and score > best_score: best_match = attr_value best_score = score return best_match, best_score def build_xpath(self, item): """ 설정 항목을 기반으로 XPath 생성 :param item: 설정 항목 :return: 구성된 XPath와 매칭된 텍스트, 유사도 점수 """ if not all(key in item for key in ['ele', 'arg', 'searchValue']): return None, None, 0 # 유사 텍스트 검색 matched_text, score = self.find_similar_text( item['searchValue'], item['ele'], item['arg'] ) if matched_text: # 기본 XPath 템플릿 구성 xpath = f"//{item['ele']}[@{item['arg']}='{matched_text}']" # path가 제공된 경우, 해당 path를 기반으로 XPath 구성 if 'path' in item and item['path']: xpath = item['path'].replace(f"[@{item['arg']}='']", f"[@{item['arg']}='{matched_text}']") xpath = xpath.replace(f"[@{item['arg']}='searchValue']", f"[@{item['arg']}='{matched_text}']") return xpath, matched_text, score return None, None, 0 def process_config(self, config): """ 설정된 JSON 설정을 처리 :param config: JSON 설정 :return: 처리된 XPath 결과들 """ results = {} for key, item in config.items(): results[key] = { 'original_config': item, 'processed_results': {} } xpath, matched_text, score = self.build_xpath(item) if xpath: try: xpath_results = self.root.xpath(xpath) results[key]['processed_results'] = { 'original_value': item['searchValue'], 'matched_value': matched_text, 'similarity_score': score, 'xpath': xpath, 'results': xpath_results } except etree.XPathEvalError as e: results[key]['error'] = f"XPath evaluation error: {str(e)}" else: results[key]['error'] = "Unable to build XPath: missing required configuration" return results # 사용 예시 def main(): config = { "0": { "path": "//TEXTART[@Text='']/TEXTARTSHAPE/@FontName", "ele": "TEXTART", "arg": "Text", "searchValue": "즐거운컬러푸드영양교실", "value": "궁서체", "points": 10 }, "1": { "path": "//TEXTARTSHAPE[@FontName='']", "ele": "TEXTARTSHAPE", "arg": "FontName", "searchValue": "궁서체", "value": "궁서체", "points": 2 } } xmlPath = r"C:\Users\gzero-ser7-win11\Documents\hwpTest\Output\1.xml"; handler = XMLPathHandler(xmlPath) results = handler.process_config(config) # 결과 출력 for key, result in results.items(): print(f"\nProcessing config item {key}:") print(f"Original config: {result['original_config']}") if 'error' in result: print(f"Error: {result['error']}") else: processed = result['processed_results'] print(f"Generated XPath: {processed['xpath']}") print(f"Matched text: {processed['matched_value']}") print(f"Similarity score: {processed['similarity_score']}") print(f"Results found: {processed['results']}") if __name__ == "__main__": main()