Can I force JAXB not to convert " into ", for example, when marshalling to XML?

Viewed 65852

I have an Object that is being marshalled to XML using JAXB. One element contains a String that includes quotes ("). The resulting XML has " where the " existed.

Even though this is normally preferred, I need my output to match a legacy system. How do I force JAXB to NOT convert the HTML entities?

--

Thank you for the replies. However, I never see the handler escape() called. Can you take a look and see what I'm doing wrong? Thanks!

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

--

The output is this:

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

and as you can see, the callback is never displayed. (Once I get the callback being called, I'll worry about having it actually do what I want.)

--

14 Answers

i found same issue i fixed this using xmlWriter in xmlWriter file there is one method isEscapeText() and setEscapeTest that is by default true if you dont want transformation between < to &lt that time you need to setEscapeTest(false); during 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);

this change writer.setEscapeText(false); fixed my issue hope this changes helpful to you

I would advise against using CharacterEscapeHandler for the reasons mentioned above (it's an internal class). Instead you can use Woodstox and supply your own EscapingWriterFactory to a XMLStreamWriter. Something like:

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

An example of how to write an EscapingWriter can be seen in CharacterEscapingTest.

After trying all the above solutions, finally came to the conclusion.

your marshaling logic through the custom escape handler.

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

And the custom escape handler is as follow:

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