Comment intégrez-vous des données binaires dans XML?

107

J'ai deux applications écrites en Java qui communiquent entre elles à l'aide de messages XML sur le réseau. J'utilise un analyseur SAX à la réception pour récupérer les données des messages. L'une des conditions requises est d'incorporer des données binaires dans un message XML, mais SAX n'aime pas cela. Est-ce que quelqu'un sait comment faire ça?

MISE À JOUR: Je l'ai fait fonctionner avec la classe Base64 de la bibliothèque de codecs apache commons , au cas où quelqu'un d'autre essaie quelque chose de similaire.

Bill le lézard
la source

Réponses:

209

XML est si polyvalent ...

<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 est comme la violence - S'il ne résout pas votre problème, vous n'en utilisez pas assez.

ÉDITER:

BTW: Base64 + CDATA est probablement la meilleure solution

(EDIT2:
Quiconque me modifie, s'il vous plaît, modifiez également la vraie réponse. Nous ne voulons pas qu'une pauvre âme vienne ici et mette en œuvre ma méthode parce qu'elle était la mieux classée sur SO, non?)

Mo.
la source
9
Ce n'est rien de moins qu'une utilisation complètement honteuse de XML si vous êtes sérieux. Et si vous ne l'êtes pas, comment les débutants qui n'écrivent pas de haut niveau pensent de bas niveau le sauraient?
TheFlash
1
Je trouve ça drôle. Mais oui, encore une fois, utiliser le type de données base64 réel est la voie à suivre. CData est trop générique.
Omniwombat
4
Je ne pense pas que ce soit assez descriptif - peut-être devrait-on utiliser «BINARYDIGIT» plutôt que la contraction «BIT»? ;-)
Lee Atkinson
Sensationnel. Cela rendra le fichier de plage de kilo-octets moyen environ 230 fois plus grand :)
Nyerguds
36
Oh pour le plaisir. C'était une blague. Qu'est-ce que j'ai fait?!: Thedailywtf.com/Articles/The-HumanReadable-Encryption-Key.aspx
Mo.
26

Base64 est en effet la bonne réponse mais CDATA ne l'est pas, c'est dire en gros: "cela pourrait être n'importe quoi", mais ce ne doit pas être n'importe quoi, il doit s'agir de données binaires encodées en Base64. XML Schema définit le binaire Base 64 comme un type de données primitif que vous pouvez utiliser dans votre xsd.

Boris Terzic
la source
2
Point supplémentaire pour mentionner le xs:base64Binarytype de données, qui est le bon type à utiliser.
Christopher Schultz
14

J'ai eu ce problème la semaine dernière. J'ai dû sérialiser un fichier PDF et l'envoyer, dans un fichier XML, à un serveur.

Si vous utilisez .NET, vous pouvez convertir un fichier binaire directement en une chaîne base64 et le coller dans un élément XML.

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

Ou, il existe une méthode intégrée directement dans l'objet XmlWriter. Dans mon cas particulier, j'ai dû inclure l'espace de noms de type de données 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 chaîne abc ressemble à quelque chose qui ressemble à ceci:

<?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
la source
meilleure réponse parce que je peux copier / coller Convert.ToBase64String à partir de celui
Eldritch Conundrum
5

Essayez d'encoder / décoder vos données binaires en Base64. Regardez également dans les sections CDATA

basszero
la source
4

Peut-être les encoder dans un ensemble connu - quelque chose comme la base 64 est un choix populaire.

mercutio
la source
4

Tout encodage binaire en texte fera l'affaire. J'utilise quelque chose comme ça

<data encoding="yEnc>
<![CDATA[ encoded binary data ]]>
</data>
Jarek Przygódzki
la source
4

La surcharge en base64 est de 33%.

La surcharge de BaseXML pour XML1.0 n'est que de 20% . Mais ce n'est pas une norme et n'a encore qu'une implémentation C. Vérifiez-le si vous êtes préoccupé par la taille des données. Notez cependant que les navigateurs ont tendance à implémenter la compression afin qu'elle soit moins nécessaire.

Je l'ai développé après la discussion dans ce fil: Encodage de données binaires dans XML: alternatives à base64 .

KrisWebDev
la source
4

Bien que les autres réponses soient généralement bonnes, vous pouvez essayer une autre méthode d'encodage plus efficace en termes d'espace, telle que yEnc. ( lien wikipedia yEnc ) Avec yEnc, obtenez également la capacité de somme de contrôle dès la sortie de la boîte. Lisez et liens ci-dessous. Bien sûr, étant donné que XML n'a pas de type yEnc natif, votre schéma XML doit être mis à jour pour décrire correctement le nœud encodé.

Pourquoi : En raison des stratégies de codage base64 / 63, uuencode et al. les encodages augmentent la quantité de données (surcharge) que vous devez stocker et transférer d'environ 40% (contre 1 à 2% de yEnc). En fonction de ce que vous encodez, une surcharge de 40% pourrait être / devenir un problème.


yEnc - Résumé Wikipédia: https://en.wikipedia.org/wiki/YEnc yEnc est un schéma de codage binaire en texte pour transférer des fichiers binaires dans des messages sur Usenet ou par e-mail. ... Un avantage supplémentaire de yEnc par rapport aux méthodes de codage précédentes, telles que uuencode et Base64, est l'inclusion d'une somme de contrôle CRC pour vérifier que le fichier décodé a été livré intact.

Jamie
la source
2
@Jamine alors avez-vous une autre alternative?
Chasse
Jamie, cela pourrait être une réponse décente avec un peu plus de travail. J'ai supprimé mon -1 et je vais +1 si vous donnez un effort ... signalez-moi si vous suivez.
Paul Sasik
Jamie, n / m. J'ai mis à jour votre réponse et + 1, espérons-le, avec des informations que vous vouliez transmettre à l'origine. Jetez un coup d'œil et effectuez peut-être des mises à jour comme bon vous semble. (Je n'ai pas été actif sur SO depuis un certain temps. C'était amusant de rechercher et de modifier une réponse. J'ai +1 parce qu'en cours de route, j'ai appris quelques nouvelles choses et c'est de ça qu'il s'agit ...? Cheers.)
Paul Sasik
escapeeless peut être une alternative à yEnc lorsque la surcharge prévisible / fixe est critique.
Ivan Kosarev
2

Vous pouvez également Uuencoder vos données binaires originales. Ce format est un peu plus ancien mais il fait la même chose que l'encodage base63.

Andrei Savu
la source
* encodage base63
luckydonald
0

Si vous contrôlez le format XML, vous devez régler le problème à l'envers. Plutôt que de joindre le XML binaire, vous devriez réfléchir à la façon de joindre un document qui a plusieurs parties, dont l'une contient du XML.

La solution traditionnelle à cela est une archive (par exemple tar). Mais si vous souhaitez conserver votre document englobant dans un format texte ou si vous n'avez pas accès à une bibliothèque d'archivage de fichiers, il existe également un schéma standardisé largement utilisé dans les e-mails et HTTP qui est en plusieurs parties / * MIME avec Content-Transfer-Encoding: binaire .

Par exemple, si vos serveurs communiquent via HTTP et que vous souhaitez envoyer un document en plusieurs parties, le principal étant un document XML qui fait référence à des données binaires, la communication HTTP peut ressembler à ceci:

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

Comme dans l'exemple ci-dessus, le XML fait référence aux données binaires dans le multipart englobant en utilisant un cidschéma d'URI qui est un identificateur de l'en-tête Content-Id. La surcharge de ce schéma serait juste l'en-tête MIME. Un schéma similaire peut également être utilisé pour la réponse HTTP. Bien sûr, dans le protocole HTTP, vous avez également la possibilité d'envoyer un document en plusieurs parties dans une requête / réponse distincte.

Si vous souhaitez éviter d'encapsuler vos données dans un multipart, utilisez l'URI de données:

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

Mais cela a la surcharge de base64.

Mensonge Ryan
la source