Java JAXB使用CDATA进行编组解组

Java JAXB使用CDATA进行编组解组,java,xml,jaxb,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>

我正在尝试使用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>
<?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>
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;
    }
}
我的豆子看起来像这样:

<?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>
<?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>
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;
    }
}
适配器类

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;
    }
}
公共类适配器数据扩展XmlAdapter{
@凌驾
公共字符串封送处理程序(字符串arg0)引发异常{
返回“”;
}
@凌驾
公共字符串解组器(字符串arg0)引发异常{
返回arg0;
}
}

请注意:我是专家组的负责人和成员

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

根目录

<?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>
@xmlcata
注释用于指示希望将字段/属性的内容包装在CDATA节中。
@xmlcata
注释可以与
@xmlement
结合使用

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;

}
jaxb.properties

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

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
演示

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

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

}
input.xml/Output

<?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>
下面是运行演示代码的输入和输出

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

kshitij]]>
索兰基]]>
了解更多信息


您可以执行以下操作:

适配器数据

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

}
演示

我必须在
OutputStreamWriter
中包装
System.out
,以获得所需的效果。还请注意,设置
CharacterEscapeHandler
意味着它负责该
封送处理程序的所有转义处理

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

}
input.xml/Output

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

kshitij]]>
索兰基]]>
@测试
public void t()引发异常{
JAXBContext jc=JAXBContext.newInstance(Root.class);
Marshaller=jc.createMarshaller();
setProperty(marshaller.JAXB_格式化的_输出,true);
根=新根();
root.name=“Jorge&Mary

”; marshaller.marshall(root,System.out); } @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) 公共静态类根{ @XmlCDATA 私有字符串名称; } /*我在控制台中看到的 * 普豪尔酒店;玛丽/p */
com.sun.internal不适用于play2,但它可以工作

private static String marshal(YOurCLass xml){
    try{
        StringWriter stringWritter = new StringWriter();
        Marshaller marshaller = JAXBContext.newInstance(YourCLass.class).createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.setProperty(Marshaller.JAXB_ENCODING, "ISO-8859-1");
        marshaller.marshal(xml, stringWritter);
        return stringWritter.toString().replaceAll("&lt;", "<").replaceAll("&gt;", ">");
    }
    catch(JAXBException e){
        throw new RuntimeException(e);
    }
}
私有静态字符串封送处理(YOurCLass xml){
试一试{
StringWriter StringWriter=新StringWriter();
Marshaller=JAXBContext.newInstance(YourCLass.class).createMarshaller();
setProperty(marshaller.JAXB_格式化的_输出,true);
setProperty(marshaller.JAXB_编码,“ISO-8859-1”);
marshaller.marshall(xml,StringWriter);
返回StringWriter.toString().replaceAll(“,”);
}
捕获(JAXBEException e){
抛出新的运行时异常(e);
}
}

很抱歉挖出了这个问题,并发布了一个新的答案(我的代表还没有发表评论…)。 我遇到了同样的问题,我尝试了布莱斯·道格汉的答案,但从我的测试来看,要么没有涵盖所有情况,要么我在某个地方做错了什么



    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

public class CDataAwareUtfEncodedXmlCharacterEscapeHandler implements CharacterEscapeHandler { private static final char[] cDataPrefix = "<![CDATA[".toCharArray(); private static final char[] cDataSuffix = "]]>".toCharArray(); public static final CDataAwareUtfEncodedXmlCharacterEscapeHandler instance = new CDataAwareUtfEncodedXmlCharacterEscapeHandler(); private CDataAwareUtfEncodedXmlCharacterEscapeHandler() { } @Override public void escape(char[] ch, int start, int length, boolean isAttVal, Writer out) throws IOException { boolean isCData = length > cDataPrefix.length + cDataSuffix.length; if (isCData) { for (int i = 0, j = start; i < cDataPrefix.length; ++i, ++j) { if (cDataPrefix[i] != ch[j]) { isCData = false; break; } } if (isCData) { for (int i = cDataSuffix.length - 1, j = start + length - 1; i >= 0; --i, --j) { if (cDataSuffix[i] != ch[j]) { isCData = false; break; } } } } if (isCData) { out.write(ch, start, length); } else { MinimumEscapeHandler.theInstance.escape(ch, start, length, isAttVal, out); } } } 公共类CDataWareTfEncodeDxmlCharacterEscapeHandler实现CharacterEscapeHandler{ 私有静态最终字符[]CDATA前缀=“.ToCharray(); 公共静态最终CDATA awareTfEncodeDxmlCharacterEscapeHandler实例=新CDATA awareTfEncodeDxmlCharacterEscapeHandler(); 私有CDATA AwareTfEncodeDxmlCharacterEscapeHandler(){ } @凌驾 公共void转义(char[]ch,int start,int length,boolean isAttVal,Writer out)抛出IOException{ 布尔值isCData=length>cDataPrefix.length+cDataSuffix.length; 如果(isCData){ 对于(int i=0,j=start;i=0;--i,--j){ if(后缀[i]!=ch[j]){ isCData=false; 打破 } } } } 如果(isCData){ 输出。写入(ch、开始、长度); }否则{ MinimumEscapeHandler.theInstance.escape(ch、start、length、isAttVal、out); } } }
如果您的编码不是UTF*,您可能不想调用MinimumEscapeHandler,而是想调用NioEscapeHandler,甚至DumbEscapeHandler。

我登上这页试图找到类似问题的解决方案,我找到了另一种解决方法。 解决此问题的一种方法是将XML作为SAX2事件发送给处理程序,然后在处理程序中写入逻辑,将CDATA标记添加到XML中。这种方法不需要添加任何注释。在从XSD生成要封送的类的场景中非常有用

假设在从XSD生成的类中有一个字符串字段,该字段将被封送,并且该字符串字段包含要放入CDATA标记中的特殊字符

@XmlRootElement
public class TestingCDATA{
    public String xmlContent;

}
我们将首先搜索一个合适的类,该类的方法可以在我们的内容处理程序中重写。其中一个类是在com.sun.xml.txw2.output包中找到的XMLWriter,它在JDK1.7和1.8中可用

import com.sun.xml.txw2.output.XMLWriter;
import org.xml.sax.SAXException;

import java.io.IOException;
import java.io.Writer;
import java.util.regex.Pattern;

public class CDATAContentHandler extends XMLWriter {
    public CDATAContentHandler(Writer writer, String encoding) throws IOException {
        super(writer, encoding);
    }

    // see http://www.w3.org/TR/xml/#syntax
    private static final Pattern XML_CHARS = Pattern.compile("[<>&]");

    public void characters(char[] ch, int start, int length) throws SAXException {
        boolean useCData = XML_CHARS.matcher(new String(ch, start, length)).find();
        if (useCData) {
            super.startCDATA();
        }
        super.characters(ch, start, length);
        if (useCData) {
            super.endCDATA();
        }
    }
}
这将封送对象并返回XML,如果我们需要的话