我正在尝试与JAXB进行编组。
我的输出就像
<?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>
我正在使用以下代码来执行此操作。如果我取消注释代码我得到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);
}
}
}
和我的豆子一样喜欢
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;
}
}
答案 0 :(得分:36)
您可以执行以下操作:
<强> 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;
}
}
<强>根强>
@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;
}
<强>演示强>
我必须将System.out
包裹在OutputStreamWriter
中以获得所需的效果。另请注意,设置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));
}
}
<强> 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>
答案 1 :(得分:11)
请注意:我是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;
}
<强> 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中/输出强>
以下是运行演示代码的输入和输出。
<?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>
了解更多信息
答案 2 :(得分:3)
很抱歉挖掘出这个问题并发布一个新的答案(我的代表还不够评论......)。 我遇到了同样的问题,我尝试了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
:
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); } } }
如果您的编码不是UTF *,您可能不想调用MinimumEscapeHandler,而是调用NioEscapeHandler甚至是DumbEscapeHandler。
答案 3 :(得分:1)
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);
}
}
答案 4 :(得分:0)
@Test
public void t() throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Root root = new Root();
root.name = "<p>Jorge & Mary</p>";
marshaller.marshal(root, System.out);
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class Root {
@XmlCDATA
private String name;
}
/* WHAT I SEE IN THE CONSOLE
*
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<name><p>Jorge & Mary</p></name>
</root>
*/
答案 5 :(得分:0)
我登陆此页面试图找到类似问题的解决方案,我找到了解决此问题的另一种方法。 解决此问题的一种方法是将XML作为SAX2事件发送到处理程序,然后在处理程序中编写逻辑以将CDATA标记添加到XML。此方法不需要添加任何注释。在从XSD生成要编组的类的场景中很有用。
假设在XSD中生成的类中有一个String字段,该字段将被封送,String字段包含要放在CDATA标记内的特殊字符。
@XmlRootElement
public class TestingCDATA{
public String xmlContent;
}
我们首先搜索一个合适的类,其方法可以在我们的内容处理程序中被覆盖。其中一个类是在com.sun.xml.txw2.output包中找到的XMLWriter,它在jdk 1.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();
}
}
}
我们重写了字符方法,使用正则表达式检查是否包含任何特殊字符。如果找到它们,那么我们在它们周围放置CDATA标签。在这种情况下,XMLWriter负责添加CDATA标记。</ p>
我们将使用以下代码进行编组:
public String addCDATAToXML(TestingCDATA request) throws FormatException {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(TestingCDATA.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
StringWriter sw = new StringWriter();
CDATAContentHandler cDataContentHandler = new CDATAContentHandler(sw, "UTF-8");
jaxbMarshaller.marshal(request, cDataContentHandler);
return sw.toString();
} catch (JAXBException | IOException e) {
throw new FormatException("Unable to add CDATA for request", e);
}
}
如果我们按照下面的说明传递一个要封送的请求,这将封送对象并返回XML。
TestingCDATA request=new TestingCDATA();
request.xmlContent="<?xml>";
System.out.println(addCDATAToXML(request)); // Would return the following String
Output-
<?xml version="1.0" encoding="UTF-8"?>
<testingCDATA>
<xmlContent><![CDATA[<?xml>]]></xmlContent>
</testingCDATA>
答案 6 :(得分:0)
除了@bdoughan答案。具有CDATA支持的字符转义处理程序
import com.sun.xml.bind.marshaller.CharacterEscapeHandler;
import java.io.IOException;
import java.io.Writer;
/**
* This class is a modern version of JAXB MinimumEscapeHandler with CDATA support
*
* @author me
* @see com.sun.xml.bind.marshaller.MinimumEscapeHandler
*/
public class CdataEscapeHandler implements CharacterEscapeHandler {
private CdataEscapeHandler() {
} // no instanciation please
public static final CharacterEscapeHandler theInstance = new CdataEscapeHandler();
@Override
public void escape(char[] ch, int start, int length, boolean isAttVal, Writer out) throws IOException {
// avoid calling the Writerwrite method too much by assuming
// that the escaping occurs rarely.
// profiling revealed that this is faster than the naive code.
int limit = start + length;
for (int i = start; i < limit; i++) {
if (!isAttVal
&& i <= limit - 12
&& ch[i] == '<'
&& ch[i + 1] == '!'
&& ch[i + 2] == '['
&& ch[i + 3] == 'C'
&& ch[i + 4] == 'D'
&& ch[i + 5] == 'A'
&& ch[i + 6] == 'T'
&& ch[i + 7] == 'A'
&& ch[i + 8] == '[') {
int cdataEnd = i + 8;
for (int k = i + 9; k < limit - 2; k++) {
if (ch[k] == ']'
&& ch[k + 1] == ']'
&& ch[k + 2] == '>') {
cdataEnd = k + 2;
break;
}
}
out.write(ch, start, cdataEnd + 1);
if (cdataEnd == limit - 1) return;
start = i = cdataEnd + 1;
}
char c = ch[i];
if (c == '&' || c == '<' || c == '>' || c == '\r' || (c == '\"' && isAttVal)) {
if (i != start)
out.write(ch, start, i - start);
start = i + 1;
switch (ch[i]) {
case '&':
out.write("&");
break;
case '<':
out.write("<");
break;
case '>':
out.write(">");
break;
case '\"':
out.write(""");
break;
}
}
}
if (start != limit)
out.write(ch, start, limit - start);
}
}