import csv import xml.etree.ElementTree as ET import sys import os csv_file = '/home/x79/sisvietnamvn_01/sisvietnamvn_Trang chính thức hiện tại/DS_BacSi/DANH SÁCH BÁC SĨ NGỒI PHÒNG KHÁM_THÔNG TIN CHI TIẾT_FULL.csv' xml_file = '/home/x79/sisvietnamvn_01/sisvietnamvn_Trang chính thức hiện tại/DS_BacSi/bnhvinakhoaquctsiscnth.WordPress.2026-07-28 (5).xml' # Read CSV csv_doctors = {} with open(csv_file, 'r', encoding='utf-8-sig') as f: reader = csv.DictReader(f) for row in reader: name = row.get('Họ và tên', '').strip() if not name: continue msnv = row.get('MSNV', '').strip() title = row.get('Chức danh', '').strip() degree = row.get('Trình độ chuyên môn', '').strip() specialty = row.get('Khoa/ Phòng', '').strip() education = row.get('Quá trình đào tạo', '').strip() experience = row.get('Quá trình công tác', '').strip() achievements = row.get('Hiệp hội chuyên môn', '').strip() + '\n' + row.get('Ghi chú', '').strip() csv_doctors[name.lower()] = { 'name': name, 'doctor_code': msnv, 'title': degree, 'position': title, 'specialty': specialty, 'education': education, 'experience': experience, 'achievements': achievements, 'active': 1 if msnv else 0 } # Read XML xml_doctors = {} tree = ET.parse(xml_file) root = tree.getroot() ns = { 'wp': 'http://wordpress.org/export/1.2/', 'content': 'http://purl.org/rss/1.0/modules/content/' } for channel in root.findall('channel'): for item in channel.findall('item'): post_type = item.find('wp:post_type', ns) if post_type is None or post_type.text != 'doctor': continue title_elem = item.find('title') if title_elem is None or not title_elem.text: continue name = title_elem.text.strip() if not name: continue doc = {'name': name} # Extract department category for cat in item.findall('category'): if cat.get('domain') == 'department': doc['specialty'] = cat.text.strip() break for meta in item.findall('wp:postmeta', ns): key = meta.find('wp:meta_key', ns) val = meta.find('wp:meta_value', ns) if key is not None and val is not None and val.text: k = key.text v = val.text.strip() if k == 'doctor_information_position': doc['position'] = v elif k == 'doctor_information_specialty': doc['specialty'] = v elif k == 'doctor_information_experience': doc['experience'] = v elif k == 'doctor_information_education': doc['education'] = v elif k == 'doctor_information_achievements': doc['achievements'] = v elif k == 'doctor_information_gender': doc['gender'] = v elif k == 'doctor_information_phone': doc['phone_number'] = v elif k == 'doctor_information_email': doc['email'] = v elif k == 'doctor_information_avatar': doc['avatar_url'] = v elif k == 'doctor_information_booking': doc['booking_url'] = v elif k == 'doctor_information_title': doc['title'] = v xml_doctors[name.lower()] = doc # Merge merged_doctors = {} for name_key, xml_doc in xml_doctors.items(): merged_doctors[name_key] = xml_doc # Priorities: CSV overwrites XML for name_key, csv_doc in csv_doctors.items(): # Find matching XML doctor by checking if CSV name is substring of XML name matched_xml_key = None for xml_key in merged_doctors.keys(): # Remove spaces and dashes for comparison clean_csv = name_key.replace(' ', '').replace('-', '') clean_xml = xml_key.replace(' ', '').replace('-', '') if clean_csv in clean_xml or clean_xml in clean_csv: matched_xml_key = xml_key break if matched_xml_key: existing = merged_doctors[matched_xml_key] for k, v in csv_doc.items(): if v and str(v).strip(): existing[k] = v # Ensure we use the clean plain name from CSV, not the long XML title existing['name'] = csv_doc['name'] else: merged_doctors[name_key] = csv_doc # Write SQL plsql = "BEGIN\n" plsql += " DELETE FROM sis_doctor_schedule;\n" plsql += " DELETE FROM sis_doctor;\n" for doc in merged_doctors.values(): name = doc.get('name', '').replace("'", "''") code = doc.get('doctor_code', '').replace("'", "''") title = doc.get('title', '').replace("'", "''") pos = doc.get('position', '').replace("'", "''") gender = doc.get('gender', '').replace("'", "''") phone = doc.get('phone_number', '').replace("'", "''") email = doc.get('email', '').replace("'", "''") spec = doc.get('specialty', '').replace("'", "''") edu = doc.get('education', '').replace("'", "''") exp = doc.get('experience', '').replace("'", "''") ach = doc.get('achievements', '').replace("'", "''") avt = doc.get('avatar_url', '').replace("'", "''") bk = doc.get('booking_url', '').replace("'", "''") active = doc.get('active', 0) plsql += f""" DECLARE v_count NUMBER; v_spec_id NUMBER := NULL; BEGIN IF '{spec}' IS NOT NULL THEN SELECT COUNT(*) INTO v_count FROM sis_specialty WHERE name = '{spec}'; IF v_count = 0 THEN INSERT INTO sis_specialty (id, name, slug, created_by, created_date, last_modified_by, last_modified_date) VALUES (sequence_generator.NEXTVAL, '{spec}', '{spec}', 'system', sysdate, 'system', sysdate); END IF; SELECT id INTO v_spec_id FROM sis_specialty WHERE name = '{spec}' FETCH FIRST 1 ROWS ONLY; END IF; INSERT INTO sis_doctor ( id, name, doctor_code, title, position, gender, phone_number, email, specialty_id, education, work_experience, achievements, avatar_url, booking_url, active, display_order, created_by, created_date, last_modified_by, last_modified_date ) VALUES ( sequence_generator.NEXTVAL, '{name}', '{code}', '{title}', '{pos}', '{gender}', '{phone}', '{email}', v_spec_id, '{edu}', '{exp}', '{ach}', '{avt}', '{bk}', {active}, 0, 'system', sysdate, 'system', sysdate ); END; """ plsql += "COMMIT;\nEND;\n/" with open('/home/x79/sisvietnamvn_01/sisvietnamvn_main/src/main/resources/config/liquibase/data/merge_doctors.sql', 'w', encoding='utf-8') as f: f.write(plsql) print("Generated merge_doctors.sql")