Могу ли я заставить JAXB не преобразовывать «в», например, при сортировке в XML? - PullRequest
25 голосов
/ 02 октября 2009

У меня есть объект, который маршалируется в XML с использованием JAXB. Один элемент содержит строку, которая содержит кавычки ("). Полученный XML имеет ", где" существовал ".

Несмотря на то, что это обычно предпочитается, мне нужно, чтобы мой вывод соответствовал устаревшей системе. Как заставить JAXB НЕ преобразовывать сущности HTML?

-

Спасибо за ответы. Однако я никогда не вижу вызываемого обработчика escape (). Можете посмотреть и посмотреть, что я делаю не так? Спасибо!

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

-

Вывод такой:

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

и, как вы можете видеть, обратный вызов никогда не отображается. (Как только я получу обратный вызов, я буду беспокоиться о том, чтобы он действительно делал то, что я хочу.)

-

Ответы [ 14 ]

13 голосов
/ 06 октября 2009

Решение, которое наш товарищ по команде нашел:

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

Вместо передачи xmlFile в marshal (), передайте DataWriter, который знает как кодировку, так и соответствующий обработчик escape, если таковой имеется.

Примечание. Поскольку DataWriter и DumbEscapeHandler находятся в пакете com.sun.xml.internal.bind.marshaller, необходимо выполнить загрузку javac.

9 голосов
/ 02 августа 2013

Я только что создал свой пользовательский обработчик как класс:

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

}

в методе маршаллера просто вызовите:

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

работает нормально.

4 голосов
/ 06 октября 2009

Я немного поиграл с вашим примером и отлаживал код JAXB. И похоже, что-то конкретное в используемой кодировке UTF-8. Свойство escapeHandler MarshallerImpl, похоже, установлено правильно. Однако это используется не в каждом контексте. Если я искал звонки MarshallerImpl.createEscapeHandler(), я нашел:

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

Обратите внимание, что в вашей настройке учтен верхний раздел (...equals("UTF-8")...). Однако этот не берет escapeHandler. Однако, если вы установите кодировку на любое другое, нижняя часть этого метода называется (createWriter(OutputStream, String)), и этот использует escapeHandler, поэтому EH играет свою роль. Итак, добавив ...

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

позволяет вызывать ваш пользовательский CharacterEscapeHandler. Не совсем уверен, но я думаю, это ошибка в JAXB.

3 голосов
/ 23 марта 2017

Я бы сказал, что самый простой способ сделать это - переопределить 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 голосов
/ 10 февраля 2012

@ Elliot Вы можете использовать это, чтобы позволить маршаллеру войти в функцию characterEscape. Это странно, но работает, если вы установите « Unicode » вместо «UTF-8». Добавьте это непосредственно перед или после установки свойства CharacterEscapeHandler.

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

Однако не следует проверять, просто проверяя консоль в своей среде IDE, поскольку она должна отображаться в зависимости от кодировки рабочей области. Лучше проверить это также из такого файла:

marshaller.marshal(shipOrder, new File("C:\\shipOrder.txt"));
2 голосов
/ 22 января 2018

я нашел ту же проблему я исправил это используя xmlWriter в файле xmlWriter есть один метод isEscapeText () и setEscapeTest по умолчанию это правда если вам не нужно преобразование между <и lt в это время, вам нужно установить setscape (false); во время сортировки </p>

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

это изменение writer.setEscapeText (false); исправило мою проблему надеюсь, что эти изменения будут полезны для вас

1 голос
/ 27 января 2014

Это работает для меня после прочтения других сообщений:

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 голос
/ 05 апреля 2010

Я проверил спецификацию XML. http://www.w3.org/TR/REC-xml/#sec-references говорит, что «правильно оформленные документы не должны объявлять ни одну из следующих сущностей: amp, lt, gt, apos, quot." *

(я знаю, что это не решит вашу проблему, но по крайней мере приятно иметь возможность сказать, какой компонент неисправен).

1 голос
/ 02 октября 2009

Кажется, что это возможно с реализацией Sun JAXB , хотя я сам этого не делал.

0 голосов
/ 11 октября 2018

Перепробовав все вышеперечисленные решения, наконец пришел к выводу.

ваша логика маршалинга через пользовательский обработчик escape.

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

А пользовательский обработчик escape выглядит следующим образом:

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