web-dev-qa-db-fra.com

Puis-je forcer JAXB à ne pas convertir "en", par exemple, lors du marshalling au format XML?

J'ai un objet en cours de conversion en XML à l'aide de JAXB. Un élément contient une chaîne qui inclut des guillemets ("). Le XML résultant a " où le" existait.

Même si cela est généralement préférable, ma sortie doit correspondre à un système legacy . Comment forcer JAXB à NE PAS convertir les entités HTML?

-

Merci pour les réponses. Cependant, je ne vois jamais le gestionnaire escape () appelé. Pouvez-vous regarder et voir ce que je fais mal? Merci!

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();
    }
}

-

La sortie est la suivante:

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

et comme vous pouvez le constater, le rappel n’est jamais affiché. (Une fois que j'aurai reçu le rappel, je n'aurai plus à le faire faire ce que je veux.)

-

24
Elliot

Solution trouvée par mon coéquipier:

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

Au lieu de transmettre le fichier xmlFile à marshal (), transmettez le DataWriter qui connaît à la fois l’encodage et un gestionnaire d’échappement approprié, le cas échéant.

Remarque: DataWriter et DumbEscapeHandler étant tous deux contenus dans le package com.Sun.xml.internal.bind.marshaller, vous devez initialiser javac.

12
Elliot

Je viens de faire mon gestionnaire personnalisé en tant que classe comme ceci:

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);
    }

}

dans la méthode marshaller, appelez simplement:

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

ça fonctionne bien. 

9
Laura Liparulo

J'ai un peu joué avec votre exemple et débogué le code JAXB. Et il semble que le codage UTF-8 utilisé soit spécifique. La propriété escapeHandler de MarshallerImpl semble être définie correctement. Cependant, il n'est pas utilisé dans tous les contextes. Si j'ai recherché des appels de MarshallerImpl.createEscapeHandler() j'ai trouvé:

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 );
    }
}

Notez que dans votre configuration, la section supérieure (...equals("UTF-8")...) est prise en compte. Cependant celui-ci ne prend pas la escapeHandler. Cependant, si vous définissez le codage sur un autre, la partie inférieure de cette méthode est appelée (createWriter(OutputStream, String)) et celle-ci utilise escapeHandler, donc EH joue son rôle . Donc, en ajoutant ...

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

fait que votre coutume CharacterEscapeHandler soit appelée . Pas vraiment sûr, mais je suppose que c'est un peu un bogue dans JAXB. 

4
Grzegorz Oledzki

Je dirais que la meilleure façon de faire est de remplacer 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);
    }
});
3
Maher Abuthraa

@ Elliot vous pouvez l'utiliser pour permettre à marshaller d'entrer la fonction characterEscape . C'est étrange mais cela fonctionne si vous définissez " Unicode " au lieu de "UTF-8". Ajoutez-le juste avant ou après la définition de la propriété CharacterEscapeHandler.

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

Cependant ne vous assurez pas uniquement en vérifiant votre console dans votre IDE, car elle devrait être affichée dépend du codage de l'espace de travail. Il est préférable de vérifier également à partir d'un fichier comme celui-ci: 

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

j'ai trouvé le même problème J'ai corrigé ceci en utilisant xmlWriter Dans le fichier xmlWriter, il existe une méthode isEscapeText () et setEscapeTest qui est par défaut vrai si vous ne voulez pas de transformation entre <pour & lt cette fois-ci besoin de setEscapeTest (false); pendant le triage

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

cette modificationwriter.setEscapeText (false);résolu mon problème espérons que cela change pour vous

2
Binal Parekh

Cela fonctionne pour moi après avoir lu d'autres articles:

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);
            }
        }
    }
1
user3240843

J'ai vérifié la spécification XML. http://www.w3.org/TR/REC-xml/#sec-references dit "les documents bien formés ne doivent déclarer aucune des entités suivantes: amp, lt, gt, apos, quot." il apparaît donc que l'analyseur XML utilisé par le système existant n'est pas conforme.

(Je sais que cela ne résout pas votre problème, mais au moins c'est agréable de pouvoir dire quel composant est cassé).

On dirait que c'est possible avec l'implémentation JAXB de Sun , même si je ne l'ai pas fait moi-même.

1
laz

Pour une raison quelconque, je n'ai pas le temps de le savoir, cela a fonctionné pour moi

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

Au lieu d'utiliser "UTF-8" ou "Unicode"

Je suggère que vous les essayiez, et comme @Javatar a dit , vérifiez-les en train de déposer pour classer en utilisant:

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

et en l'ouvrant avec un éditeur de texte décent comme notepad ++

0
mamuso

Après avoir essayé toutes les solutions ci-dessus, est finalement arrivé à la conclusion.

votre logique de marshaling via le gestionnaire d’échappement personnalisé.

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();

Et le gestionnaire d’évasion personnalisé est le suivant:

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);
            }
    }
}
0
Sufiyan Ansari

Le moyen le plus simple, lors de l'utilisation de l'implémentation Marshaller de Sun, consiste à fournir votre propre implémentation de CharacterEscapeEncoder qui n'échappe à rien.

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

Avec 

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 );
    }
}
0
fred

intéressant mais avec des chaînes, vous pouvez essayer 

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

au moins pour moi cela n'échappe pas aux citations 

0
jurisz

Je déconseille d'utiliser CharacterEscapeHandler pour les raisons mentionnées ci-dessus (c'est une classe interne). Au lieu de cela, vous pouvez utiliser Woodstox et fournir votre propre EscapingWriterFactory à un XMLStreamWriter. Quelque chose comme:

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 exemple de comment écrire une EscapingWriter peut être vu dans CharacterEscapingTest .

0
samblake