如何使用Python将此XML字符串转换为二进制形式?

时间:2014-03-21 01:19:24

标签: python xml encoding

首先,我正在使用UTF-8编码用记事本保存的文本文件进行解析。这足以确保它是UTF-8吗?我尝试了chardet模块,但它并没有真正帮助我。如果有人能够找到更多内容,这里是文本文件的几行:

CUSTOMERLOC|1|N/A|N/A|LEGACY COPPER|N/A|Existing|N/A|NRZ|NRZ|N/A|N/A
FTSMAR08|01/A|N/A|N/A|LEGACY COPPER|N/A|Existing|N/A|NRZ|NRZ|N/A|N/A
FTSMAR08|01/B|N/A|N/A|LEGACY COPPER|N/A|Existing|N/A|NRZ|NRZ|N/A|N/A

我使用lxml模块编写XML,并使用tostring()方法将其分配给名为data的变量。

然后我使用a2b_qp()模块的binascii函数将XML字符串转换为二进制文件,然后将所有这些字符串放入bytearray

data = bytearray(binascii.a2b_qp(ET.tostring(root, pretty_print=True)), "UTF-8")

现在在我看来,这个data变量应该在bytearray内包含二进制形式的XML。

所以,然后我使用了更新游标并将数据插入到表的BLOB字段中。

row[2] = data
cursor.updateRow(row)

一切似乎都有效,但当我使用此代码阅读BLOB字段时:

with arcpy.da.SearchCursor("Point", ['BlobField']) as cursor:
    for row in cursor:
        binaryRep = row[0]
        open("C:/Blob.xml, 'wb').write(binaryRep.tobytes())

当我打开Blob.xml文件时,我希望看到我首先以可读的形式创建的XML字符串,但是我将这个混乱的Notepad ++设置为UTF-8编码:

enter image description here

这个与Notepad ++的混乱设置为ANSI编码:

ANSI encoding

我认为有经验的人可能会通过看图片知道发生了什么。我已经阅读了很多并试图弄明白,但我已经被困了一段时间了。

3 个答案:

答案 0 :(得分:4)

  

我正在使用UTF-8中的记事本保存的文本文件进行解析   编码。这足以确保它是UTF-8吗?我试过了   chardet模块,但它并没有真正帮助我。

是的,告诉编辑将其保存在给定的编码中足以确保它以该编码保存。如果可能的话,这也应该记录在某个地方的文件中 - 使用XML,<?xml encoding="utf-8"?>是指定这一点的常用方法 - 但这只是元数据,而不是实际控制编码。当{em>您不知道编码时,chardet非常有用 - 但它的猜测应该作为最后的手段保留。 UTF8通常是一个很好的默认假设,特别是对于XML。

这一行的原因:

data = bytearray(binascii.a2b_qp(ET.tostring(root, pretty_print=True)), "UTF-8")

让你胡说八道,它会做一些讨厌的事情,并最终得到mojibake

ET.tostring()默认以ASCII格式编码(因此会丢失任何不是ASCII范围的数据,但现在除了这一点之外)。所以,现在你有一个ASCII字符串。 binascii.a2b_qp 使用引用的可打印编码对其进行解码。因此,它将其从一切都是可打印的ASCII字符转变为不必要的情况(qp使用3个可打印的ASCII字符对可打印ASCII范围内的任何字节进行编码)。这意味着,例如,如果您的文本中有任何内容= 00,则会将其转换为空字节。问题是你所拥有的是不是 QP编码的,所以QP解码会导致无意义。

然后使用bytearray将其再次编码为UTF8。 bytearray假设如果你给它一个编码,那么字符串是一个unicode字符串 - 你打破这个假设,并给它原始的二进制数据(这已经没有意义)。将原始二进制数据编码为UTF8并不是特别有意义的事情,这一点让我相信您正在使用Python 2.当您尝试执行此操作时,Python 3会正确地抛出错误:

>>> bytearray(b'123', 'utf8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: encoding or errors without a string argument

Python 2对于什么是字节以及什么是解码字符非常模糊,这使问题类型的问题更容易遇到。如果可以的话,这是升级到Python 3的一个很好的理由。但它不会帮助你从a2b_qp中获得前所未有的废话(因为它是一个字节&lt; - &gt;字节编码)。


修复方法是从头开始将其编码为UTF-8 ,并忘记quoted-printable。 (如果你真的希望它是QP编码的,那么在之后通过binascii.b2a 运行它是UTF8化的。)

ElementTree允许您指定编码:

 ET.tostring(root, encoding='utf-8')

将为您提供正确的UTF-8编码XML,它将在Notepad ++中很好地打开。

答案 1 :(得分:3)

我认为你在这里偏离轨道:

binascii.a2b_qp(ET.tostring(root, pretty_print=True))

a2b_qp假设输入是'quoted printable'(类似于base64),但它实际上是XML。 结果是二进制文件是垃圾邮件。

相反,您应该使用bytearray。传递你的XML字符串和编码("utf-8"),它将返回你的blob。

编码是有趣的一套心理体操。总结:

  • 如果在Python 3中,你可能很好。如果您使用的是2.x,那么您几乎肯定希望使用unicode数据类型,而不是str
  • Unicode是一种比编码更高级的概念。每个可显示的字符是超过一百万个字符的巨大逻辑空间中的一个(或有时多于一个)代码点。
  • 简单地将Unicode字符串写入磁盘需要每个字符3个字节。这些文件会比它们大得多,并且与大多数现有的ASCII文件不兼容 - 这在1990年代是不可接受的,当时大多数数据都是ASCII而且磁盘非常昂贵,因此使用了编码(映射) 。 UTF-8是一个很好的因为:
    • 向后兼容性:所有7个但ASCII文件都是有效的UTF-8文件
    • 效率:8位到14位字符(大多数人使用的大多数其他字符)映射到2个字节的UTF-8。其他字符根据需要占用3或4个字节
    • 兼容性:许多重要的协议和标准都使用UTF-8
  • 你已经使用binascii进行了另一种编码。这是一组例程,当您必须通过仅允许ASCII或安全的媒体(例如URL和SMTP /电子邮件)发送二进制数据(例如JPG)时使用。 Base64的工作原理如下
    • 使用A-Z,a-z,0-9和更多字符,您有64个代码点或6位信息。
    • 这些字符中的4个是6x4 = 24位,与3个字节的数据(3x8)相同。
    • Base64因此获取3个字节的块并将它们映射为4个安全字符。
    • 换句话说,您可以将任何二进制文件转换为安全字符块,但代价是增加30%。

我希望这会有所帮助

答案 2 :(得分:0)

储存:

  • 拥有您的XML数据
  • 将其序列化为字符串
  • 将该字符串编码为UTF-8二进制字符串(即xml_string.encode('utf-8')
  • 将生成的二进制字符串保存在数据库中

Retrieiving:

  • 从数据库中检索二进制字符串
  • 从UTF-8解码 - xml_string.decode('utf-8')
  • 再次将其反序列化为XML
  • 使用XML执行您想要的操作