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

114

我有两个用Java编写的应用程序,它们使用网络上的XML消息进行通信。我在接收端使用SAX解析器来获取消息中的数据。其中一个要求是在XML消息中嵌入二进制数据,但SAX不支持此操作。请问是否有人知道如何实现?

更新:我使用apache commons codec库中的Base64类使其起作用,以防其他人尝试类似操作。

12个回答

229

220

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使用不当。而如果你不是,那么那些不懂得高层次写作和低层次思考的初学者又该怎么办呢? - Robin Rodricks
1
我觉得这很有趣。但是,再次强调,使用实际的base64数据类型才是正确的选择。CData太泛化了。 - Omniwombat
4
我认为这个描述不够准确 - 或许应该使用“BINARYDIGIT”而非缩写“BIT”?;-) - Lee Atkinson
哇,这将使平均千字节范围的文件大约增加230倍 :) - Nyerguds
40
哦,见鬼了。这只是个玩笑。我做了什么?!:http://thedailywtf.com/Articles/The-HumanReadable-Encryption-Key.aspx - Mo.

30

Base64确实是正确的答案,但CDATA不是,它基本上是在说:“这可能是任何东西”,但它必须仅是任何东西,而必须是Base64编码的二进制数据。XML Schema将Base 64 binary定义为原始数据类型 ,您可以在xsd中使用它。


2
额外加分项是提到 xs:base64Binary 数据类型,这是正确使用的数据类型。 - Christopher Schultz

15

就在上周我也遇到了这个问题。我需要将一个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

6

5
任何二进制转文本编码都可以解决问题。我使用类似这样的东西。
<data encoding="yEnc>
<![CDATA[ encoded binary data ]]>
</data>

5
尝试对二进制数据进行Base64编码/解码。此外,研究一下CDATA部分。

4

Base64的开销为33%。

BaseXML针对XML1.0的开销仅为20%。但它并不是一个标准,目前只有C语言实现。如果您关注数据大小,请查看一下。请注意,浏览器通常会实现压缩,因此这种方法不太需要。

在这个主题的讨论中,我开发了它:Encoding binary data within XML : alternatives to base64


4
也许将它们编码成已知集合中的一种 - 像 base64 这样的东西是一个流行的选择。

4
虽然其他答案大多可以,但您可以尝试另一种更节省空间的编码方法,如yEnc。(yEnc wikipedia link)使用yEnc还可以获得校验和功能。当然,由于XML没有本地yEnc类型,因此应更新XML模式以正确描述编码节点。 为什么:由于编码策略base64/63、uuencode等编码使您需要存储和传输的数据量(开销)增加了约40%(与yEnc的1-2%相比)。根据您要编码的内容,40%的开销可能会成为一个问题。
yEnc - 维基百科摘要:https://en.wikipedia.org/wiki/YEncyEnc是一种用于在Usenet或通过电子邮件中的消息中传输二进制文件的二进制到文本编码方案。... yEnc相对于之前的编码方法(如uuencode和Base64)的另一个优点是包括CRC校验和,以验证已传递完好的解码文件。

2
@Jamine,你有其他的选择吗? - Hunt
Jamie,如果再多做些努力这可能是一个不错的答案。我撤回了我的-1,如果你付出更多的努力我会+1...如果你有后续,请给我标记。 - Paul Sasik
Jamie,没事。我更新了你的答案,并点赞了,希望加入了你原本想传达的信息。请看一下,如果需要的话可以进行更新。(我已经有一段时间没有在SO上活跃了。研究和编辑答案很有趣。我点赞是因为在这个过程中学到了一些新东西,这就是它的全部意义...?干杯。) - Paul Sasik
当可预测/固定的开销至关重要时,escapeless 可能是 yEnc 的替代选择。 - Ivan Kosarev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接