代码之家  ›  专栏  ›  技术社区  ›  Bill the Lizard

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

  •  101
  • Bill the Lizard  · 技术社区  · 16 年前

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

    最新消息:我把它和 Base64 类从 apache commons codec library 以防其他人尝试类似的东西。

    12 回复  |  直到 6 年前
        1
  •  204
  •   Greg Hurlman    16 年前

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

    Handling Binary Data in XML Documents

        2
  •  203
  •   Mo.    16 年前

    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可能是最好的解决方案

    (EdET2):
    不管是谁升级我,请也升级真正的答案。我们不想让任何可怜的灵魂来这里实现我的方法,因为它是排名最高的所以,对吗?)

        3
  •  25
  •   Boris Terzic    16 年前

    base64确实是正确的答案,但是cdata不是,这基本上是说:“这可以是任何东西”,但是它必须 不管怎样,它必须是base64编码的二进制数据。XML架构定义 Base 64 binary as a primitive datatype 可以在XSD中使用。

        4
  •  11
  •   Baxter Tidwell    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>
    
        5
  •  6
  •   Anders Sandvig    16 年前

    我通常用 MIME Base64 URL encoding .

        6
  •  5
  •   basszero    16 年前

    尝试对二进制数据进行base64编码/解码。还可以查看CDATA部分

        7
  •  4
  •   mercutio    16 年前

    也许把它们编码成一个已知的集合——比如base 64是一个流行的选择。

        8
  •  4
  •   Jarek Przygódzki    14 年前

    任何 binary-to-text encoding 会成功的。我用那种东西

    <data encoding="yEnc>
    <![CDATA[ encoded binary data ]]>
    </data>
    
        9
  •  3
  •   Community CDub    7 年前

    base64开销为33%。

    BaseXML 对于XML1.0 开销只有20% . 但它不是一个标准,只有一个C实现。如果您关心数据大小,请查看它。但是请注意,浏览器倾向于实现压缩,这样就不需要压缩了。

    我是在这个主题的讨论之后开发的: Encoding binary data within XML : alternatives to base64 .

        10
  •  3
  •   Paul Sasik    6 年前

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

    为什么? :由于编码策略base64/63,Uuencode等人编码增加了您需要存储和传输的数据量(开销),大约增加了40%(与Yenc的1-2%相比)。根据您正在编码的内容,40%的开销可能会成为一个问题。


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

        11
  •  2
  •   Andrei Savu    16 年前

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

        12
  •  0
  •   Lie Ryan Bryan    10 年前

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

    传统的解决方案是归档(例如tar)。但是,如果您希望将封闭文档保持为基于文本的格式,或者如果您没有访问文件存档库的权限,那么在电子邮件和HTTP中也有一个标准化方案,该方案在 multipart/* MIME 具有 Content-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方案,是内容ID头的标识符。这个方案的开销将只是mime头。类似的方案也可以用于HTTP响应。当然,在HTTP协议中,您还可以选择将多部分文档发送到单独的请求/响应中。

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

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

    但这有base64开销。