Как встраивать двоичные данные в XML?

107

У меня есть два приложения, написанные на Java, которые взаимодействуют друг с другом с помощью сообщений XML по сети. Я использую синтаксический анализатор SAX на принимающей стороне, чтобы вернуть данные из сообщений. Одно из требований - встраивать двоичные данные в сообщение XML, но SAX это не нравится. Кто-нибудь знает как это сделать?

ОБНОВЛЕНИЕ: я получил это, работая с классом Base64 из библиотеки кодеков apache commons , на случай, если кто-то еще пытается что-то подобное.

Билл Ящерица
источник

Ответы:

209

XML настолько универсален ...

<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 подобен насилию: если он не решает вашу проблему, вы используете его недостаточно.

РЕДАКТИРОВАТЬ:

Кстати: Base64 + CDATA, вероятно, лучшее решение

(EDIT2:
Кто бы меня ни обновил, пожалуйста, обновите и настоящий ответ. Мы не хотим, чтобы какая-то бедняжка пришла сюда и фактически реализовала мой метод, потому что он был наивысшим рейтингом в SO, верно?)

Пн.
источник
9
Если серьезно, это не что иное, как совершенно позорное использование XML. А если нет, то как новички, которые не пишут на высоком уровне, думают на низком уровне, знают?
TheFlash 02
1
Я думаю, это забавно. Но да, еще раз, использование фактического типа данных base64 - это путь. CData слишком общий.
Omniwombat
4
Я не думаю, что это достаточно описательно - может быть, лучше использовать «BINARYDIGIT», чем сокращение «BIT»? ;-)
Ли Аткинсон
Вот это да. Это увеличит средний размер файла в килобайтах примерно в 230 раз :)
Нергудс
36
Ох, черт возьми. Это была шутка. Что я сделал?!: Thedailywtf.com/Articles/The-HumanReadable-Encryption-Key.aspx
Пн,
26

Base64 - действительно правильный ответ, а вот CDATA - нет, по сути говоря: «это может быть что угодно», но это не должно быть просто что-то, это должны быть двоичные данные в кодировке Base64. Схема XML определяет двоичный код Base 64 как примитивный тип данных, который вы можете использовать в своем xsd.

Борис Терзич
источник
2
Дополнительный пункт для упоминания xs:base64Binaryтипа данных, который является правильным типом для использования.
Кристофер Шульц
14

У меня была эта проблема только на прошлой неделе. Мне пришлось сериализовать PDF-файл и отправить его внутри XML-файла на сервер.

Если вы используете .NET, вы можете преобразовать двоичный файл непосредственно в строку base64 и вставить его в элемент XML.

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

Или есть метод, встроенный прямо в объект XmlWriter. В моем конкретном случае мне пришлось включить пространство имен типа данных 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();

Строка abc выглядит примерно так:

<?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>
Бакстер Тидвелл
источник
лучший ответ, потому что я могу скопировать / вставить Convert.ToBase64String из него
Eldritch Conundrum
5

Попробуйте кодировать / декодировать ваши двоичные данные Base64. Также загляните в разделы CDATA

басовый
источник
4

Может быть, закодировать их в известный набор - популярный выбор - что-то вроде base 64.

Меркуцио
источник
4

Накладные расходы Base64 составляют 33%.

BaseXML для XML1.0 накладных расходов составляет всего 20% . Но это не стандарт и пока есть только реализация C. Проверьте это, если вас беспокоит размер данных. Обратите внимание, что браузеры, как правило, реализуют сжатие, поэтому в нем меньше необходимости.

Я разработал его после обсуждения в этой теме: Кодирование двоичных данных в XML: альтернативы base64 .

KrisWebDev
источник
4

Хотя другие ответы в основном подходят, вы можете попробовать другой, более экономичный метод кодирования, например yEnc. ( Ссылка на yEnc wikipedia ) С yEnc также можно получить контрольную сумму прямо "из коробки". Читайте и ссылки ниже. Конечно, поскольку XML не имеет собственного типа yEnc, ваша XML-схема должна быть обновлена, чтобы правильно описывать закодированный узел.

Почему : из-за стратегии кодирования base64 / 63, uuencode et al. кодирование увеличивает объем данных (накладные расходы), которые необходимо хранить и передавать, примерно на 40% (по сравнению с 1-2% yEnc). В зависимости от того, что вы кодируете, 40% накладных расходов могут стать проблемой.


yEnc - аннотация Википедии: https://en.wikipedia.org/wiki/YEnc yEnc - это схема кодирования двоичного кода в текст для передачи двоичных файлов в сообщениях в Usenet или по электронной почте. ... Дополнительным преимуществом yEnc перед предыдущими методами кодирования, такими как uuencode и Base64, является включение контрольной суммы CRC для проверки того, что декодированный файл был доставлен без изменений. Взаимодействие с другими людьми

Джейми
источник
2
@ Джамин, а у тебя есть другая альтернатива?
Hunt
Джейми, это могло бы быть достойным ответом, если бы немного поработали. Я удалил свой -1 и получу +1, если вы приложите немного усилий ... отметьте меня, если вы последуете.
Пол Сасик
Джейми, н / м. Я обновил ваш ответ и поставил +1, надеюсь, с информацией, которую вы изначально хотели передать. Взгляните и, возможно, сделайте обновления по своему усмотрению. (Я не был активен в SO в течение некоторого времени. Было весело исследовать и редактировать ответ. Я поставил +1, потому что по пути я узнал пару новых вещей, и в этом все дело ...? Ура.)
Пол Сасик
Escapeless может быть альтернативой yEnc, когда критичны предсказуемые / фиксированные накладные расходы.
Иван Косарев
2

Вы также можете Uuencode исходные двоичные данные. Этот формат немного старше, но выполняет то же самое, что и кодировка base63.

Андрей Саву
источник
* кодировка base63
luckydonald
0

Если у вас есть контроль над форматом XML, вы должны вывернуть проблему наизнанку. Вместо того, чтобы прикреплять двоичный XML, вы должны подумать о том, как заключить документ, состоящий из нескольких частей, одна из которых содержит XML.

Традиционным решением этой проблемы является архив (например, tar). Но если вы хотите сохранить прилагаемый документ в текстовом формате или если у вас нет доступа к библиотеке архивирования файлов, существует также стандартизированная схема, которая широко используется в электронной почте и HTTP, которая является multipart / * MIME с Content-Transfer-Encoding: двоичный .

Например, если ваши серверы обмениваются данными через HTTP, и вы хотите отправить составной документ, основным из которых является XML-документ, который ссылается на двоичные данные, HTTP-связь может выглядеть примерно так:

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

Как и в приведенном выше примере, XML ссылается на двоичные данные во включающем multipart с помощью cidсхемы URI, которая является идентификатором заголовка Content-Id. Накладные расходы этой схемы будут только заголовком MIME. Похожая схема также может использоваться для HTTP-ответа. Конечно, в протоколе HTTP у вас также есть возможность отправить составной документ в отдельный запрос / ответ.

Если вы хотите избежать упаковки данных в составную часть, следует использовать URI данных:

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

Но это накладные расходы base64.

Ли Райан
источник