Jak osadzasz dane binarne w XML?

107

Mam dwie aplikacje napisane w Javie, które komunikują się ze sobą za pomocą komunikatów XML w sieci. Używam parsera SAX na końcu odbierającym, aby odzyskać dane z wiadomości. Jednym z wymagań jest osadzenie danych binarnych w wiadomości XML, ale SAX tego nie lubi. Czy ktoś wie, jak to zrobić?

AKTUALIZACJA: Mam to, pracując z klasą Base64 z biblioteki kodeków Apache commons , na wypadek, gdyby ktoś inny próbował czegoś podobnego.

Bill the Lizard
źródło

Odpowiedzi:

209

XML jest tak wszechstronny ...

<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 jest jak przemoc - jeśli nie rozwiązuje problemu, oznacza to, że nie używasz go wystarczająco dużo.

EDYTOWAĆ:

BTW: Base64 + CDATA to prawdopodobnie najlepsze rozwiązanie

(EDIT2:
Ktokolwiek mnie upmodowuje, proszę również zmodyfikuj prawdziwą odpowiedź. Nie chcemy, aby jakakolwiek biedna dusza przychodziła tutaj i faktycznie wdrażała moją metodę, ponieważ była najwyżej oceniona na SO, prawda?)

Pon.
źródło
9
Jest to nic innego jak całkowicie haniebne użycie XML, jeśli mówisz poważnie. A jeśli tak nie jest, skąd mają wiedzieć początkujący, którzy nie piszą na wysokim poziomie, a myślą na niskim poziomie?
TheFlash
1
Myślę, że to zabawne. Ale tak, ponownie, użycie rzeczywistego typu danych base64 jest drogą do zrobienia. Dane CData są zbyt ogólne.
Omniwombat
4
Nie wydaje mi się, żeby to było wystarczająco opisowe - być może należałoby użyć „BINARYDIGIT” zamiast skrótu „BIT”? ;-)
Lee Atkinson
Łał. Spowoduje to, że średni plik z zakresem kilobajtów będzie około 230 razy większy :)
Nyerguds
36
Och, do cholery. To był żart. Co ja zrobiłem?!: Thedailywtf.com/Articles/The-HumanReadable-Encryption-Key.aspx
pon.
26

Base64 jest rzeczywiście właściwą odpowiedzią, ale CDATA nie, to w zasadzie mówi: „to może być cokolwiek”, jednak nie może to być byle jakie, muszą to być dane binarne zakodowane w Base64. Schemat XML definiuje binarny Base 64 jako prymitywny typ danych, którego możesz użyć w swoim xsd.

Boris Terzic
źródło
2
Dodatkowy punkt za wzmiankę o xs:base64Binarytypie danych, który jest właściwy do użycia.
Christopher Schultz
14

Miałem ten problem w zeszłym tygodniu. Musiałem serializować plik PDF i wysłać go w pliku XML na serwer.

Jeśli używasz .NET, możesz przekonwertować plik binarny bezpośrednio na ciąg base64 i umieścić go w elemencie XML.

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

Lub istnieje metoda wbudowana bezpośrednio w obiekt XmlWriter. W moim przypadku musiałem uwzględnić przestrzeń nazw typu danych firmy 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();

Ciąg abc wygląda mniej więcej tak:

<?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
źródło
najlepsza odpowiedź, ponieważ mogę skopiować / wkleić Convert.ToBase64String z niego
Eldritch Conundrum
5

Spróbuj kodować / dekodować dane binarne Base64. Zajrzyj także do sekcji CDATA

basszero
źródło
4

Może zakoduj je do znanego zestawu - coś takiego jak baza 64 jest popularnym wyborem.

mercutio
źródło
4

Każde kodowanie binarne na tekst załatwi sprawę. Używam czegoś takiego

<data encoding="yEnc>
<![CDATA[ encoded binary data ]]>
</data>
Jarek Przygódzki
źródło
4

Narzut Base64 wynosi 33%.

BaseXML dla XML1.0 narzut wynosi tylko 20% . Ale to nie jest standard i ma jeszcze tylko implementację C. Sprawdź to, jeśli obawiasz się rozmiaru danych. Należy jednak pamiętać, że przeglądarki mają tendencję do implementowania kompresji, więc jest ona mniej potrzebna.

Opracowałem go po dyskusji w tym wątku: Kodowanie danych binarnych w XML: alternatywy dla base64 .

KrisWebDev
źródło
4

Podczas gdy inne odpowiedzi są w większości w porządku, możesz wypróbować inną, bardziej wydajną przestrzennie metodę kodowania, taką jak yEnc. ( yEnc wikipedia link ) Z yEnc również można uzyskać sumę kontrolną zaraz po wyjęciu z pudełka. Przeczytaj i linki poniżej. Oczywiście, ponieważ XML nie ma natywnego typu yEnc, twój schemat XML powinien zostać zaktualizowany, aby poprawnie opisał zakodowany węzeł.

Dlaczego : Ze względu na strategie kodowania base64 / 63, uuencode et al. kodowanie zwiększa ilość danych (narzut), które musisz przechowywać i przesyłać o około 40% (w porównaniu z 1-2% YEnc). W zależności od tego, co kodujesz, 40% narzut może być / stać się problemem.


yEnc - streszczenie Wikipedii: https://en.wikipedia.org/wiki/YEnc yEnc to schemat kodowania binarnego na tekst służący do przesyłania plików binarnych w wiadomościach w Usenecie lub za pośrednictwem poczty e-mail. ... Dodatkową zaletą yEnc nad poprzednimi metodami kodowania, takimi jak uuencode i Base64, jest dołączenie sumy kontrolnej CRC w celu sprawdzenia, czy zdekodowany plik został dostarczony w stanie nienaruszonym. Wcześniejsze

Jamie
źródło
2
@Jamine, więc czy masz inną alternatywę?
Hunt
Jamie, to może być przyzwoita odpowiedź, biorąc pod uwagę trochę więcej pracy. Usunąłem -1 i dam +1, jeśli się postarasz ... oflaguj mnie, jeśli będziesz kontynuować.
Paul Sasik
Jamie, n / m. Zaktualizowałem twoją odpowiedź i dałem +1, mam nadzieję, że informacje, które pierwotnie chciałeś przekazać. Rzuć okiem i być może dokonaj aktualizacji według własnego uznania. (Od jakiegoś czasu nie byłem aktywny w SO. Fajnie było badać i edytować odpowiedź. Dałem +1, ponieważ po drodze nauczyłem się kilku nowych rzeczy i o to właśnie chodzi ...? Pozdrawiam.)
Paul Sasik
Escapeless może być alternatywą dla yEnc, gdy przewidywalne / stałe obciążenie jest krytyczne.
Ivan Kosarev
2

Możesz także zakodować oryginalne dane binarne. Ten format jest nieco starszy, ale robi to samo, co kodowanie base63.

Andrei Savu
źródło
* kodowanie base63
Luckydonald
0

Jeśli masz kontrolę nad formatem XML, powinieneś odwrócić problem na drugą stronę. Zamiast dołączać binarny plik XML, powinieneś pomyśleć o tym, jak załączyć dokument, który ma wiele części, z których jedna zawiera XML.

Tradycyjnym rozwiązaniem jest archiwum (np. Tar). Ale jeśli chcesz zachować załączony dokument w formacie tekstowym lub jeśli nie masz dostępu do biblioteki archiwizującej pliki, istnieje również ustandaryzowany schemat, który jest często używany w wiadomościach e-mail i HTTP, który jest wieloczęściowy / * MIME z Content-Transfer-Encoding: binarny .

Na przykład, jeśli Twoje serwery komunikują się przez HTTP i chcesz wysłać dokument wieloczęściowy, z których podstawowym jest dokument XML, który odnosi się do danych binarnych, komunikacja HTTP może wyglądać mniej więcej tak:

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

Jak w powyższym przykładzie, XML odwołuje się do danych binarnych w otaczającym go wieloczęściowym przy użyciu cidschematu URI, który jest identyfikatorem nagłówka Content-Id. Narzut tego schematu byłby tylko nagłówkiem MIME. Podobny schemat można również zastosować do odpowiedzi HTTP. Oczywiście w protokole HTTP masz również możliwość wysłania wieloczęściowego dokumentu w osobnym żądaniu / odpowiedzi.

Jeśli chcesz uniknąć zawijania danych w wieloczęściowy, użyj identyfikatora URI danych:

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

Ale to ma narzut na base64.

Lie Ryan
źródło