Come si incorporano dati binari in XML?


107

Ho due applicazioni scritte in Java che comunicano tra loro utilizzando messaggi XML sulla rete. Sto usando un parser SAX all'estremità ricevente per recuperare i dati dai messaggi. Uno dei requisiti è incorporare dati binari in un messaggio XML, ma a SAX non piace. Qualcuno sa come fare questo?

AGGIORNAMENTO: ho ottenuto questo funzionamento con la classe Base64 dalla libreria dei codec di apache commons , nel caso qualcun altro stia provando qualcosa di simile.

Risposte:



209

XML è così versatile ...

<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 è come la violenza: se non risolve il tuo problema, non ne stai utilizzando abbastanza.

MODIFICARE:

BTW: Base64 + CDATA è probabilmente la soluzione migliore

(EDIT2:
Chiunque mi ottimizzi, per favore anche upmod la vera risposta. Non vogliamo che nessuna povera anima venga qui e implementa effettivamente il mio metodo perché era il più alto classificato in SO, giusto?)


9
Questo non è altro che un uso assolutamente vergognoso di XML se sei serio. E se non lo sei, come lo saprebbero i principianti che non scrivono di alto livello-pensiero-basso livello?
TheFlash

1
Penso sia divertente. Ma sì, ancora una volta, utilizzare l'attuale tipo di dati base64 è la strada da percorrere. CData è troppo generico.
Omniwombat

4
Non penso che sia abbastanza descrittivo - forse si dovrebbe usare "BINARYDIGIT" anziché la contrazione "BIT"? ;-)
Lee Atkinson

Wow. Questo renderà il file con intervallo medio di kilobyte circa 230 volte più grande :)
Nyerguds

36
Oh per l'amor del cazzo. Questo era uno scherzo. Cosa ho fatto?!: Thedailywtf.com/Articles/The-HumanReadable-Encryption-Key.aspx
Lun

26

Base64 è davvero la risposta giusta ma CDATA non lo è, in pratica sta dicendo: "questo potrebbe essere qualsiasi cosa", tuttavia deve non essere qualsiasi cosa, deve essere codificato Base64 dati binari. XML Schema definisce il binario Base 64 come un tipo di dati primitivo che puoi usare nel tuo xsd.


2
Punto extra per menzionare il xs:base64Binarytipo di dati, che è il tipo giusto da usare.
Christopher Schultz

14

Ho avuto questo problema solo la scorsa settimana. Ho dovuto serializzare un file PDF e inviarlo, all'interno di un file XML, a un server.

Se stai usando .NET, puoi convertire un file binario direttamente in una stringa base64 e incollarlo all'interno di un elemento XML.

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

In alternativa, esiste un metodo integrato direttamente nell'oggetto XmlWriter. Nel mio caso particolare, ho dovuto includere lo spazio dei nomi del tipo di dati di 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 stringa abc ha un aspetto simile a questo:

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

migliore risposta perché posso copiare / incollare Convert.ToBase64String da esso
Eldritch Conundrum


5

Prova la codifica / decodifica Base64 dei tuoi dati binari. Guarda anche nelle sezioni CDATA


4

Forse codificali in un set noto: qualcosa come la base 64 è una scelta popolare.




4

Mentre le altre risposte sono per lo più a posto, potresti provare un altro metodo di codifica più efficiente in termini di spazio come yEnc. ( yEnc wikipedia link ) Con yEnc ottieni anche la capacità di checksum "fuori dalla scatola". Leggi e link di seguito. Ovviamente, poiché XML non ha un tipo yEnc nativo, il tuo schema XML dovrebbe essere aggiornato per descrivere correttamente il nodo codificato.

Perché : a causa delle strategie di codifica base64 / 63, uuencode et al. le codifiche aumentano la quantità di dati (overhead) che è necessario archiviare e trasferire di circa il 40% (rispetto all'1-2% di yEnc). A seconda di ciò che stai codificando, il 40% di overhead potrebbe essere / diventare un problema.


yEnc - Estratto di Wikipedia: https://en.wikipedia.org/wiki/YEnc yEnc è uno schema di codifica da binario a testo per il trasferimento di file binari nei messaggi su Usenet o tramite e-mail. ... Un ulteriore vantaggio di yEnc rispetto ai metodi di codifica precedenti, come uuencode e Base64, è l'inclusione di un checksum CRC per verificare che il file decodificato sia stato consegnato intatto.


2
@ Jamine quindi hai qualche altra alternativa?
Caccia

Jamie, questa potrebbe essere una risposta decente dato un po 'più di lavoro. Ho rimosso il mio -1 e farò +1 se ci provi ... segnalami se mi segui.
Paul Sasik

Jamie, n / m. Ho aggiornato la tua risposta e ho fatto +1, si spera con le informazioni che avevi intenzione di trasmettere in origine. Dai un'occhiata e magari fai gli aggiornamenti come meglio credi. (Non sono attivo su SO da un po 'di tempo. È stato divertente cercare e modificare una risposta. Ho fatto +1 perché lungo la strada ho imparato un paio di cose nuove ed è di questo che si tratta ...? Saluti.)
Paul Sasik

escapeless può essere un'alternativa a yEnc quando l'overhead prevedibile / fisso è critico.
Ivan Kosarev


0

Se hai il controllo sul formato XML, dovresti capovolgere il problema. Piuttosto che allegare l'XML binario, dovresti pensare a come racchiudere un documento che ha più parti, una delle quali contiene XML.

La soluzione tradizionale a questo è un archivio (ad esempio tar). Ma se vuoi mantenere il tuo documento allegato in un formato basato su testo o se non hai accesso a una libreria di archiviazione di file, c'è anche uno schema standardizzato che viene utilizzato pesantemente nelle e-mail e HTTP che è multipart / * MIME con Content-Transfer-Encoding: binario .

Ad esempio, se i tuoi server comunicano tramite HTTP e desideri inviare un documento in più parti, il principale è un documento XML che fa riferimento a dati binari, la comunicazione HTTP potrebbe essere simile a questa:

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

Come nell'esempio precedente, l'XML fa riferimento ai dati binari nella multiparte che lo racchiude utilizzando uno cidschema URI che è un identificatore dell'intestazione Content-Id. Il sovraccarico di questo schema sarebbe solo l'intestazione MIME. Uno schema simile può essere utilizzato anche per la risposta HTTP. Ovviamente nel protocollo HTTP, hai anche la possibilità di inviare un documento multiparte in una richiesta / risposta separata.

Se vuoi evitare di racchiudere i tuoi dati in una multiparte, devi usare l'URI dei dati:

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

Ma questo ha l'overhead base64.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.