Vita da tecnici

Entries categorized as ‘change encoding’

Java encoding addedum no. 4 xml all’interno dell’xml

Gennaio 22, 2008 · Nessun Commento

Questo è il penultimo dei post che riguarda l’xml encoding e tratta un argomento che si può presentare quando si ha a che fare con delle applicazioni che si basano su scambio di messaggi xml. Capita a volte che le applicazioni message oriented abbiano una struttura a due livelli:

  1. il primo livello di xml trasmette i campi generali (es il mittente, il nome del servizio, il contenuto informativo)
  2. il secondo livello di xml trasmette il contenuto vero proprio ed è rappresentato da un campo del primo livello

Esempio

<message>

<sender>Giovanni</sender>

<service>invio_fattura</service>

<content><![CDATA[

<?xml version="1.0" encoding="ISO-8859-1"?>
<fattura> 	<numero>2</numero>  	<data>20080131</data> ... ...  </fattura>

]]></content>

</message>

Tale strutturazione si usa quando si vuole creare uno scheletro di comunicazione da usare per diversi servizi che vengono chiesti a dei fornitori in tempi diversi. Gli sviluppi successivi possono riutilizzare “l’infrastruttura” di comunicazione e concentrarsi solo sul contenuto senza dover configurare endpoint diversi e “menate varie”.

Una soluzione di questo tipo pone un problema di encoding particolare; infatti per evitare il famoso Invalid byte 2 of 3-byte UTF-8 sequenceed annessi e connessi è necessario capire cosa succede se il messaggio viene trasportato via rete tramite protocollo http.

Il contenuto del tag content è a tutti gli effetti una stringa che, nel caso di cdata non viene toccata (si può inserire il contenuto facendo l’escaping dei caratteri, ma il messaggio diventa molto meno leggibile ad occhio nudo). La domanda da porsi è: se all’interno di CDATA ci sono dei caratteri accentati con che encoding vengono trasmessi?

La risposta è: a priori non è dato saperlo. Eh? Perchè?

Analizziamo il “viaggio” del messaggio; se si usa un web service client (tipo quelli generati da AXIS) abbiamo a disposizione un metodo di un oggetto che, presi i parametri di input, crea un xml e tramite un http client, lo invia “come stringa” (è una semplificazione, ma serve per non perdersi nei dettagli) all’http server. l’http client specifica un encoding nell’header http; il server legge l’encoding e ricostruisce una stringa che rappresenta il messaggio xml. A questo punto sul server il web service può essere implementato tramite un metodo che accetta gli stessi parametri del client (stile AXIS) o viene fornito un albero JDOM, DOM4J o XOM da cui prelevare i dati (stile Spring Web Services). In entrambi i casi il contenuto del campo content è accedibile come stringa. Stringa = sequenza di caratteri per cui non esiste problema di encoding, la conversione byte-caratteri è stata presa in carico dall’http server o dalla libreria che implementa i meccanismi di web service.

Che problemi ci sono allora?

Che il contenuto di content deve essere dato in pasto alla nostra libreria XML preferita che crea un albero o una serie di eventi; ma nell’header del messaggio contenuto in content è specificato un encoding che non ha più alcun legame con l’encoding reale. Tale informazione sull’encoding va ignorata.

Come si fa?

La soluzione l’ho citata nel post precedente: si usa un reader al posto di un input stream.

Ricetta facile e veloce: se dobbiamo dare in pasto ad una libreria xml del contenuto che proviene da una stringa utilizziamo un reader e non un inputstream

Categorie: change encoding · java encoding · xml caratteri accentati · xml encoding

Java encoding addedum no. 3: InputStream vs Reader

Dicembre 4, 2007 · Nessun Commento

In questo articolo porrò le fondamenta di quello che sarà l’argomento di un altro post, l’xml all’interno dell’xml.

Capire la differenza fra Reader ed InputStream è fondamentale se si vuole riuscire ad evitare errori di vario tipo legati all’encoding.

Quel e’ la differenza fra InputStream e Reader?

Il primo ragiona in byte, il secondo in caratteri che tradotto significa: il primo non fa il decoding il secondo sì. (per OutputStream e Writer si applica il concetto complementare di encoding)

La differenza è “tutta” qui. Vediamo cosa significa: se in un programma che tratta XML (dove quindi l’encoding/decoding è richiesto) passo un InputStream cosa fa la libreria(DOM4J per esempio)? Legge la prima riga, il prologo con <?xml cerca l’encoding e costruisce un Reader che trasforma i byte in caratteri secondo le regole del charset. Se invece alla libreria passo un reader, essa comincia  caricare i caratteri senza controllare l’encoding del prologo.

Quindi in un caso il prologo viene letto (e quindi viene fatta una operazione di decoding) nell’altro viene ignorato (il decoding lo ha già fatto il reader).

Sapere che esistono queste due possibilità è molto utile infatti ci sono casi dove il prologo e la relativa informazione sull’encoding deve essere letta (per esempio quando si legge da file system), mentre ce ne sono altri in cui deve essere ignorata (per esempio quando l’xml viene passato come stringa).

Nel prossimo post affronterò l’ulteriore complicazione dell’xml dentro xml, caso che può essere abbastanza frequente nel caso di webservice che si scambiano nessaggi.

Categorie: change encoding · java encoding · xml caratteri accentati · xml encoding

Java encoding addedum no. 1

Ottobre 18, 2007 · Nessun Commento

**If there are some non italian readers that wish to learn more about java encoding please leave a comment in english and I’ll try to post more articles (english readable) on the topic.**

Ho visto che molte delle ricerche che portano al blog hanno le parole chiava java ed encoding. Ho pensato di dedicare qualche post all’argomento.

Il primo e’: Come cambiare encoding ad un file?

Faccio copia ed incolla di un sorgente Java che preso un file con un certo encoding (da specificare esplicitamente)  ne crea una sua versione con un encoding differente.

public class FileReEncoder {

private static final int BUFFER_SIZE=2048;

public static void main(String[] args) throws Exception {
String fileNameIn=”test1″;
String fileNameOut=”test2″;
String encodingIn=”UTF-8″;
String encodingOut=”ISO-8859-1″;
File fileIn=new File(fileNameIn);
if (!fileIn.exists() || !fileIn.canRead()) {
System.err.println(”Il file ” + fileNameIn + ” non esiste o è illeggibile”);
System.exit(-1);
}
FileInputStream fis= new FileInputStream(fileIn);
InputStreamReader reader= new InputStreamReader(fis,Charset.forName(encodingIn));
try {
FileOutputStream fos=new FileOutputStream(fileNameOut);
OutputStreamWriter writer= new OutputStreamWriter(fos, Charset.forName(encodingOut));
try {
char[] bufferChar=new char[BUFFER_SIZE];
int charsRead=0;
while ((charsRead=reader.read(bufferChar))>0) {
writer.write(bufferChar, 0, charsRead);
}
} finally {
writer.close();
}
} finally {
reader.close();
}

}

}

Enjoy!

Se ci sono altre domande o cose che vorreste vedere trattate sull’argomento suggerite pure.

**If there are some non italian readers that wish to learn more about java encoding please leave a comment in english and I’ll try to post more articles (english readable) on the topic.**

Categorie: change encoding · java encoding · xml encoding