¿Cómo se incrustan datos binarios en XML?

107

Tengo dos aplicaciones escritas en Java que se comunican entre sí mediante mensajes XML a través de la red. Estoy usando un analizador SAX en el extremo receptor para recuperar los datos de los mensajes. Uno de los requisitos es incrustar datos binarios en un mensaje XML, pero a SAX no le gusta esto. ¿Alguien sabe como hacer esto?

ACTUALIZACIÓN: Conseguí que esto funcionara con la clase Base64 de la biblioteca de códec de apache commons , en caso de que alguien más esté intentando algo similar.

Bill el lagarto
fuente

Respuestas:

209

XML es tan versátil ...

<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 es como violencia: si no resuelve su problema, no lo está usando lo suficiente.

EDITAR:

Por cierto: Base64 + CDATA es probablemente la mejor solución

(EDIT2:
Quien me mejore, por favor también actualice la respuesta real. No queremos que ningún pobrecito venga aquí y realmente implemente mi método porque fue el mejor clasificado en SO, ¿verdad?)

Mes.
fuente
9
Esto es nada menos que un uso completamente vergonzoso de XML si es serio. Y si no es así, ¿cómo sabrían los principiantes que no escriben-alto-nivel-piensan-bajo-nivel?
TheFlash
1
Pienso que es divertido. Pero sí, una vez más, usar el tipo de datos base64 real es el camino a seguir. CData es demasiado genérico.
Omniwombat
4
No creo que sea lo suficientemente descriptivo, ¿quizás uno debería usar 'BINARYDIGIT' en lugar de la contracción 'BIT'? ;-)
Lee Atkinson
Guau. Esto hará que el archivo de rango de kilobytes promedio sea aproximadamente 230 veces más grande :)
Nyerguds
36
Oh, por el amor de Dios. Esto fue una broma. ¡¿Qué hice?!: Thedailywtf.com/Articles/The-HumanReadable-Encryption-Key.aspx
Lunes
26

Base 64 es de hecho la respuesta correcta, pero no es CDATA, que está básicamente diciendo: "esto podría ser cualquier cosa", sin embargo, debe no ser sólo algo, tiene que ser codificado base 64 de datos binarios. El esquema XML define el binario Base 64 como un tipo de datos primitivo que puede usar en su xsd.

Boris Terzic
fuente
2
Un punto extra por mencionar el xs:base64Binarytipo de datos, que es el tipo correcto para usar.
Christopher Schultz
14

Tuve este problema la semana pasada. Tuve que serializar un archivo PDF y enviarlo, dentro de un archivo XML, a un servidor.

Si está utilizando .NET, puede convertir un archivo binario directamente en una cadena base64 y pegarlo dentro de un elemento XML.

string base64 = Convert.ToBase64String(File.ReadAllBytes(fileName));

O hay un método integrado directamente en el objeto XmlWriter. En mi caso particular, tuve que incluir el espacio de nombres del tipo de datos de 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();

La cadena abc se ve así:

<?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>
Baxter Tidwell
fuente
la mejor respuesta porque puedo copiar / pegar Convert.ToBase64String desde él
Eldritch Conundrum
5

Pruebe la codificación / decodificación Base64 de sus datos binarios. También busque en las secciones de CDATA

basszero
fuente
4

Tal vez codificarlos en un conjunto conocido; algo como base 64 es una opción popular.

mercutio
fuente
4

La sobrecarga de Base64 es del 33%.

La sobrecarga de BaseXML para XML1.0 es solo del 20% . Pero no es un estándar y solo tiene una implementación en C. Compruébelo si le preocupa el tamaño de los datos. Tenga en cuenta que, sin embargo, los navegadores tienden a implementar la compresión para que sea menos necesaria.

Lo desarrollé después de la discusión en este hilo: Codificación de datos binarios dentro de XML: alternativas a base64 .

KrisWebDev
fuente
4

Si bien las otras respuestas están en su mayoría bien, puede probar otro método de codificación más eficiente en el espacio como yEnc. ( Enlace de wikipedia de yEnc ) Con yEnc también obtenga la capacidad de suma de comprobación "lista para usar". Lea y enlaces a continuación. Por supuesto, debido a que XML no tiene un tipo yEnc nativo, su esquema XML debe actualizarse para describir correctamente el nodo codificado.

Por qué : Debido a las estrategias de codificación base64 / 63, uuencode et al. Las codificaciones aumentan la cantidad de datos (gastos generales) que necesita almacenar y transferir en aproximadamente un 40% (frente al 1-2% de yEnc). Dependiendo de lo que esté codificando, la sobrecarga del 40% podría convertirse en un problema.


yEnc - Resumen de Wikipedia: https://en.wikipedia.org/wiki/YEnc yEnc es un esquema de codificación de binario a texto para transferir archivos binarios en mensajes en Usenet o por correo electrónico. ... Una ventaja adicional de yEnc sobre los métodos de codificación anteriores, como uuencode y Base64, es la inclusión de una suma de comprobación CRC para verificar que el archivo decodificado se haya entregado intacto.

Jamie
fuente
2
@Jamine, ¿tienes alguna otra alternativa?
Caza el
Jamie, esta podría ser una respuesta decente con un poco más de trabajo. Eliminé mi -1 y haré +1 si le das un poco de esfuerzo ... marcame si sigues.
Paul Sasik
Jamie, n / m. Actualicé tu respuesta y hice +1, con suerte con la información que querías transmitir originalmente. Eche un vistazo y quizás haga las actualizaciones que considere oportunas. (No he estado activo en SO por algún tiempo. Fue divertido investigar y editar una respuesta. Hice +1 porque en el camino aprendí un par de cosas nuevas y de eso se trata ...? Saludos).
Paul Sasik
escapeless puede ser una alternativa a yEnc cuando la sobrecarga predecible / fija es crítica.
Ivan Kosarev
2

También puede Uuencode sus datos binarios originales. Este formato es un poco más antiguo, pero hace lo mismo que la codificación base63.

Andrei Savu
fuente
* codificación base63
luckydonald
0

Si tiene control sobre el formato XML, debería darle la vuelta al problema. En lugar de adjuntar el XML binario, debería pensar en cómo adjuntar un documento que tiene varias partes, una de las cuales contiene XML.

La solución tradicional a esto es un archivo (por ejemplo, tar). Pero si desea mantener el documento adjunto en un formato basado en texto o si no tiene acceso a una biblioteca de archivo de archivos, también existe un esquema estandarizado que se usa mucho en correo electrónico y HTTP que es multiparte / * MIME con Codificación de transferencia de contenido: binario .

Por ejemplo, si sus servidores se comunican a través de HTTP y desea enviar un documento de varias partes, siendo el principal un documento XML que se refiere a datos binarios, la comunicación HTTP podría verse así:

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--

Como en el ejemplo anterior, el XML se refiere a los datos binarios en la multiparte adjunta mediante un cid esquema de URI que es un identificador del encabezado Content-Id. La sobrecarga de este esquema sería solo el encabezado MIME. También se puede utilizar un esquema similar para la respuesta HTTP. Por supuesto, en el protocolo HTTP, también tiene la opción de enviar un documento de varias partes en una solicitud / respuesta separada.

Si desea evitar envolver sus datos en una multiparte es usar URI de datos:

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

Pero esto tiene la sobrecarga de base64.

Mentira Ryan
fuente