【问题标题】:encode and decode bytes in xml strings编码和解码 xml 字符串中的字节
【发布时间】:2020-03-22 13:26:52
【问题描述】:

我正在寻找一种在 xml 文件中写入和读取字节数据的方法。我希望 xml 文件是人类可读的,所以我想避免使用 base64 编码或类似的东西。我想我可以做这样的事情。如果我有一个字符串b'abc < ABC\x04&' 需要进入标签<node>,那么我会写成

<node>abc &lt; ABC&#x04;&amp;</node>

有没有办法让这种编码与 python3 中的任何 xml 库一起工作?我更喜欢lxml,但这不是必需的。

澄清:当我写一个 xml 文件时,字符串最初的类型是 bytes,例如b'abc &lt; ABC\x04&amp;'。在很多情况下,它们只包含字母数字 ascii 字符,我想将其写入 xml。我想将其他字节编码为十六进制值,因此它们仍然很容易理解。而且我想将&amp;gt;&amp;amp; 之类的字符编码为&amp;gt;&amp;amp;(或者也作为十六进制值)以避免使用&lt;![CDATA[&lt;]]&gt;。当我读取字符串时,如果可能的话,我希望将它们转换回b'...'

【问题讨论】:

    标签: python python-3.x xml byte


    【解决方案1】:

    我很确定没有内置函数可以完全满足您的要求

    我认为您能做的最好的事情就是迭代字符并“修复”每个字符(请参阅我认为完整的示例)

    try: # python2
      from htmlentitydefs import codepoint2name
    except: # python3
      from html.entities import codepoint2name
    
    def encode_xml(c):
      # return the character or its &#XX; or &entity; representation
      ascii_val = ord(c)
      known_entity =  codepoint2name.get(ascii_val,None)
      if known_entity: # this is a named codepoint
        return "&%s;"%(known_entity,)  
      # printable characters are ascii values [32..127] inclusive
      is_normal_character =  32 <= ascii_val <= 127
      if is_normal_character:
          return c
      return hex(ascii_val).replace("0x","&#")+";"
    
    
    def make_xml_entity_string(s):
      return "".join(encode_xml(c) for c in s)
    
    print("R:", make_xml_entity_string( 'abc < ABC\x14\xF2&'))
    

    然后你可以走其他路......以大致相同的方式(不过这次利用正则表达式)

    try: # python2  
      from htmlentitydefs import name2codepoint
    except: # python3
      from html.entities import name2codepoint
    import re
    
    def decode_xml_replacer(match):
      name=match.group(1);
      if(name.startswith("#")):
        return chr(int(name[1:],16))
      return chr(name2codepoint.get(name,'?'))
    
    def decode_xml_string(s):
      return re.sub("&(.*?);",decode_xml_replacer,s)
    

    ...请注意,这不适用于代码点 > 255 我认为

    【讨论】:

    • 很遗憾图书馆似乎没有将其作为一个选项来实现。编码不是这里最大的问题,因为它可以在调用 xml 库之前完成。真正的问题是解码,因为库会尝试自己进行解码,并且至少 lxml 似乎会阻塞小于 32 的字节。例如,etree.fromstring('&lt;x&gt;a&amp;gt;bc&amp;#x80;&lt;/x&gt;').text 给出 'a&gt;bc\x80',但 etree.fromstring('&lt;x&gt;a&amp;gt;bc&amp;#x14;&lt;/x&gt;').text 阻塞声称 invalid xmlChar value 20 .
    • 我想我可以保留\x14 类型的编码并自己解析它,并且只替换对 xml 不利的字符,例如&lt;.
    猜你喜欢
    • 2012-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-05
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多