Wie bettet man Binärdaten in XML ein?

107

Ich habe zwei in Java geschriebene Anwendungen, die über XML-Nachrichten über das Netzwerk miteinander kommunizieren. Ich verwende einen SAX-Parser am empfangenden Ende, um die Daten aus den Nachrichten zurückzugewinnen. Eine der Anforderungen ist das Einbetten von Binärdaten in eine XML-Nachricht, aber SAX gefällt das nicht. Weiß jemand, wie man das macht?

UPDATE: Ich habe dies mit der Base64- Klasse aus der Apache Commons Codec-Bibliothek zum Laufen gebracht , falls jemand anderes etwas Ähnliches versucht.

Bill die Eidechse
quelle

Antworten:

209

XML ist so vielseitig ...

<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 ist wie Gewalt - Wenn es Ihr Problem nicht löst, verwenden Sie nicht genug davon.

BEARBEITEN:

Übrigens: Base64 + CDATA ist wahrscheinlich die beste Lösung

(EDIT2:
Wer auch immer mich modifiziert, bitte modifiziert auch die wahre Antwort. Wir wollen nicht, dass eine arme Seele hierher kommt und meine Methode tatsächlich umsetzt, weil sie die höchste auf SO war, oder?)

Mo.
quelle
9
Dies ist nichts weniger als eine äußerst schändliche Verwendung von XML, wenn Sie es ernst meinen. Und wenn nicht, wie würden Anfänger, die nicht auf hohem Niveau schreiben, auf niedrigem Niveau denken?
TheFlash
1
Ich finde es lustig. Aber ja, noch einmal, die Verwendung des tatsächlichen base64-Datentyps ist der richtige Weg. CData ist zu allgemein.
Omniwombat
4
Ich denke nicht, dass es beschreibend genug ist - vielleicht sollte man 'BINARYDIGIT' anstelle der Kontraktion 'BIT' verwenden? ;-)
Lee Atkinson
Beeindruckend. Dadurch wird die durchschnittliche Kilobyte-Datei etwa 230-mal größer :)
Nyerguds
36
Oh, verdammt noch mal. Das war ein Witz. Was habe ich getan ?!: Thedailywtf.com/Articles/The-HumanReadable-Encryption-Key.aspx
Mo.
26

Base64 ist in der Tat die richtige Antwort, CDATA jedoch nicht. Das heißt im Grunde: "Dies könnte alles sein", es muss jedoch nicht alles sein, es müssen Base64-codierte Binärdaten sein. Das XML-Schema definiert die Base 64-Binärdatei als primitiven Datentyp, den Sie in Ihrer xsd verwenden können.

Boris Terzic
quelle
2
Zusätzlicher Punkt für die Erwähnung des xs:base64BinaryDatentyps, der der richtige Typ ist.
Christopher Schultz
14

Ich hatte dieses Problem erst letzte Woche. Ich musste eine PDF-Datei serialisieren und in einer XML-Datei an einen Server senden.

Wenn Sie .NET verwenden, können Sie eine Binärdatei direkt in eine base64-Zeichenfolge konvertieren und in ein XML-Element einfügen.

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

Oder es gibt eine Methode, die direkt in das XmlWriter-Objekt integriert ist. In meinem speziellen Fall musste ich den Datentyp-Namespace von Microsoft einschließen:

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();

Der String abc sieht ungefähr so ​​aus:

<?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
quelle
beste Antwort, weil ich Convert.ToBase64String daraus kopieren / einfügen kann
Eldritch Conundrum
5

Versuchen Sie, Ihre Binärdaten mit Base64 zu codieren / decodieren. Schauen Sie sich auch die CDATA-Abschnitte an

Basszero
quelle
4

Vielleicht codieren Sie sie in einen bekannten Satz - so etwas wie Base 64 ist eine beliebte Wahl.

mercutio
quelle
4

Jede Binär-zu-Text-Codierung reicht aus . Ich benutze so etwas

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

Der Base64-Overhead beträgt 33%.

Der Overhead für BaseXML für XML1.0 beträgt nur 20% . Aber es ist kein Standard und hat noch nur eine C-Implementierung. Probieren Sie es aus, wenn Sie sich mit der Datengröße befassen. Beachten Sie jedoch, dass Browser dazu neigen, die Komprimierung zu implementieren, sodass sie weniger benötigt wird.

Ich habe es nach der Diskussion in diesem Thread entwickelt: Codierung von Binärdaten in XML: Alternativen zu base64 .

KrisWebDev
quelle
4

Während die anderen Antworten meistens in Ordnung sind, können Sie eine andere, platzsparendere Codierungsmethode wie yEnc ausprobieren. ( yEnc wikipedia link ) Mit yEnc erhalten Sie auch die Prüfsummenfunktion "out of the box". Lesen und Links unten. Da XML keinen nativen yEnc-Typ hat, sollte Ihr XML-Schema natürlich aktualisiert werden, um den codierten Knoten ordnungsgemäß zu beschreiben.

Warum : Aufgrund der Codierungsstrategien base64 / 63 haben uuencode et al. Codierungen erhöhen die Datenmenge (Overhead), die Sie zum Speichern und Übertragen benötigen, um ungefähr 40% (gegenüber 1-2% bei yEnc). Je nachdem, was Sie codieren, können 40% Overhead ein Problem sein / werden.


yEnc - Wikipedia-Zusammenfassung: https://en.wikipedia.org/wiki/YEnc yEnc ist ein Binär-Text-Codierungsschema zum Übertragen von Binärdateien in Nachrichten im Usenet oder per E-Mail. ... Ein zusätzlicher Vorteil von yEnc gegenüber früheren Codierungsmethoden wie uuencode und Base64 ist die Aufnahme einer CRC-Prüfsumme, um zu überprüfen, ob die decodierte Datei intakt geliefert wurde. .

Jamie
quelle
2
@Jamine, hast du also eine andere Alternative?
Hunt
Jamie, dies könnte eine anständige Antwort sein, wenn etwas mehr Arbeit geleistet wird. Ich habe meine -1 entfernt und werde +1, wenn Sie sich etwas Mühe geben ... kennzeichnen Sie mich, wenn Sie nachverfolgen.
Paul Sasik
Jamie, n / m. Ich habe Ihre Antwort aktualisiert und + 1ed, hoffentlich mit Informationen, die Sie ursprünglich übermitteln wollten. Werfen Sie einen Blick und nehmen Sie möglicherweise Aktualisierungen vor, wie Sie es für richtig halten. (Ich war seit einiger Zeit nicht mehr auf SO aktiv. Es hat Spaß gemacht, eine Antwort zu recherchieren und zu bearbeiten. Ich habe + 1 geschrieben, weil ich auf dem Weg ein paar neue Dinge gelernt habe und darum geht es ...? Prost.)
Paul Sasik
Escapeeless kann eine Alternative zu yEnc sein, wenn vorhersehbarer / fester Overhead kritisch ist.
Ivan Kosarev
2

Sie können Ihre ursprünglichen Binärdaten auch mit Uuencode versehen . Dieses Format ist etwas älter, funktioniert aber genauso wie die Base63-Codierung.

Andrei Savu
quelle
* Base63-Codierung
Luckydonald
0

Wenn Sie die Kontrolle über das XML-Format haben, sollten Sie das Problem auf den Kopf stellen. Anstatt das binäre XML anzuhängen, sollten Sie darüber nachdenken, wie Sie ein Dokument mit mehreren Teilen einschließen, von denen einer XML enthält.

Die traditionelle Lösung hierfür ist ein Archiv (z. B. Teer). Aber wenn Sie Ihre einschließende Dokument in einem textbasierten Format behalten möchten oder wenn Sie Zugriff auf eine Datei nicht Bibliothek Archivierung haben, gibt es auch ein standardisiertes Schema , das stark in E - Mail verwendet wird und HTTP , die ist multipart / * MIME mit Content-Transfer-Encoding: binär .

Wenn Ihre Server beispielsweise über HTTP kommunizieren und Sie ein mehrteiliges Dokument senden möchten, wobei das primäre ein XML-Dokument ist, das sich auf Binärdaten bezieht, sieht die HTTP-Kommunikation möglicherweise folgendermaßen aus:

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

Wie im obigen Beispiel verweist das XML unter Verwendung eines cidURI-Schemas, das eine Kennung für den Content-ID-Header ist, auf die Binärdaten im umschließenden Multipart . Der Overhead dieses Schemas wäre nur der MIME-Header. Ein ähnliches Schema kann auch für die HTTP-Antwort verwendet werden. Natürlich haben Sie im HTTP-Protokoll auch die Möglichkeit, ein mehrteiliges Dokument in einer separaten Anfrage / Antwort zu senden.

Wenn Sie vermeiden möchten, dass Ihre Daten mehrteilig verpackt werden, verwenden Sie den Daten-URI:

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

Dies hat jedoch den Base64-Overhead.

Lie Ryan
quelle