如何用OpenAI GPT-4翻译带CDATA的XML并保留CDATA结构?
问题:GPT-4翻译XML时无法保留CDATA结构
我使用OpenAI GPT-4将XML内容从英文翻译为法语,但遇到了无法保留XML中CDATA结构的问题。XML包含带CDATA段的字符串,需要翻译后的输出维持CDATA结构。
输入XML示例
<resources> <string name="app_name">RoomThermometer</string> <string name="instructions" formatted="false"> <![CDATA[ <b>How it works? </b><br /> The thermometer app is using your phone temperature sensors to measure room temperature.<br /><br /> <b>Why this thermometer is the best one?</b><br /> We use AI-powered algorithm to get the most accurate measure by ± 3°C. The more you use the thermometer, the more accurate it is!<br /><br /> <b>How to get the best room temperature measure?</b><br /> You want to prevent the phone from overheating, follow the next steps:<br /> <b>1-</b> take your case off<br /> <b>2-</b> Your phone is charging or just charged, let it cool down<br /> <b>3-</b> Turn off unnecessary apps running in the background<br /> ]]> </string> </resources>
当前错误输出
<resources> <string name="app_name">Thermomètre de Chambre</string> <string name="instructions" formatted="false"> '<b>Comment ça marche?</b><br/> L'application de thermomètre utilise les capteurs de température de votre téléphone pour mesurer la température ambiante.<br/><br/> <b>Pourquoi ce thermomètre est le meilleur?</b><br/> Nous utilisons un algorithme alimenté par l'IA pour obtenir la mesure la plus précise à ± 3°C. Plus vous utilisez le thermomètre, plus il est précis!<br/><br/> <b>Comment obtenir la meilleure mesure de température ambiante?</b><br/> Vous voulez éviter que le téléphone ne surchauffe, suivez les étapes suivantes:<br/> <b>1-</b> retirez votre coque<br/> <b>2-</b> Votre téléphone est en charge ou vient d'être chargé, laissez-le refroidir<br/> <b>3-</b> Arrêtez l'application inutile qui fonctionne en arrière-plan<br/>' </string> </resources>
期望输出
<resources> <string name="app_name">Thermomètre de Chambre</string> <string name="instructions" formatted="false"> <![CDATA[ <b>Comment ça fonctionne ? </b><br /> L'application thermomètre utilise les capteurs de température de votre téléphone pour mesurer la température de la pièce.<br /><br /> <b>Pourquoi ce thermomètre est le meilleur ?</b><br /> Nous utilisons un algorithme alimenté par l'IA pour obtenir la mesure la plus précise à ± 3°C. Plus vous utilisez le thermomètre, plus il est précis !<br /><br /> <b>Comment obtenir la meilleure mesure de la température de la pièce ?</b><br /> Vous voulez empêcher le téléphone de surchauffer, suivez les étapes suivantes :<br /> <b>1-</b> retirez votre étui<br /> <b>2-</b> Votre téléphone est en train de charger ou vient de se charger, laissez-le refroidir<br /> <b>3-</b> Fermez les applications inutiles qui tournent en arrière-plan<br /> ]]> </string> </resources>
问题代码
原脚本中处理XML的函数存在两处核心问题:
- Python标准库
xml.etree.ElementTree解析XML时会自动剥离CDATA标记,导致代码中的CDATA判断条件无法触发 - 手动拼接CDATA字符串会被ElementTree转义,无法生成合法的CDATA段
def translate_xml_file(xml_file_path, target_language="French"): # Parse the XML file tree = ET.parse(xml_file_path) root = tree.getroot() # Iterate over each 'string' element for string_element in root.iter('string'): # Check if the element contains text if string_element.text: string_text = string_element.text.strip() # Check if the text is within a CDATA section if string_text.startswith("<![CDATA[") and string_text.endswith("]]>"): # Extract the content from CDATA cdata_content = string_text[9:-3] # Translate the content translated_cdata_content = translate_string(cdata_content, target_language) # Manually wrap with CDATA and set back to element string_element.text = "<![CDATA[" + translated_cdata_content + "]]>" else: # Translate normal text translated_text = translate_string(string_text, target_language) string_element.text = translated_text return tree
解决方案
步骤1:自定义CDATA处理类(标准库兼容)
扩展ElementTree,让它能识别并输出CDATA段:
import xml.etree.ElementTree as ET class CDATA(ET.Element): def __init__(self, text): super().__init__() self.text = text def _serialize_cdata(write, elem, encoding, qnames, namespaces): write(f"<![CDATA[{elem.text}]]>".encode(encoding)) # 替换默认的XML序列化逻辑 ET._original_serialize_xml = ET._serialize_xml def _serialize_xml(write, elem, encoding, qnames, namespaces, orig=ET._original_serialize_xml): if isinstance(elem, CDATA): _serialize_cdata(write, elem, encoding, qnames, namespaces) else: orig(write, elem, encoding, qnames, namespaces) ET._serialize_xml = _serialize_xml
步骤2:修改XML解析逻辑,捕获CDATA标记
自定义解析器,记录哪些元素原本包含CDATA:
class CDATAExtractor(ET.TreeBuilder): def cdata(self, data): # 标记当前元素包含CDATA self._last_is_cdata = True super().data(data) def end(self, tag): elem = super().end(tag) if hasattr(self, '_last_is_cdata') and self._last_is_cdata: elem.set('__is_cdata', 'True') delattr(self, '_last_is_cdata') return elem
步骤3:更新翻译函数
修改后的函数能正确识别并保留CDATA结构:
def translate_xml_file(xml_file_path, target_language="French"): # 使用自定义解析器捕获CDATA信息 parser = ET.XMLParser(target=CDATAExtractor()) tree = ET.parse(xml_file_path, parser=parser) root = tree.getroot() for string_element in root.iter('string'): if string_element.text: string_text = string_element.text.strip() # 检查是否为CDATA元素 is_cdata = string_element.get('__is_cdata') == 'True' if is_cdata: string_element.attrib.pop('__is_cdata') if is_cdata: # 翻译时提示GPT保留HTML标签 prompt = f"Translate the following text to {target_language}, keep all HTML tags (like <b>, <br>) unchanged, do not escape them:\n{string_text}" translated_content = translate_string(prompt, target_language) # 替换为CDATA元素 string_element.text = None string_element.append(CDATA(translated_content)) else: translated_text = translate_string(string_text, target_language) string_element.text = translated_text return tree
步骤4:保存XML时的注意事项
调用write方法时需指定编码,避免乱码:
tree = translate_xml_file("input.xml") tree.write("output.xml", encoding='utf-8', xml_declaration=True)
补充说明
- 确保
translate_string函数中的GPT prompt明确要求保留HTML标签,避免GPT转义标签 - 如果可以使用第三方库
lxml,可以简化CDATA的处理(lxml原生支持CDATA对象)
内容的提问来源于stack exchange,提问作者user22833873
相关产品推荐
相关产品推荐

