Domanda

Ho un oggetto di cui viene effettuato il marshalling in XML utilizzando JAXB.Un elemento contiene una stringa che include virgolette (").L'XML risultante ha " dove " esisteva.

Anche se questo è normalmente preferito, ho bisogno che il mio output corrisponda a a eredità sistema.Come faccio a forzare JAXB a NON convertire le entità HTML?

--

Grazie per le risposteTuttavia, non vedo mai il gestore escape() chiamato.Puoi dare un'occhiata e vedere cosa sto facendo di sbagliato?Grazie!

package org.dc.model;

import java.io.IOException;
import java.io.Writer;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import org.dc.generated.Shiporder;

import com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler;

public class PleaseWork {
    public void prettyPlease() throws JAXBException {
        Shiporder shipOrder = new Shiporder();
        shipOrder.setOrderid("Order's ID");
        shipOrder.setOrderperson("The woman said, \"How ya doin & stuff?\"");

        JAXBContext context = JAXBContext.newInstance("org.dc.generated");
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        marshaller.setProperty(CharacterEscapeHandler.class.getName(),
                new CharacterEscapeHandler() {
                    @Override
                    public void escape(char[] ch, int start, int length,
                            boolean isAttVal, Writer out) throws IOException {
                        out.write("Called escape for characters = " + ch.toString());
                    }
                });
        marshaller.marshal(shipOrder, System.out);
    }

    public static void main(String[] args) throws Exception {
        new PleaseWork().prettyPlease();
    }
}

--

L'output è questo:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<shiporder orderid="Order's ID">
    <orderperson>The woman said, &quot;How ya doin &amp; stuff?&quot;</orderperson>
</shiporder>

e come puoi vedere, la richiamata non viene mai visualizzata.(Una volta che ricevo la richiamata, mi preoccuperò di fargli effettivamente fare quello che voglio.)

--

È stato utile?

Soluzione

SOLUZIONE ha trovato il mio compagno di squadra:

PrintWriter printWriter = new PrintWriter(new FileWriter(xmlFile));
DataWriter dataWriter = new DataWriter(printWriter, "UTF-8", DumbEscapeHandler.theInstance);
marshaller.marshal(request, dataWriter);

Invece di passare XMLfile a Marshal (), passa il datawriter che conosce sia la codifica che un gestore di fuga appropriato, se presente.

Nota: poiché DataWriter e DumbescapeHandler sono entrambi all'interno del pacchetto com.sun.xml.internal.bind.marshaller, è necessario bootstrap javac.

Altri suggerimenti

Ho appena fatto il mio gestore personalizzato come una lezione come questa:

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;

import com.sun.xml.bind.marshaller.CharacterEscapeHandler;

public class XmlCharacterHandler implements CharacterEscapeHandler {

    public void escape(char[] buf, int start, int len, boolean isAttValue,
            Writer out) throws IOException {
        StringWriter buffer = new StringWriter();

        for (int i = start; i < start + len; i++) {
            buffer.write(buf[i]);
        }

        String st = buffer.toString();

        if (!st.contains("CDATA")) {
            st = buffer.toString().replace("&", "&amp;").replace("<", "&lt;")
                .replace(">", "&gt;").replace("'", "&apos;")
                .replace("\"", "&quot;");

        }
        out.write(st);
        System.out.println(st);
    }

}

Nel metodo Marshaller chiama semplicemente:

marshaller.setProperty(CharacterEscapeHandler.class.getName(),
                new XmlCharacterHandler());

funziona bene.

Ho giocato un po 'con il tuo esempio e il debug del codice JAXB. E sembra che sia qualcosa di specifico sulla codifica UTF-8 utilizzata. La proprietà di EscapeHandler di MarshallerImpl sembra essere impostato correttamente. Tuttavia viene utilizzato non in ogni contesto. Se ho cercato chiamate di MarshallerImpl.createEscapeHandler() Ho trovato:

public XmlOutput createWriter( OutputStream os, String encoding ) throws JAXBException {
    // UTF8XmlOutput does buffering on its own, and
    // otherwise createWriter(Writer) inserts a buffering,
    // so no point in doing a buffering here.

    if(encoding.equals("UTF-8")) {
        Encoded[] table = context.getUTF8NameTable();
        final UTF8XmlOutput out;
        if(isFormattedOutput())
            out = new IndentingUTF8XmlOutput(os,indent,table);
        else {
            if(c14nSupport)
                out = new C14nXmlOutput(os,table,context.c14nSupport);
            else
                out = new UTF8XmlOutput(os,table);
        }
        if(header!=null)
            out.setHeader(header);
        return out;
    }

    try {
        return createWriter(
            new OutputStreamWriter(os,getJavaEncoding(encoding)),
            encoding );
    } catch( UnsupportedEncodingException e ) {
        throw new MarshalException(
            Messages.UNSUPPORTED_ENCODING.format(encoding),
            e );
    }
}

Nota che nella tua configurazione la sezione superiore (...equals("UTF-8")...) è preso in considerazione. Tuttavia questo non prende il escapeHandler. Tuttavia, se si imposta la codifica su qualsiasi altro, viene chiamata la parte inferiore di questo metodo (createWriter(OutputStream, String)) e questo usa escapeHandler, quindi EH gioca il suo ruolo. Quindi, aggiungendo ...

    marshaller.setProperty(Marshaller.JAXB_ENCODING, "ASCII");

rende la tua abitudine CharacterEscapeHandler essere chiamato. Non sono davvero sicuro, ma immagino che questo sia una specie di bug in Jaxb.

@Elliot Puoi usarlo per consentire a Marshaller di inserire la funzione di caratteristiche. È strano ma funziona se si imposta "Unicode"Invece di" UTF-8 ". Aggiungilo poco prima o dopo aver impostato la proprietà di caratteristiche.

marshaller.setProperty(Marshaller.JAXB_ENCODING, "Unicode");

Tuttavia Non essere sicuro solo controllando la tua console All'interno del tuo IDE, perché dovrebbe essere mostrato dipende dalla codifica dell'area di lavoro. È meglio controllarlo anche da un file del genere:

marshaller.marshal(shipOrder, new File("C:\\shipOrder.txt"));

Direi che il modo più semplice per fare è prevalere CharacterEscapeHandler :

marshaller.setProperty("com.sun.xml.bind.characterEscapeHandler", new CharacterEscapeHandler() {
    @Override
    public void escape(char[] ch, int start, int length, boolean isAttVal,
                       Writer out) throws IOException {
        out.write(ch, start, length);
    }
});

Ho trovato lo stesso problema che ho risolto questo usando XMLWriter nel file XMLWriter Esiste un metodo isEScapeText () e SeteScapeTest che è per impostazione predefinita se non si desidera trasformazione tra <a <quel tempo è necessario per SeteScapeTest (false); Durante la marshalling

JAXBContext jaxbContext = JAXBContext.newInstance(your class);
Marshaller marshaller = jaxbContext.createMarshaller();

marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

// Create a filter that will remove the xmlns attribute
NamespaceFilter outFilter = new NamespaceFilter(null, false);

// Do some formatting, this is obviously optional and may effect
// performance
OutputFormat format = new OutputFormat();
format.setIndent(true);
format.setNewlines(true);

// Create a new org.dom4j.io.XMLWriter that will serve as the
// ContentHandler for our filter.
XMLWriter writer = new XMLWriter(new FileOutputStream(file), format);
writer.setEscapeText(false); // <----------------- this line
// Attach the writer to the filter
outFilter.setContentHandler(writer);
// marshalling
marshaller.marshal(piaDto, outFilter);
marshaller.marshal(piaDto, System.out);

questo cambiamento writer.seteScapeText (false); Risolto il mio problema, spero che questo cambi utili a te

Sembra che sia possibile con Implementazione di JAXB di Sun, anche se non l'ho fatto da solo.

Ho controllato la specifica XML. http://www.w3.org/TR/REC-xml/#sec-references afferma che "i documenti ben formati non devono dichiarare nessuna delle seguenti entità:amp, lt, gt, apos, quot." quindi sembra che il parser XML utilizzato dal sistema legacy non sia conforme.

(So ​​che non risolve il tuo problema, ma almeno è bello poter dire quale componente è rotto).

Questo funziona per me dopo aver letto altri post:

javax.xml.bind.JAXBContext jc = javax.xml.bind.JAXBContext.newInstance(object);
marshaller = jc.createMarshaller();         marshaller.setProperty(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(javax.xml.bind.Marshaller.JAXB_ENCODING, "UTF-8");                   marshaller.setProperty(CharacterEscapeHandler.class.getName(), new CustomCharacterEscapeHandler());


public static class CustomCharacterEscapeHandler implements CharacterEscapeHandler {
        /**
         * Escape characters inside the buffer and send the output to the Writer.
         * (prevent <b> to be converted &lt;b&gt; but still ok for a<5.)
         */
        public void escape(char[] buf, int start, int len, boolean isAttValue, Writer out) throws IOException {
            if (buf != null){
                StringBuilder sb = new StringBuilder();
                for (int i = start; i < start + len; i++) {
                    char ch = buf[i];

                    //by adding these, it prevent the problem happened when unmarshalling
                    if (ch == '&') {
                        sb.append("&amp;");
                        continue;
                    }

                    if (ch == '"' && isAttValue) {
                        sb.append("&quot;");
                        continue;
                    }

                    if (ch == '\'' && isAttValue) {
                        sb.append("&apos;");
                        continue;
                    }


                    // otherwise print normally
                    sb.append(ch);
                }

                //Make corrections of unintended changes
                String st = sb.toString();

                st = st.replace("&amp;quot;", "&quot;")
                       .replace("&amp;lt;", "&lt;")
                       .replace("&amp;gt;", "&gt;")
                       .replace("&amp;apos;", "&apos;")
                       .replace("&amp;amp;", "&amp;");

                out.write(st);
            }
        }
    }

interessante ma con le corde puoi provare

Marshaller marshaller = jaxbContext.createMarshaller();
StringWriter sw = new StringWriter();
marshaller.marshal(data, sw);
sw.toString();

Almeno per me questo non sfuggire alle citazioni

Il modo più semplice, quando si utilizzano l'implementazione di Marshaller di Sun è fornire la propria implementazione del caratteristica che non sfugge a nulla.

    Marshaller m = jcb.createMarshaller();
m.setProperty(
    "com.sun.xml.bind.marshaller.CharacterEscapeHandler",
    new NullCharacterEscapeHandler());

Insieme a

public class NullCharacterEscapeHandler implements CharacterEscapeHandler {

    public NullCharacterEscapeHandler() {
        super();
    }


    public void escape(char[] ch, int start, int length, boolean isAttVal, Writer writer) throws IOException {
        writer.write( ch, start, length );
    }
}

Per qualche motivo non ho tempo per scoprirlo, ha funzionato per me durante l'impostazione

marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");

Al contrario all'uso "UTF-8" o "Unicode"

Ti suggerisco di provarli e come @Javatar ha detto, controllali dumping su file usando:

marshaller.marshal(shipOrder, new File("<test_file_path>"));

e aprendolo con un editor di testo decente come Notepad ++

Consiglierei di usare CharacterEscapeHandler Per i motivi sopra menzionati (è una classe interna). Invece puoi usare Woodstox e fornisci il tuo EscapingWriterFactory a a XMLStreamWriter. Qualcosa di simile a:

XMLOutputFactory2 xmlOutputFactory = (XMLOutputFactory2)XMLOutputFactory.newFactory();
xmlOutputFactory.setProperty(XMLOutputFactory2.P_TEXT_ESCAPER, new EscapingWriterFactory() {

    @Override
    public Writer createEscapingWriterFor(Writer w, String enc) {
        return new EscapingWriter(w);
    }

    @Override
    public Writer createEscapingWriterFor(OutputStream out, String enc) throws UnsupportedEncodingException {
        return new EscapingWriter(new OutputStreamWriter(out, enc));
    }

});

marshaller.marshal(model, xmlOutputFactory.createXMLStreamWriter(out);

Un esempio di come scrivere un EscapingWriter può essere visto in Caratteristica.

Dopo aver provato tutte le soluzioni di cui sopra, finalmente arrivò alla conclusione.

La tua logica di maresciallo attraverso il gestore di fuga personalizzato.

final StringWriter sw = new StringWriter();
    final Class classType = fixml.getClass();
    final JAXBContext jaxbContext = JAXBContext.newInstance(classType);
    final Marshaller marshaller = jaxbContext.createMarshaller();
    final JAXBElement<T> fixmsg = new JAXBElement<T>(new QName(namespaceURI, localPart), classType, fixml);
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    marshaller.setProperty(CharacterEscapeHandler.class.getName(), new JaxbCharacterEscapeHandler());
    marshaller.marshal(fixmsg, sw);
    return sw.toString();

E il gestore di fuga personalizzato è il seguente:

import java.io.IOException;
import java.io.Writer;

public class JaxbCharacterEscapeHandler implements CharacterEscapeHandler {

    public void escape(char[] buf, int start, int len, boolean isAttValue,
                    Writer out) throws IOException {

            for (int i = start; i < start + len; i++) {
                    char ch = buf[i];
                    out.write(ch);
            }
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top