JAXB使用CDATA编组解组

KSH*_*TiJ 25 java xml jaxb

我正在尝试与JAXB进行编组.

我的输出就像

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <name>&lt;![CDATA[&lt;h1&gt;kshitij&lt;/h1&gt;]]&gt;</name>
    <surname>&lt;h1&gt;solanki&lt;/h1&gt;</surname>
    <id>&lt;h1&gt;1&lt;/h1&gt;</id>
</root>
Run Code Online (Sandbox Code Playgroud)

但我需要输出像

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <root>
        <name><![CDATA[<h1>kshitij</h1>]]></name>
        <surname><![CDATA[<h1>solanki</h1>]]></surname>
        <id><![CDATA[0]]></id>
    </root>
Run Code Online (Sandbox Code Playgroud)

我正在使用以下代码来执行此操作.如果我取消注释代码我得到Property Binding Exception.没有它我可以编译,但我没有得到确切的所需输出.

  package com.ksh.templates;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import com.sun.xml.bind.marshaller.CharacterEscapeHandler;

public class MainCDATA {
    public static void main(String args[])
    {
        try
        {
            String name = "<h1>kshitij</h1>";
            String surname = "<h1>solanki</h1>";
            String id = "<h1>1</h1>";

            TestingCDATA cdata = new TestingCDATA();
            cdata.setId(id);
            cdata.setName(name);
            cdata.setSurname(surname);

            JAXBContext jaxbContext = JAXBContext.newInstance(TestingCDATA.class);
            Marshaller marshaller = jaxbContext.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

            marshaller.setProperty(CharacterEscapeHandler.class.getName(), new CharacterEscapeHandler() { 
                public void escape(char[] ac, int i, int j, boolean flag,
                Writer writer) throws IOException {
                writer.write( ac, i, j ); }
                });
            StringWriter stringWriter = new StringWriter(); 
            marshaller.marshal(cdata, stringWriter);
            System.out.println(stringWriter.toString());
        }
        catch (Exception e) 
        {
            System.out.println(e);
        }       
    }
}
Run Code Online (Sandbox Code Playgroud)

我的豆子喜欢

 package com.ksh.templates;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import com.sun.xml.txw2.annotation.XmlCDATA;

@XmlRootElement(name = "root")
@XmlAccessorType(XmlAccessType.FIELD)
public class TestingCDATA {

    @XmlElement
    @XmlJavaTypeAdapter(value = AdaptorCDATA.class)
    private String name;
    @XmlElement
    @XmlJavaTypeAdapter(value = AdaptorCDATA.class)
    private String surname;

    @XmlCDATA
    public String getName() {
        return name;
    }
    @XmlCDATA
    public void setName(String name) {
        this.name = name;
    }
    @XmlCDATA
    public String getSurname() {
        return surname;
    }
    @XmlCDATA
    public void setSurname(String surname) {
        this.surname = surname;
    }
}
Run Code Online (Sandbox Code Playgroud)

适配器类

public class AdaptorCDATA extends XmlAdapter<String, String> {

    @Override
    public String marshal(String arg0) throws Exception {
        return "<![CDATA[" + arg0 + "]]>";
    }
    @Override
    public String unmarshal(String arg0) throws Exception {
        return arg0;
    }
}
Run Code Online (Sandbox Code Playgroud)

bdo*_*han 37

您可以执行以下操作:

AdapterCDATA

package forum14193944;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class AdapterCDATA extends XmlAdapter<String, String> {

    @Override
    public String marshal(String arg0) throws Exception {
        return "<![CDATA[" + arg0 + "]]>";
    }
    @Override
    public String unmarshal(String arg0) throws Exception {
        return arg0;
    }

}
Run Code Online (Sandbox Code Playgroud)

@XmlJavaTypeAdapter注释用于指定XmlAdapter应该使用的注释.

package forum14193944;

import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    @XmlJavaTypeAdapter(AdapterCDATA.class)
    private String name;

    @XmlJavaTypeAdapter(AdapterCDATA.class)
    private String surname;

    @XmlJavaTypeAdapter(AdapterCDATA.class)
    private String id;

}
Run Code Online (Sandbox Code Playgroud)

演示

我不得不换System.outOutputStreamWriter获得预期的效果.另请注意,设置CharacterEscapeHandler表示它负责所有的转义处理Marshaller.

package forum14193944;

import java.io.*;
import javax.xml.bind.*;
import com.sun.xml.bind.marshaller.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum14193944/input.xml");
        Root root = (Root) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.setProperty(CharacterEscapeHandler.class.getName(),
                new CharacterEscapeHandler() {
                    @Override
                    public void escape(char[] ac, int i, int j, boolean flag,
                            Writer writer) throws IOException {
                        writer.write(ac, i, j);
                    }
                });
        marshaller.marshal(root, new OutputStreamWriter(System.out));
    }

}
Run Code Online (Sandbox Code Playgroud)

input.xml中/输出

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <name><![CDATA[<h1>kshitij</h1>]]></name>
    <surname><![CDATA[<h1>solanki</h1>]]></surname>
    <id><![CDATA[0]]></id>
</root>
Run Code Online (Sandbox Code Playgroud)

  • @BlaiseDoughan,你的AdapterCDATA给了我以下xml:<subject>&lt;![CDATA [sometext]]&gt; </ subject>,因为&lt; 和&gt; 这段代码被误解了. (9认同)
  • 这将禁用_all_字段上的字符转义,而不仅仅是cdata字段.使用起来相当危险. (7认同)

bdo*_*han 16

请注意: 我是EclipseLink JAXB(MOXy)的负责人,也是JAXB(JSR-222)专家组的成员.

如果您使用MOXy作为JAXB(JSR-222)提供程序,那么您可以利用@XmlCDATA您的用例扩展.

@XmlCDATA注释用于指示要字段/属性包裹在CDATA部分的内容.该@XmlCDATA注释可与组合使用@XmlElement.

package forum14193944;

import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlCDATA;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    @XmlCDATA
    private String name;

    @XmlCDATA
    private String surname;

    @XmlCDATA
    private String id;

}
Run Code Online (Sandbox Code Playgroud)

jaxb.properties

要将MOXy用作JAXB提供程序,您需要添加jaxb.properties以下条目命名的文件.

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Run Code Online (Sandbox Code Playgroud)

演示

下面是一些演示代码,以证明一切正常.

package forum14193944;

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum14193944/input.xml");
        Root root = (Root) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(root, System.out);
    }

}
Run Code Online (Sandbox Code Playgroud)

input.xml中/输出

下面是运行演示代码的输入和输出.

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <name><![CDATA[<h1>kshitij</h1>]]></name>
   <surname><![CDATA[<h1>solanki</h1>]]></surname>
   <id><![CDATA[0]]></id>
</root>
Run Code Online (Sandbox Code Playgroud)

欲获得更多信息


小智 6

很抱歉挖掘出这个问题,并发布了一个新答案(我的代表还不够高,无法发表评论......)。我遇到了同样的问题,我尝试了 Blaise Doughan 的答案,但从我的测试来看,要么它没有涵盖所有情况,要么我在某处做错了。



    marshaller.setProperty(CharacterEscapeHandler.class.getName(),
                    new CharacterEscapeHandler() {
                        @Override
                        public void escape(char[] ac, int i, int j, boolean flag,
                                Writer writer) throws IOException {
                            writer.write(ac, i, j);
                        }
                    });


从我的测试中,此代码删除了所有转义,无论您是否@XmlJavaTypeAdapter(AdapterCDATA.class)在属性上使用注释...

为了解决这个问题,我实现了以下内容CharacterEscapeHandler

    公共类 CDataAwareUtfEncodedXmlCharacterEscapeHandler 实现 CharacterEscapeHandler {

        private static final char[] cDataPrefix = "<![CDATA[".toCharArray();
        private static final char[] cDataSuffix = "]]>".toCharArray();

        public static final CDataAwareUtfEncodedXmlCharacterEscapeHandler instance = new CDataAwareUtfEncodedXmlCharacterEscapeHandler();

        私人 CDataAwareUtfEncodedXmlCharacterEscapeHandler() {
        }

        @覆盖
        public void escape(char[] ch, int start, int length, boolean isAttVal, Writer out) 抛出 IOException {
            boolean isCData = length > cDataPrefix.length + cDataSuffix.length;
            如果(isCData){
                for (int i = 0, j = start; i < cDataPrefix.length; ++i, ++j) {
                    如果 (cDataPrefix[i] != ch[j]) {
                        isCData = false;
                        休息;
                    }
                }
                如果(isCData){
                    for (int i = cDataSuffix.length - 1, j = start + length - 1; i >= 0; --i, --j) {
                        如果 (cDataSuffix[i] != ch[j]) {
                            isCData = false;
                            休息;
                        }
                    }
                }
            }
            如果(isCData){
                out.write(ch, 开始, 长度);
            } 别的 {
                MinimumEscapeHandler.theInstance.escape(ch, start, length, isAttVal, out);
            }
        }
    }

如果您的编码不是 UTF*,您可能不想调用 MinimumEscapeHandler 而是 NioEscapeHandler 甚至 DumbEscapeHandler。