У меня есть два приложения, написанные на Java, которые обмениваются данными друг с другом с помощью XML-сообщений по сети. Я использую SAX-парсер на принимающей стороне, чтобы получить данные обратно из сообщений. Одним из требований является встраивание двоичных данных в XML-сообщение, но SAX это не нравится. Кто-нибудь знает, как это сделать?
UPDATE: я получил эту работу с классом Base64 из apache commons codec library, если кто-то еще пытается что-то подобное.
Вы можете закодировать двоичные данные с помощью base64 и поместить его в элемент Base64; ниже статья является довольно хорошей по этому вопросу.
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 похож на насилие. Если это не решит вашу проблему, вы не используете его достаточно.
EDIT:
BTW: Base64 + CDATA, вероятно, лучшее решение
(EDIT2:
Кто бы ни передумал, пожалуйста, также поднимите настоящий ответ. Мы не хотим, чтобы какая-нибудь бедная душа приходила сюда и действительно применяла мой метод, потому что она была наивысшей оценкой на SO, верно?)
Base64 действительно правильный ответ, но CDATA не является, в основном говоря: "это может быть что угодно", однако оно должно не быть чем угодно, оно должно быть двоичными данными, закодированными в Base64. XML Schema определяет Base 64 двоичный как примитивный тип данных, который вы можете использовать в своем xsd.
xs:base64Binary
, который является правильным типом для использования.
У меня была эта проблема только на прошлой неделе. Мне пришлось сериализовать 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>
Я обычно кодирую двоичные данные MIME Base64 или URL-кодирование.
Попробуйте Base64 кодировать/декодировать ваши двоичные данные. Также просмотрите разделы CDATA
Любое двоично-текстовое кодирование будет делать трюк. Я использую что-то вроде этого
<data encoding="yEnc>
<![CDATA[ encoded binary data ]]>
</data>
Может быть, закодировать их в известном наборе - что-то вроде базы 64 является популярным выбором.
Накладные расходы Base64 составляют 33%.
BaseXML для служебных сообщений XML1.0 составляет всего 20%. Но это не стандарт и еще только реализация C. Проверьте это, если вы заинтересованы в размере данных. Обратите внимание, что, однако, браузеры, как правило, реализуют сжатие, поэтому он менее необходим.
Я разработал его после обсуждения в этой теме: Кодирование двоичных данных в XML: альтернативы base64.
Хотя остальные ответы в основном хороши, вы можете попробовать другой, более экономичный способ кодирования, например, yEnc. (ссылка yEnc на Википедию) С помощью yEnc вы также можете получить контрольную сумму прямо из коробки. Читайте и ссылки ниже. Конечно, поскольку XML не имеет собственного типа yEnc, ваша XML-схема должна быть обновлена для правильного описания закодированного узла.
Почему: из-за стратегий кодирования base64/63, uuencode et al. Кодировки увеличивают объем данных (накладные расходы), которые необходимо хранить и передавать, примерно на 40% (против YEnc на 1-2%). В зависимости от того, что вы кодируете, 40% накладных расходов могут стать/стать проблемой.
yEnc - аннотация в Википедии: https://en.wikipedia.org/wiki/YEnc. yEnc - это схема кодирования двоичных текстов для передачи двоичных файлов в сообщениях на Usenet или по электронной почте.... Дополнительным преимуществом yEnc перед предыдущими методами кодирования, такими как uuencode и Base64, является включение контрольной суммы CRC для проверки того, что декодированный файл был доставлен без изменений.
Вы также можете Uuencode исходные двоичные данные. Этот формат немного старше, но он делает то же самое, что и base63.
Если у вас есть контроль над 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, используя схему URI cid
, которая является идентификатором заголовка Content-Id. Накладные расходы этой схемы будут только заголовком MIME. Аналогичную схему можно также использовать для ответа HTTP. Конечно, в протоколе HTTP вы также можете отправить многостраничный документ в отдельный запрос/ответ.
Если вы хотите избежать обертывания ваших данных в multipart, необходимо использовать URI данных:
<myxml>
<data href="data:application/something;charset=utf-8;base64,dGVzdGRhdGE="/>
</myxml>
Но у этого есть накладные расходы base64.