Python解析XML:将十六进制转义序列视为字面字符串
保留XML属性中的实体字符串而不解码
这问题我之前也踩过坑!默认的XML解析器(包括lxml的fromstring)会严格遵循XML规范,自动解码属性值里的字符实体,把转换成实际的退格控制字符。要保留原始的实体字符串,有两种实用的解决方法:
方法1:预处理XML文本,转义实体的起始符
核心思路是把属性里的&#x替换成&#x——这样解析器会把&识别成普通的&字符,最终得到完整的字符串。示例代码:
import lxml.etree as ET # 原始XML片段(需包裹成合法的单根XML结构) raw_xml = ''' <root> <key code="51" output=""/> <!-- backspace --> <key code="53" output=""/> <!-- escape --> </root> ''' # 预处理:将实体的&转义为&,避免解析器自动解码 processed_xml = raw_xml.replace('&#x', '&#x') # 正常解析XML tree = ET.fromstring(processed_xml) for key_elem in tree.findall('.//key'): output_attr = key_elem.get('output') print(repr(output_attr)) # 输出: '' 和 ''
方法2:使用SAX解析器直接获取原始属性值
SAX是基于事件的XML解析器,它不会自动解码实体,能直接拿到属性的原始字符串内容,适合处理大型XML或者需要更底层控制的场景:
from xml.sax import make_parser, handler class EntityCaptureHandler(handler.ContentHandler): def startElement(self, tag_name, attrs): if tag_name == 'key': # getValue方法返回未解码的原始属性字符串 raw_output = attrs.getValue('output') print(f"原始output属性值: {repr(raw_output)}") # 初始化SAX解析器 parser = make_parser() parser.setContentHandler(EntityCaptureHandler()) # 解析XML(同样需要合法的单根结构) parser.parseString(''' <root> <key code="51" output=""/> <!-- backspace --> <key code="53" output=""/> <!-- escape --> </root> ''')
补充说明:为什么默认解析器会自动解码?
根据XML 1.0规范,属性值中的字符实体(比如&#xHHHH;)必须被解析器解码为对应的Unicode字符。所以DOM类解析器(包括lxml、xml.etree)都会默认执行这个操作,要绕过它就得用上面两种方法。
内容的提问来源于stack exchange,提问作者Jollywatt
相关产品推荐
相关产品推荐

