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

时间:2008-08-21 13:35:47

标签: java xml binary binary-data

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

更新:我使用Base64中的apache commons codec library课程,以防其他人尝试类似的事情。

12 个答案:

答案 0 :(得分:210)

您可以使用base64对二进制数据进行编码,并将其放入Base64元素中;以下文章是关于这一主题的非常好的文章。

Handling Binary Data in XML Documents

答案 1 :(得分: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就像暴力 - 如果它无法解决您的问题,那么您就没有使用它。

编辑:

BTW:Base64 + CDATA可能是最好的解决方案

(EDIT2:
无论谁对我进行upmod,请同意upmod真正的答案。我们不希望任何可怜的灵魂来到这里实际实施我的方法,因为它在SO上排名最高,对吗?)

答案 2 :(得分:25)

Base64确实是正确的答案,但CDATA不是,这基本上是说:“这可能是任何东西”,但它必须只是任何东西,它必须是Base64编码的二进制数据。 XML Schema定义了您可以在xsd中使用的Base 64 binary as a primitive datatype

答案 3 :(得分:12)

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

答案 4 :(得分:6)

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

答案 5 :(得分:5)

尝试Base64编码/解码二进制数据。另请参阅CDATA部分

答案 6 :(得分:4)

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

答案 7 :(得分:4)

任何binary-to-text encoding都可以解决问题。我使用类似的东西

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

答案 8 :(得分:4)

虽然其他答案大多都很好,但您可以尝试另一种更节省空间的编码方法,例如yEnc。 (yEnc wikipedia link)使用yEnc也可以“开箱即用”获得校验和功能。阅读和链接如下。当然,因为XML没有本机yEnc类型,所以应该更新XML模式以正确描述编码节点。

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


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

答案 9 :(得分:3)

Base64开销为33%。

BaseXML对于XML1.0 开销仅为20%。但它不是标准,只有C实现。如果您关注数据大小,请查看它。请注意,但是浏览器倾向于实现压缩,因此不太需要它。

我在这个帖子的讨论后开发了它:Encoding binary data within XML : alternatives to base64

答案 10 :(得分:2)

您还可以Uuencode原始二进制数据。这种格式有点旧,但它与base63编码的作用相同。

答案 11 :(得分:0)

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

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

例如,如果您的服务器通过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协议中,您还可以选择将多部分文档发送到单独的请求/响应中。

如果要避免在multipart中包装数据,请使用数据URI:

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

但这有base64开销。