如何将二进制数据嵌入XML?


107

我有两个用Java编写的应用程序,它们通过网络使用XML消息相互通信。我在接收端使用了SAX解析器,以从消息中获取数据。要求之一是将二进制数据嵌入XML消息中,但是SAX不喜欢这样。有谁知道如何做到这一点?

更新:我可以通过apache commons编解码器库中Base64类进行此操作,以防其他人尝试类似的操作。

Answers:



209

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就像暴力-如果它不能解决问题,则说明您使用的不够多。

编辑:

顺便说一句:Base64 + CDATA可能是最好的解决方案

(编辑2:
无论谁修改我的意见,也请修改真实的答案。我们不希望任何可怜的人来这里并实际实施我的方法,因为它在SO上排名最高,对吗?)


9
如果您是认真的人,这无非是对XML的完全可耻的使用。如果不是,那么那些不写高水平,想低水平的初学者怎么会知道呢?
TheFlash

1
我觉得这很有趣。但是,是的,再次使用实际的base64数据类型是可行的方法。CData太通用了。
Omniwombat

4
我认为描述性不够-也许应该使用“ BINARYDIGIT”而不是缩写“ BIT”?;-)
Lee Atkinson

哇。这将使平均千字节范围的文件大约大230倍:)
Nyerguds 2011年

36
哦,为了缘故。开个玩笑。我做了什么?!thedailywtf.com/Articles/The-HumanReadable-Encryption-Key.aspx
密苏里州


14

上周我遇到了这个问题。我必须序列化一个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>

最佳答案,因为我可以从中复制/粘贴Convert.ToBase64String
Eldritch Conundrum


5

尝试对您的二进制数据进行Base64编码/解码。同时查看CDATA部分


4

也许将它们编码成一个已知的集合-诸如base 64之类的东西很受欢迎。




4

尽管其他答案通常都不错,但是您可以尝试使用其他更节省空间的编码方法,例如yEnc。(yEnc Wikipedia链接)有了yEnc,“开箱即用”还可以获得校验和功能。阅读下面的链接。当然,由于XML没有本机yEnc类型,因此应更新XML模式以正确描述编码的节点。

原因:由于采用base64 / 63编码策略,因此uuencode等。编码使您需要存储和传输的数据量(开销)大约增加了40%(与yEnc的1-2%相比)。取决于您要编码的内容,40%的开销可能是/成为一个问题。


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


2
@Jamine所以您还有其他选择吗?
2014年

杰米,考虑到更多工作,这可能是一个不错的答案。我删除了我的-1,如果您付出一些努力,我将+1。
保罗·萨西克

杰米,不适用。我更新了您的答案,并+1了,希望能提供您原本打算传达的信息。偷看一下,也许在您认为合适的时候进行更新。(我已经有一段时间没有活跃于SO了。研究和编辑答案很有趣。我+1是因为在学习新事物的过程中,这就是全部内容了……干杯。)
保罗·萨西克

当可预见的/固定的开销至关重要时,escapeless可以替代yEnc。
伊万·科萨列夫


0

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

对此的传统解决方案是存档(例如tar)。但是,如果您希望将附件文档保留为基于文本的格式,或者如果您无权访问文件归档库,那么还有一种标准化的方案,该方案在电子邮件和HTTP中大量使用,它是multipart / * MIMEContent-Transfer-Encoding:二进制

例如,如果您的服务器通过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通过使用cidURI方案(它是Content-Id标头的标识符)来引用封闭多部分中的二进制数据。这种方案的开销只是MIME标头。类似的方案也可以用于HTTP响应。当然,在HTTP协议中,您还可以选择将多部分文档发送到单独的请求/响应中。

如果要避免将数据包装成多部分,请使用数据URI:

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

但这有base64开销。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.