2011-02-04 17 views
16

Qualcuno sa di un buon tutorial (o di un buon esempio) per scrivere XML usando il framework SAX (o qualcosa di simile) e Java? La ricerca ha prodotto molto poco in termini di risultati utili. Sto cercando di esportare da un'app per Android e sto cercando di evitare il maggior carico di memoria possibile.Generazione di XML tramite SAX e Java

+0

SAX è un parser, non genera nulla :) – bestsss

+0

A meno che non si vuole assolutamente usa SAX (che può occasionalmente accadere quando si elaborano le pipeline), forse potresti chiedere in termini più generici, cioè, cosa stai cercando di ottenere, al contrario di "come faccio a usare questo strumento"? – StaxMan

+2

Quello che sto veramente cercando è generare XML con il minimo sovraccarico di memoria possibile. Ho visto alcuni esempi usando il framework SAX, ma nulla di abbastanza concreto per un newb Java come me da trovare utile. – Lunchbox

risposta

14

C'è una tecnica molto utile per generare XML direttamente dal POJO tramite il quadro SAX (non un parser SAX, ma la Quadro SAX). Questa tecnica può essere utilizzata per generare un documento XML.

Generazione di XML da una struttura arbitraria dati
http://download.oracle.com/javaee/1.4/tutorial/doc/JAXPXSLT5.html

In sostanza, si aggiungono i metodi per il tuo POJO o scrivere classe di utilità per i vostri POJO che li trasformano in emettitori di eventi SAX (che emettono gli eventi come un parser SAX normalmente sarebbe quando parsing di un documento XML). Ora il vostro "generatore di eventi SAX" appare come il lato di output di un parser SAX e può essere fornito a qualsiasi gestore di contenuto che un parser SAX prenderebbe, come uno che stampa pretyy XML. Ma potrebbe anche essere inviato a un parser DOM per generare un albero DOM o un feed a un motore XSLT per generare HTML o eseguire una traduzione XSL vera senza dover prima generare un documento XML intermedio dai POJO.

Ad esempio, una classe persona potrebbe avere un metodo emitXML() che includono queste righe:

handler.startElement(nsu, PERSON_TAG, PERSON_TAG, NO_ATTRIBUTES); 

handler.startElement(nsu, FIRSTNAME_TAG, FIRSTNAME_TAG, atts); 
handler.characters(this.firstName.toCharArray(), 
     0, 
     this.firstName.length()); 
handler.endElement(nsu, FIRSTNAME_TAG, FIRSTNAME_TAG); 

... emit more instance variables 

... emit child object like: homeAddress.emitXML(handler, ...); 

handler.endElement(nsu, PERSON_TAG, PERSON_TAG); 

Aggiornamento:

Un paio di altri riferimenti:


Un paio di risposte alle osservazioni:

Questo è vero, ma l'interfaccia XMLStreamWriter sopra descritto è molto più user -friendly.- Michael Kay 3 ore fa

Sì, ma suppongo di non essere stato chiaro. Potrei facilmente attraversare la gerarchia e usare XMLStreamWriter per generare direttamente un documento XML su uno stream. Tuttavia, gli articoli mostrano una potente tecnica per attraversare la gerarchia e generare eventi SAX, invece di emettere direttamente un documento XML. Ora posso inserire gestori di contenuti diversi che fanno cose diverse o generano versioni diverse dell'XML. Potremmo anche alimentare la nostra gerarchia di oggetti con qualsiasi strumento che abbia accettato un parser SAX, come un motore XSLT. In realtà sta solo sfruttando il modello di visitatore stabilito dal framework SAX: separiamo la gerarchia dall'output dell'XML. Le parti che generano l'XML, i gestori di contenuto, dovrebbero certamente usare uno XMLStreamWriter se il loro scopo è scrivere un flusso XML.

Ad esempio, sul nostro programma, abbiamo inviato messaggi XML su socket di rete tra componenti distribuiti e abbiamo anche utilizzato XSLT per generare le nostre pagine HTML. Precedentemente, abbiamo attraversato la nostra gerarchia per generare un documento XML (una stringa) e poi abbiamo scritto quel documento XML su un socket di rete o abbiamo alimentato quel documento al motore XSLT (che essenzialmente lo ha solo analizzato di nuovo). Dopo aver utilizzato questa tecnica, è possibile alimentare essenzialmente la gerarchia degli oggetti (utilizzando questo adattatore SAX) direttamente sul motore XSLT senza la stringa XML intermedia. Era anche comodo poter usare un gestore di contenuti per generare una rappresentazione XML compatta per il flusso di rete e usarne uno diverso per generare un documento XML piuttosto stampato da scrivere in un file di registro.

Inoltre, l'utilizzo dell'API parser SAX per scrivere XML è un uso improprio dell'API, IMHO. - Puce 49 minuti fa

Forse, ma penso che dipenda dai vostri bisogni. Se il requisito dell'OP è solo quello di scrivere un documento XML specifico, allora questo è decisamente eccessivo. Tuttavia, ho pensato che valesse la pena di menzionare se l'OP utilizza l'XML in altri modi sul suo progetto che non ha menzionato. Non c'è nulla di male nel lanciare un'idea alternativa.

Chiamarlo uso improprio potrebbe essere un po 'forte, ma sono d'accordo che hai diritto alla tua opinione. È documentato in un tutorial Oracle, quindi non è considerato un abuso da parte degli ingegneri Sun/Oracle. Abbiamo avuto molto successo nel nostro progetto per aiutarci a soddisfare i nostri requisiti senza aspetti negativi significativi, quindi terrò questo approccio nella mia casella degli strumenti per quando sarà utile in futuro.

+3

Questo è vero, ma l'interfaccia XMLStreamWriter descritta sopra è molto più user-friendly. –

+0

Inoltre, l'utilizzo dell'API parser SAX per scrivere XML è un uso improprio dell'API, IMHO. – Puce

+1

@ Michael Kay - Grazie per il tuo commento. Ho provato a chiarire in una modifica sopra. –

32

L'analisi SAX è per la lettura di documenti, non la scrittura.

È possibile scrivere XML con la XMLStreamWriter:

OutputStream outputStream = new FileOutputStream(new File("doc.xml")); 

XMLStreamWriter out = XMLOutputFactory.newInstance().createXMLStreamWriter(
       new OutputStreamWriter(outputStream, "utf-8")); 

out.writeStartDocument(); 
out.writeStartElement("doc"); 

out.writeStartElement("title"); 
out.writeCharacters("Document Title"); 
out.writeEndElement(); 

out.writeEndElement(); 
out.writeEndDocument(); 

out.close(); 
+0

Mi piace questa risposta, purtroppo quel pacchetto non è disponibile in Android. Colpa mia per non averlo menzionato. D: – Lunchbox

+2

Ok, puoi anche semplicemente stampare l'XML manualmente. 'out.print (" valore ");' ecc. Ma è necessario assicurarsi di evitare i valori correttamente. Questo potrebbe essere fatto con apache commons 'StringEscapeUtils.escapeXML()'. O qualche altro metodo. Dipende dai valori possibili, forse potresti farlo con regex. – morja

5

Qui di seguito le risposte "un buon tutorial per la scrittura di XML utilizzando il parser SAX e Java" parte della domanda

non sono sicuro se si hanno attraversato questo. Ma mi piace molto lo Java's Really Big Index of Everything.

passare attraverso questo: http://download.oracle.com/javase/tutorial/jaxp/index.html

E alla fine, in questo modo: http://download.oracle.com/javase/tutorial/jaxp/sax/index.html

+0

Grazie Nishant. Questa è un'informazione completa! Questo è quello che stavo cercando. – simpleDev

3

Considerare anche JAXB per scrivere/leggere XML.

4

Si prega di fare riferimento al mio post blog personale: XML Generation In Java - in particolare, The SAX method. Fa riferimento ad alcuni altri articoli relativi a questo, fornisce un esempio concreto e confronta SAX con le altre API popolari per la generazione di XML da Java.

(Realizzato questa è una domanda più vecchia, ma sentivo necessario aggiungere questo per chiunque altro possa avere la stessa domanda.)

1

È possibile anche ponte per trax con questo:

public abstract class PipedSAXSource extends SAXSource { 
    protected PipedSAXSource() { 
    setXMLReader(new CallWriteDuringSax()); 
    } 

    protected abstract void writeTo(ContentHandler sink) 
     throws IOException, SAXException; 

    private class CallWriteDuringSax extends XMLFilterImpl { 
    @Override 
    public void parse(InputSource ignored) throws IOException, SAXException { 
     writeTo(getContentHandler()); 
    } 

    @Override 
    public void setFeature(String name, boolean value) {} 
    } 
} 

Usa in questo modo:

public static void main(String[] args) throws Exception { 
    Source in = new PipedSAXSource() { 
     @Override 
     protected void writeTo(ContentHandler sink) throws SAXException { 
     sink.startDocument(); 

     sink.startElement("", "root", "root", new AttributesImpl()); 
     sink.endElement("", "root", "root"); 

     sink.endDocument(); 
     } 
    }; 

    Transformer identity = TransformerFactory.newInstance().newTransformer(); 
    identity.transform(in, new StreamResult(System.out)); 
    }