如何在 XML 中嵌入二进制数据?

我有两个用 Java 编写的应用程序,它们使用 XML 消息通过网络进行通信。我在接收端使用 SAX 解析器从消息中获取数据。需求之一是在 XML 消息中嵌入二进制数据,但 SAX 不喜欢这样。有人知道怎么做吗?

更新: 我得到了这个工作与 基地64类从 Apache commons 编解码器库,以防任何人正在尝试类似的东西。

117408 次浏览

也许把它们编码成一个已知的集合——类似于64进制的编码是一个流行的选择。

尝试 Base64编码/解码二进制数据

您可以使用 base64对二进制数据进行编码,并将其放入 Base64元素中; 下面的文章是关于该主题的一篇相当不错的文章。

XML 文档中二进制数据的处理

我通常用 MIME Base64URL 编码对二进制数据进行编码。

XML 是如此多才多艺..。

<DATA>
<BINARY>
<BIT index="0">0</BIT>
<BIT index="1">0</BIT>
<BIT index="2">1</BIT>
...
<BIT index="n">1</BIT>
</BINARY>
</DATA>

XML 就像暴力——如果它不能解决你的问题,你就没有充分利用它。

编辑:

BTW: Base64 + CDATA is probably the best solution

(编辑2:
不管谁提升我,请也提升真正的答案。我们不希望任何可怜的灵魂来到这里,实际执行我的方法,因为它是最高级别的 SO,对不对?)

Base64确实是正确的答案,但 CDATA 不是,基本上是说: “这可以是任何东西”,但它必须 没有是任何东西,它必须是 Base64编码的二进制数据。XMLSchema 定义了可以在 xsd 中使用的 作为基元数据类型的基64二进制文件

你也可以 Uuencode你原来的二进制数据。这种格式稍微老一些,但是它的作用与 base63编码相同。

任何 二进制文本编码都可以,我用的就是这个

<data encoding="yEnc>
<![CDATA[ encoded binary data ]]>
</data>

我上周才遇到这个问题。我必须序列化一个 PDF 文件,然后在 XML 文件中将其发送到服务器。

如果你吸毒的话。NET 中,可以将二进制文件直接转换为 base64字符串并将其粘贴到 XML 元素中。

string base64 = Convert.ToBase64String(File.ReadAllBytes(fileName));

或者,在 XmlWriter 对象中内置了一个方法。在我的特例中,我必须包含 Microsoft 的数据类型命名空间:

StringBuilder sb = new StringBuilder();
System.Xml.XmlWriter xw = XmlWriter.Create(sb);
xw.WriteStartElement("doc");
xw.WriteStartElement("serialized_binary");
xw.WriteAttributeString("types", "dt", "urn:schemas-microsoft-com:datatypes", "bin.base64");
byte[] b = File.ReadAllBytes(fileName);
xw.WriteBase64(b, 0, b.Length);
xw.WriteEndElement();
xw.WriteEndElement();
string abc = sb.ToString();

字符串 abc 看起来像这样:

<?xml version="1.0" encoding="utf-16"?>
<doc>
<serialized_binary types:dt="bin.base64" xmlns:types="urn:schemas-microsoft-com:datatypes">
JVBERi0xLjMKJaqrrK0KNCAwIG9iago8PCAvVHlwZSAvSW5mbw...(plus lots more)
</serialized_binary>
</doc>

虽然其他的答案大部分都不错,但您可以尝试另一种更节省空间的编码方法,比如 yEnc。(YEnc 维基百科链接)使用 yEnc 还可以立即获得校验和功能。阅读下面的链接。当然,由于 XML 没有本机 yEnc 类型,因此应该更新 XML 模式以正确描述编码的节点。

为什么 : 由于基于64/63的编码策略,uuencode 等编码增加了大约40% 的数据存储和传输开销(相对于 yEnc 的1-2%)。根据您所编码的内容,40% 的开销可能会成为一个问题。


yEnc - Wikipedia abstract: Https://en.wikipedia.org/wiki/yenc YEnc 是一种二进制到文本的编码方案,用于在 Usenet 上或通过电子邮件传输消息中的二进制文件。... 与以前的编码方法(如 uuencode 和 Base64)相比,yEnc 的另一个优点是包含 CRC 校验和来验证已解码的文件是否完好无损。

64基地的开销是33% 。

BaseXML for XML1.0 开销只有20% . But it's not a standard and only have a C implementation yet. Check it out if you're concerned with data size. Note that however browsers tends to implement compression so that it is less needed.

我在这个帖子的讨论之后开发了它: 在 XML 中编码二进制数据: base64的替代方案

如果您可以控制 XML 格式,那么应该彻底解决这个问题。与其附加二进制 XML,不如考虑如何封装包含多个部分(其中一个包含 XML)的文档。

传统的解决方案是存档(例如 tar)。但是,如果你想保持你的文件在一个基于文本的格式或如果你没有访问文件归档库,也有一个标准化的方案,是使用大量的电子邮件和 HTTP 是 多部分/* MIME内容传输编码: 二进制

例如,如果您的服务器通过 HTTP 进行通信,并且您希望发送一个多部分文档(主要是指二进制数据的 XML 文档) ,那么 HTTP 通信可能类似于下面这样:

POST / HTTP/1.1
Content-Type: multipart/related; boundary="qd43hdi34udh34id344"
... other headers elided ...


--qd43hdi34udh34id344
Content-Type: application/xml


<myxml>
<data href="cid:data.bin"/>
</myxml>
--qd43hdi34udh34id344
Content-Id: <data.bin>
Content-type: application/octet-stream
Content-Transfer-Encoding: binary


... binary data ...
--qd43hdi34udh34id344--

如上例所示,XML 通过使用一个 cid URI 方案(它是 Content-Id 标头的标识符)来引用封闭的多部分中的二进制数据。这个方案的开销将只是 MIME 头。类似的方案也可以用于 HTTP 响应。当然,在 HTTP 协议中,您还可以选择将多部分文档发送到单独的请求/响应中。

如果您想避免将数据包装成多部分,那么可以使用数据 URI:

<myxml>
<data href="data:application/something;charset=utf-8;base64,dGVzdGRhdGE="/>
</myxml>

但是这个有64基地的开销。