Подтвердить что ты не робот

Могу ли я заставить JAXB не преобразовывать "в", например, при сортировке XML?

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

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

-

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

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 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 ID">
    <orderperson>The woman said, &quot;How ya doin &amp; stuff?&quot;</orderperson>
</shiporder>

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

-

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

Я только что сделал свой собственный обработчик как класс, подобный этому:

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

он отлично работает.

Ответ 3

Я немного играл с вашим примером и отлаживал код 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.

Ответ 4

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

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

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

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

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

Я бы сказал, что самый простой способ - переопределить 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);
    }
});

Ответ 9

я нашел ту же проблему Я исправил это с помощью xmlWriter в файле xmlWriter есть один метод isEscapeText() и setEscapeTest это по умолчанию true если вы не хотите, чтобы преобразование между < to & lt это время вам нужно установитьEscapeTest (false); во время сортировки

JAXBContext jaxbContext = JAXBContext.newInstance(ваш класс);           Маршаллер-маршаллер = 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);***
        // Attach the writer to the filter
        outFilter.setContentHandler(writer);
        // marshalling

        marshaller.marshal(piaDto, outFilter);
        marshaller.marshal(piaDto, System.out);

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

Ответ 10

интересно, но со строками вы можете попробовать

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

по крайней мере для меня это не избежать кавычек

Ответ 11

Самый простой способ использования Sun Marshaller - предоставить вам собственную реализацию CharacterEscapeEncoder, которая ничего не ускользнет.

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

С

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

Ответ 12

По какой-то причине у меня нет времени, чтобы узнать, это сработало для меня при настройке

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

В отличие от использования "UTF-8" или "Unicode"

Я предлагаю вам попробовать их, и, как @Javatar сказал, проверьте их сброс в файл, используя:

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

и открыть его с помощью достойного текстового редактора, например notepad ++