代码之家  ›  专栏  ›  技术社区  ›  Elliot

例如,当编组为XML时,我可以强制JAXB不将“转换为"”吗?

  •  24
  • Elliot  · 技术社区  · 15 年前

    我有一个对象正在使用JAXB封送到XML。一个元素包含一个包含引号(“)的字符串。结果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 回复  |  直到 6 年前
        1
  •  12
  •   Elliot    15 年前

    我的队友发现的解决方案:

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

    不要将xmlfile传递给marshal(),而是传递数据编写器,它既知道编码,也知道适当的转义处理程序(如果有)。

    注意:由于datawriter和dumbleescaphandler都在com.sun.xml.internal.bind.marshaller包中,所以必须引导javac。

        2
  •  9
  •   sanastasiadis    8 年前

    我刚将自定义处理程序设置为如下类:

    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方法中,只需调用:

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

    它很好用。

        3
  •  4
  •   Grzegorz Oledzki    15 年前

    我已经对您的示例进行了一些尝试,并调试了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) )这个用 逃逸处理程序 因此,eh扮演着它的角色。 所以,增加…

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

    自定义 CharacterEscapeHandler 被召唤。 不太确定,但我想这是JAXB中的一种bug。

        4
  •  3
  •   javatar    13 年前

    @ 埃利奥特 您可以使用此命令使封送拆收器进入CharacterEscape函数。 它是wierd,但如果你设置它就会工作” 统一码 “而不是”utf-8“。 在设置CharacterEscapeHandler属性之前或之后添加此项。

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

    然而 不要仅仅通过检查控制台来确定 在您的IDE中,因为应该根据工作区编码来显示它。最好也从这样的文件中进行检查:

    marshaller.marshal(shipOrder, new File("C:\\shipOrder.txt"));
    
        5
  •  3
  •   Maher Abuthraa    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);
        }
    });
    
        6
  •  2
  •   JuanDM    7 年前

    我发现了同样的问题 我用xmlwriter修复了这个问题 在xmlWriter文件中,有一个方法isescapetext()和setescapetest 默认为真 如果不希望在<到<之间进行转换,则需要在编组期间设置EscapeStest(false)

    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(错误); 修正了我的问题 希望这个变化对你有帮助

        7
  •  1
  •   laz    15 年前

    似乎有可能 Sun's JAXB implementation 尽管我自己还没做。

        8
  •  1
  •   Thorbjørn Ravn Andersen    15 年前

    我检查了XML规范。 http://www.w3.org/TR/REC-xml/#sec-references 表示“格式良好的文档不需要声明以下任何实体:amp、lt、gt、apos、quot。”因此,遗留系统使用的XML解析器似乎不一致。

    (我知道这并不能解决你的问题,但能说出哪个部件坏了至少是件好事)。

        9
  •  1
  •   hoaz    11 年前

    在阅读其他帖子后,这对我很有用:

    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);
                }
            }
        }
    
        10
  •  0
  •   jurisz    14 年前

    很有趣,但是有了弦你可以试试

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

    至少对我来说,这并不能逃避引用。

        11
  •  0
  •   fred fred    13 年前

    当使用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
  •  0
  •   Community CDub    8 年前

    出于某种原因,我没有时间去了解,这对我来说很有用。

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

    与使用相反 "UTF-8" "Unicode"

    我建议你试试,然后 @Javatar said ,检查它们是否正在转储到文件,使用:

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

    用一个像样的文本编辑器打开它 notepad++

        13
  •  0
  •   samblake    6 年前

    我建议不要使用 CharacterEscapeHandler 因为上面提到的原因(它是一个内部类)。相反,你可以使用 Woodstox 提供你自己的 EscapingWriterFactory 到A XMLStreamWriter . 类似:

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

    如何编写 EscapingWriter 可以看出 CharacterEscapingTest .

        14
  •  0
  •   Sufiyan Ansari    6 年前

    在尝试了上述所有的解决方案之后,最终得出了结论。

    通过自定义转义处理程序的封送逻辑。

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

    自定义转义处理程序如下:

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