Como você incorpora dados binários em XML?

107

Tenho dois aplicativos escritos em Java que se comunicam por meio de mensagens XML na rede. Estou usando um analisador SAX na extremidade receptora para obter os dados de volta das mensagens. Um dos requisitos é incorporar dados binários em uma mensagem XML, mas SAX não gosta disso. Alguém sabe como fazer isso?

ATUALIZAÇÃO: eu consegui trabalhar com a classe Base64 da biblioteca de codecs apache commons , caso alguém esteja tentando algo semelhante.

Bill the Lizard
fonte

Respostas:

209

XML é tão versátil ...

<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 é como violência - se não resolver seu problema, você não está usando o suficiente.

EDITAR:

BTW: Base64 + CDATA é provavelmente a melhor solução

(EDIT2:
Quem quer que me atualize, por favor, também atualize a resposta real. Não queremos que nenhum pobre coitado venha aqui e realmente implemente meu método porque foi o melhor classificado no SO, certo?)

Mo.
fonte
9
Isso é nada menos do que um uso totalmente vergonhoso de XML se você estiver falando sério. E se você não for, como os iniciantes que não escrevem em alto nível pensam em baixo nível?
TheFlash
1
Eu achei engraçado. Mas sim, mais uma vez, usar o tipo de dados base64 real é o caminho a percorrer. CData é muito genérico.
Omniwombat
4
Não acho que seja descritivo o suficiente - talvez devêssemos usar 'BINARYDIGIT' em vez da contração 'BIT'? ;-)
Lee Atkinson,
Uau. Isso tornará o arquivo de intervalo de kilobytes médio cerca de 230 vezes maior :)
Nyerguds
36
Oh, pelo amor de Deus. Isso foi uma piada. O que eu fiz?!: Thedailywtf.com/Articles/The-HumanReadable-Encryption-Key.aspx
feira,
26

Base64 é realmente a resposta certa, mas CDATA não é, que é basicamente dizendo: "isso poderia ser qualquer coisa", no entanto, deve não ser apenas coisa, ele tem que ser Base64 codificado dados binários. O esquema XML define o binário Base 64 como um tipo de dados primitivo que você pode usar em seu xsd.

Boris Terzic
fonte
2
Ponto extra para mencionar o xs:base64Binarytipo de dados, que é o tipo certo a ser usado.
Christopher Schultz
14

Tive esse problema na semana passada. Tive que serializar um arquivo PDF e enviá-lo, dentro de um arquivo XML, para um servidor.

Se você estiver usando .NET, poderá converter um arquivo binário diretamente em uma string base64 e colocá-lo dentro de um elemento XML.

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

Ou existe um método embutido no objeto XmlWriter. No meu caso particular, tive que incluir o namespace de tipo de dados da 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();

A string abc se parece com isto:

<?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
fonte
melhor resposta porque posso copiar / colar Convert.ToBase64String a partir dele
Eldritch Conundrum
5

Experimente a codificação / decodificação Base64 de seus dados binários. Veja também as seções CDATA

basszero
fonte
4

Talvez codifique-os em um conjunto conhecido - algo como base 64 é uma escolha popular.

mercutio
fonte
4

A sobrecarga de Base64 é de 33%.

A sobrecarga de BaseXML para XML1.0 é de apenas 20% . Mas não é um padrão e só tem uma implementação em C ainda. Verifique se você está preocupado com o tamanho dos dados. Observe que, no entanto, os navegadores tendem a implementar a compactação para que seja menos necessária.

Eu o desenvolvi após a discussão neste tópico: Codificando dados binários em XML: alternativas para base64 .

KrisWebDev
fonte
4

Embora as outras respostas sejam geralmente boas, você pode tentar outro método de codificação mais eficiente em termos de espaço, como yEnc. ( link da wikipedia do yEnc ) Com o yEnc, você também obtém o recurso de soma de verificação "pronto para uso". Leia os links abaixo. Obviamente, como o XML não tem um tipo yEnc nativo, seu esquema XML deve ser atualizado para descrever adequadamente o nó codificado.

Por quê : Devido às estratégias de codificação base64 / 63, uuencode et al. as codificações aumentam a quantidade de dados (sobrecarga) que você precisa armazenar e transferir em cerca de 40% (contra 1-2% do yEnc). Dependendo do que você está codificando, a sobrecarga de 40% pode ser / se tornar um problema.


yEnc - resumo da Wikipedia: https://en.wikipedia.org/wiki/YEnc yEnc é um esquema de codificação binário para texto para transferir arquivos binários em mensagens na Usenet ou via e-mail. ... Uma vantagem adicional do yEnc sobre os métodos de codificação anteriores, como uuencode e Base64, é a inclusão de uma soma de verificação CRC para verificar se o arquivo decodificado foi entregue intacto.

Jamie
fonte
2
@Jamine então você tem alguma outra alternativa?
Caça de
Jamie, esta pode ser uma resposta decente com um pouco mais de trabalho. Removi meu -1 e irei +1 se você se esforçar ... sinalize-me se você continuar.
Paul Sasik
Jamie, n / m. Atualizei sua resposta e marquei com +1, espero que com informações que você pretendia transmitir originalmente. Dê uma olhada e talvez faça as atualizações conforme achar necessário. (Não sou ativo no SO há algum tempo. Foi divertido pesquisar e editar uma resposta. Marquei com +1 porque ao longo do caminho aprendi algumas coisas novas e é disso que se trata ...? Saúde.)
Paul Sasik
escapeless pode ser uma alternativa ao yEnc quando a sobrecarga previsível / fixa é crítica.
Ivan Kosarev
2

Você também pode UUencode você dados binários originais. Este formato é um pouco mais antigo, mas faz a mesma coisa que a codificação base63.

Andrei Savu
fonte
* codificação base63
luckydonald
0

Se você tem controle sobre o formato XML, deve virar o problema do avesso. Em vez de anexar o XML binário, você deve pensar em como incluir um documento que possui várias partes, uma das quais contém XML.

A solução tradicional para isso é um arquivo (por exemplo, tar). Mas se você deseja manter o seu documento anexo em um formato baseado em texto ou se você não tem acesso a uma biblioteca de arquivamento de arquivos, há também um esquema padronizado que é muito usado em e-mail e HTTP que é multipart / * MIME com Codificação de transferência de conteúdo: binário .

Por exemplo, se seus servidores se comunicam por meio de HTTP e você deseja enviar um documento multipartes, sendo o principal um documento XML que se refere a dados binários, a comunicação HTTP pode ter a seguinte aparência:

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

Como no exemplo acima, o XML se refere aos dados binários na multiparte envolvente usando um cidesquema de URI que é um identificador para o cabeçalho Content-Id. A sobrecarga desse esquema seria apenas o cabeçalho MIME. Um esquema semelhante também pode ser usado para resposta HTTP. Obviamente, no protocolo HTTP, você também tem a opção de enviar um documento multiparte em solicitação / resposta separada.

Se você deseja evitar agrupar seus dados em uma multiparte, use o URI de dados:

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

Mas isso tem a sobrecarga de base64.

Mentira ryan
fonte