JAXB使用CDATA编组解组

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

我的输出就像

  <![CDATA[<h1>kshitij</h1>]]> <h1>solanki</h1> <h1>1</h1>  

但我需要输出像

   <![CDATA[

kshitij

]]> <![CDATA[

solanki

]]>

我正在使用以下代码来执行此操作。 如果我取消注释代码,我会得到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 = "

kshitij

"; String surname = "

solanki

"; String id = "

1

"; 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 { @Override public String marshal(String arg0) throws Exception { return ""; } @Override public String unmarshal(String arg0) throws Exception { return arg0; } } 

您可以执行以下操作:

AdapterCDATA

 package forum14193944; import javax.xml.bind.annotation.adapters.XmlAdapter; public class AdapterCDATA extends XmlAdapter { @Override public String marshal(String arg0) throws Exception { return ""; } @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; } 

演示

我必须在OutputStreamWriter包装System.out以获得所需的效果。 另请注意,设置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中/输出

   kshitij]]> solanki]]>   

请注意:我是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 

演示

下面是一些演示代码,以certificate一切正常。

 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中/输出

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

   kshitij]]> solanki]]>   

了解更多信息

很抱歉挖掘这个问题,并发布一个新的答案(我的代表还不够评论……)。 我遇到了同样的问题,我尝试了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); } });
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();

         private CDataAwareUtfEncodedXmlCharacterEscapeHandler(){
         }

         @覆盖
         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  = 0;  -  i, -  j){
                         if(cDataSuffix [i]!= ch [j]){
                             isCData = false;
                            打破;
                         }
                     }
                 }
             }
             if(isCData){
                 out.write(ch,start,length);
             } else {
                 MinimumEscapeHandler.theInstance.escape(ch,start,length,isAttVal,out);
             }
         }
     }

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

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); } } 
  @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 = "

Jorge & Mary

"; marshaller.marshal(root, System.out); } @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public static class Root { @XmlCDATA private String name; } /* WHAT I SEE IN THE CONSOLE * <p>Jorge & Mary</p> */

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

假设您在从XSD生成的类中有一个字符串字段,该字段将被编组,并且字符串字段包含要放在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标记。

我们将使用以下代码进行封送处理:

 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=""; System.out.println(addCDATAToXML(request)); // Would return the following String Output-   ]]>