xPath 기반 유사도 검사 테스트 코드
This commit is contained in:
148
xpathSearch.py
Normal file
148
xpathSearch.py
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
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()
|
||||||
Reference in New Issue
Block a user