Java JAXB使用CDATA进行编组解组
我正在尝试使用JAXB进行封送处理 我的输出如下:Java JAXB使用CDATA进行编组解组,java,xml,jaxb,Java,Xml,Jaxb,我正在尝试使用JAXB进行封送处理 我的输出如下: <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <root> <name><![CDATA[<h1>kshitij</h1>]]></name> <surname>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<name><![CDATA[<h1>kshitij</h1>]]></name>
<surname><h1>solanki</h1></surname>
<id><h1>1</h1></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><![CDATA[<h1>kshitij</h1>]]></name>
<surname><h1>solanki</h1></surname>
<id><h1>1</h1></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("<", "<").replaceAll(">", ">");
}
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,如果我们需要的话