使JAXB逃脱撇号

时间:2015-12-17 08:29:52

标签: java xml jaxb escaping

我正在使用JAXB将Java对象转换为XML。我需要在输出XML中将撇号(')字符转义为'。默认情况下,JAXB不会转义撇号字符。我通过实现CharacterEscapeHandler了解了如何实现自定义转义处理程序。但是,我意识到这个类不包含在Java 1.7中。我在哪里可以获得包含这类的最新库?这个下载的JAXB库中的类是否会与Java 1.7中的JAXB类冲突?

提前致谢。

2 个答案:

答案 0 :(得分:0)

为了不依赖于JRE的其他版本/实现中不可用的内部类,您应该编写自己的ContentHandler(SAX)或XMLStreamWriter(StAX)。这样你就可以完全控制输出。

这是一个例子。它显示了JAXB如何正常输出XML以及如何使用ContentHandler自行完成。这很简单,例如性能不是很好,没有命名空间支持。您可能希望编写更好的escape()方法版本。您也可能希望将输出写入文件,而不是控制台。

public class Main {
    public static void main(String[] args) throws Exception {
        JAXBContext jaxbContext = JAXBContext.newInstance(MyData.class);
        Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.marshal(new MyData("Test < ' \" & >", "Test < ' \" & >"), System.out);

        System.out.println();

        marshaller.marshal(new MyData("Test < ' \" & >", "Test < ' \" & >"), new MyContentHandler());
    }
}
@XmlRootElement
class MyData {
    @XmlAttribute private String name;
    @XmlElement   private String desc;
    public MyData() {}
    public MyData(String name, String desc) { this.name = name; this.desc = desc; }
}
class MyContentHandler implements ContentHandler {
    @Override
    public void setDocumentLocator(Locator locator) {
        // Nothing to do
    }
    @Override
    public void startDocument() throws SAXException {
        System.out.print("<?xml version=\"1.0\" encoding=\"" + Charset.defaultCharset() + "\" standalone=\"yes\"?>");
    }
    @Override
    public void endDocument() throws SAXException {
        // Nothing to do
    }
    @Override
    public void startPrefixMapping(String prefix, String uri) throws SAXException {
        throw new UnsupportedOperationException();
    }
    @Override
    public void endPrefixMapping(String prefix) throws SAXException {
        throw new UnsupportedOperationException();
    }
    @Override
    public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
        System.out.print('<' + localName);
        for (int i = 0; i < atts.getLength(); i++)
            System.out.print(' ' + atts.getLocalName(i) + "=\"" + escape(atts.getValue(i)) + '"');
        System.out.print('>');
    }
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        System.out.print("</" + localName + ">");
    }
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        System.out.print(escape(new String(ch, start, length)));
    }
    private static String escape(String text) {
        return text.replace("&", "&amp;")
                   .replace("<", "&lt;")
                   .replace(">", "&gt;")
                   .replace("'", "&apos;")
                   .replace("\"", "&quot;");
    }
    @Override
    public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
        throw new UnsupportedOperationException();
    }
    @Override
    public void processingInstruction(String target, String data) throws SAXException {
        throw new UnsupportedOperationException();
    }
    @Override
    public void skippedEntity(String name) throws SAXException {
        throw new UnsupportedOperationException();
    }
}

输出

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><myData name="Test &lt; ' &quot; &amp; &gt;"><desc>Test &lt; ' " &amp; &gt;</desc></myData>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><myData name="Test &lt; &apos; &quot; &amp; &gt;"><desc>Test &lt; &apos; &quot; &amp; &gt;</desc></myData>

答案 1 :(得分:0)

尽管我喜欢Andreas的回答,但我不喜欢从头开始编写自己的XmlStreamWriter。我建议使用Woodstox中的实现并提供自己的EscapingWriterFactory。像这样:

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

CharacterEscapingTest中可以看到有关如何编写EscapingWriter的示例。