我有两个用 Java 编写的应用程序,它们通过网络使用 XML 消息相互通信。我在接收端使用 SAX 解析器从消息中取回数据。要求之一是在 XML 消息中嵌入二进制数据,但 SAX 不喜欢这样。有谁知道如何做到这一点?
更新:我从apache commons codec library得到了这个使用Base64类,以防其他人尝试类似的东西。
我有两个用 Java 编写的应用程序,它们通过网络使用 XML 消息相互通信。我在接收端使用 SAX 解析器从消息中取回数据。要求之一是在 XML 消息中嵌入二进制数据,但 SAX 不喜欢这样。有谁知道如何做到这一点?
更新:我从apache commons codec library得到了这个使用Base64类,以防其他人尝试类似的东西。
您可以使用 base64 对二进制数据进行编码并将其放入 Base64 元素中;下面的文章是关于这个主题的一篇很好的文章。
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 可能是最好的解决方案
(EDIT2:
无论谁升级我,也请升级真正的答案。我们不希望任何可怜的灵魂来到这里并实际实施我的方法,因为它是 SO 上排名最高的,对吗?)
Base64 确实是正确的答案,但 CDATA 不是,这基本上是在说:“这可能是任何东西”,但它不能只是任何东西,它必须是 Base64 编码的二进制数据。XML Schema 将Base 64 二进制定义为可以在 xsd 中使用的原始数据类型。
我上周刚遇到这个问题。我必须序列化一个 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>
我通常使用MIME Base64或URL encoding对二进制数据进行编码。
尝试 Base64 编码/解码您的二进制数据。还要查看 CDATA 部分
也许将它们编码成一个已知的集合——比如 base 64 是一种流行的选择。
任何二进制到文本的编码都可以解决问题。我使用类似的东西
<data encoding="yEnc>
<![CDATA[ encoded binary data ]]>
</data>
虽然其他答案大多都很好,但您可以尝试另一种更节省空间的编码方法,如 yEnc。(yEnc 维基百科链接)使用 yEnc 还可以“开箱即用”地获得校验和功能。阅读下面的链接。当然,因为 XML 没有原生 yEnc 类型,所以您的 XML 模式应该更新以正确描述编码节点。
为什么:由于编码策略 base64/63,uuencode 等。编码将您需要存储和传输的数据量(开销)增加了大约 40%(与 yEnc 的 1-2% 相比)。根据您编码的内容,40% 的开销可能/成为问题。
yEnc - 维基百科摘要: https: //en.wikipedia.org/wiki/YEnc yEnc 是一种二进制到文本的编码方案,用于在 Usenet 或通过电子邮件的消息中传输二进制文件。... 与以前的编码方法(例如 uuencode 和 Base64)相比,yEnc 的另一个优势是包含 CRC 校验和,以验证解码后的文件是否已完整交付。</p>
Base64 开销为 33%。
XML1.0的BaseXML开销仅为 20%。但它不是一个标准,只有一个 C 实现。如果您担心数据大小,请查看它。请注意,但是浏览器倾向于实现压缩,因此不需要它。
我在此线程中讨论后开发了它:在 XML 中编码二进制数据:base64 的替代品。
您还可以对原始二进制数据进行Uuencode 。这种格式有点旧,但它与 base63 编码的作用相同。
如果您可以控制 XML 格式,则应该彻底解决问题。与其附加二进制 XML,不如考虑如何封装一个包含多个部分的文档,其中一个部分包含 XML。
对此的传统解决方案是存档(例如 tar)。但是,如果您想以基于文本的格式保存您的附件文档,或者如果您无法访问文件归档库,那么还有一个在电子邮件和 HTTP 中大量使用的标准化方案,它是multipart/* 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
Content-Id 标头标识符的 URI 方案来引用封闭多部分中的二进制数据。该方案的开销只是 MIME 标头。类似的方案也可用于 HTTP 响应。当然,在 HTTP 协议中,您还可以选择将多部分文档发送到单独的请求/响应中。
如果要避免将数据包装在多部分中,请使用数据 URI:
<myxml>
<data href="data:application/something;charset=utf-8;base64,dGVzdGRhdGE="/>
</myxml>
但这有 base64 开销。