JAXB Marshalling Unmarshalling avec CDATA

J’essaie de faire du marshaling avec JAXB.

ma sortie est comme

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

mais j’ai besoin de sortie comme

   <![CDATA[

kshitij

]]> <![CDATA[

solanki

]]>

J’utilise le code suivant pour le faire. et si je décode le code, j’obtiens une exception de liaison de propriété. Sans cela, je peux comstackr mais je ne reçois pas la sortie exacte requirejse.

  package com.ksh.templates; import java.io.IOException; import java.io.SsortingngWriter; 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(Ssortingng args[]) { try { Ssortingng name = "

kshitij

"; Ssortingng surname = "

solanki

"; Ssortingng 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 ); } }); SsortingngWriter ssortingngWriter = new SsortingngWriter(); marshaller.marshal(cdata, ssortingngWriter); System.out.println(ssortingngWriter.toSsortingng()); } catch (Exception e) { System.out.println(e); } } }

et mes haricots aiment

  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 Ssortingng name; @XmlElement @XmlJavaTypeAdapter(value = AdaptorCDATA.class) private Ssortingng surname; @XmlCDATA public Ssortingng getName() { return name; } @XmlCDATA public void setName(Ssortingng name) { this.name = name; } @XmlCDATA public Ssortingng getSurname() { return surname; } @XmlCDATA public void setSurname(Ssortingng surname) { this.surname = surname; } } 

Classe d’adaptateur

 public class AdaptorCDATA extends XmlAdapter { @Override public Ssortingng marshal(Ssortingng arg0) throws Exception { return ""; } @Override public Ssortingng unmarshal(Ssortingng arg0) throws Exception { return arg0; } } 

Vous pouvez faire ce qui suit:

AdapterCDATA

 package forum14193944; import javax.xml.bind.annotation.adapters.XmlAdapter; public class AdapterCDATA extends XmlAdapter { @Override public Ssortingng marshal(Ssortingng arg0) throws Exception { return ""; } @Override public Ssortingng unmarshal(Ssortingng arg0) throws Exception { return arg0; } } 

Racine

L’annotation @XmlJavaTypeAdapter est utilisée pour spécifier que XmlAdapter doit être utilisé.

 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 Ssortingng name; @XmlJavaTypeAdapter(AdapterCDATA.class) private Ssortingng surname; @XmlJavaTypeAdapter(AdapterCDATA.class) private Ssortingng id; } 

Démo

J’ai dû envelopper System.out dans un OutputStreamWriter pour obtenir l’effet désiré. Notez également que la définition d’un CharacterEscapeHandler signifie qu’il est responsable de la gestion de toutes les sorties pour ce Marshaller .

 package forum14193944; import java.io.*; import javax.xml.bind.*; import com.sun.xml.bind.marshaller.*; public class Demo { public static void main(Ssortingng[] 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

   kshitij]]> solanki]]>   

Remarque: je suis le responsable EclipseLink JAXB (MOXy) et un membre du groupe d’experts JAXB (JSR-222) .

Si vous utilisez MOXy comme fournisseur JAXB (JSR-222), vous pouvez @XmlCDATA extension @XmlCDATA pour votre cas d’utilisation.

Racine

L’annotation @XmlCDATA est utilisée pour indiquer que vous souhaitez que le contenu d’un champ / propriété soit encapsulé dans une section CDATA. L’annotation @XmlCDATA peut être utilisée en combinaison avec @XmlElement .

 package forum14193944; import javax.xml.bind.annotation.*; import org.eclipse.persistence.oxm.annotations.XmlCDATA; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Root { @XmlCDATA private Ssortingng name; @XmlCDATA private Ssortingng surname; @XmlCDATA private Ssortingng id; } 

jaxb.properties

Pour utiliser MOXy en tant que fournisseur JAXB, vous devez append le fichier nommé jaxb.properties à l’entrée suivante.

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

Démo

Vous trouverez ci-dessous un code de démonstration permettant de prouver que tout fonctionne.

 package forum14193944; import java.io.File; import javax.xml.bind.*; public class Demo { public static void main(Ssortingng[] 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

Ci-dessous se trouvent l’entrée et la sortie de l’exécution du code de démonstration.

   kshitij]]> solanki]]>   

Pour plus d’informations

Désolé de creuser cette question et de poster une nouvelle réponse (mon représentant n’est pas encore assez haut pour commenter …). J’ai rencontré le même problème, j’ai essayé la réponse de Blaise Doughan, mais d’après mes tests, soit elle ne couvre pas tous les cas, soit je fais quelque chose de mal quelque part.

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

De mes tests, ce code supprime toutes les échappements, peu importe si vous utilisez l’ @XmlJavaTypeAdapter(AdapterCDATA.class) sur votre atsortingbut …

Pour résoudre ce problème, j’ai mis en œuvre le CharacterEscapeHandler suivant:


     Classe publique CDataAwareUtfEncodedXmlCharacterEscapeHandler implémente CharacterEscapeHandler {

         char final statique privé [] cDataPrefix = "". toCharArray ();

         public final final CDataAwareUtfEncodedXmlCharacterEscapeHandler instance = new CDataAwareUtfEncodedXmlCharacterEscapeHandler ();

         private CDataAwareUtfEncodedXmlCharacterEscapeHandler () {
         }

         @Passer outre
         échappement void public (char [] ch, int start, int length, boolean isAttVal, Writer out) émet une exception IOException {
             boolean isCData = length> cDataPrefix.length + cDataSuffix.length;
             if (isCData) {
                 pour (int i = 0, j = début; i  = 0; --i, --j) {
                         if (cDataSuffix [i]! = ch [j]) {
                             isCData = false;
                             Pause;
                         }
                     }
                 }
             }
             if (isCData) {
                 out.write (ch, start, length);
             } autre {
                 MinimumEscapeHandler.theInstance.escape (ch, début, longueur, isAttVal, out);
             }
         }
     }

Si votre codage n’est pas UTF *, vous ne voudrez peut-être pas appeler MinimumEscapeHandler, mais plutôt NioEscapeHandler ou même DumbEscapeHandler.

com.sun.internal ne fonctionne pas avec play2, mais cela fonctionne

 private static Ssortingng marshal(YOurCLass xml){ try{ SsortingngWriter ssortingngWritter = new SsortingngWriter(); 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, ssortingngWritter); return ssortingngWritter.toSsortingng().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 Ssortingng name; } /* WHAT I SEE IN THE CONSOLE * <p>Jorge & Mary</p> */

J’ai atterri sur cette page en essayant de trouver une solution à un problème similaire, j’ai trouvé une autre approche pour résoudre ce problème. Une façon de résoudre ce problème consiste à envoyer du XML en tant qu’événements SAX2 à un gestionnaire, puis à écrire la logique dans le gestionnaire pour append les balises CDATA au XML. Cette approche ne nécessite aucune annotation. Utile dans les scénarios où les classes à marshaler sont générées à partir de fichiers XSD.

Supposons que vous ayez un champ Ssortingng dans une classe générée à partir de XSD à marshaler et que le champ Ssortingng contient des caractères spéciaux à insérer dans une balise CDATA.

 @XmlRootElement public class TestingCDATA{ public Ssortingng xmlContent; } 

Nous commencerons par rechercher une classe appropriée dont la méthode peut être remplacée dans notre gestionnaire de contenu. Une telle classe est XMLWriter trouvée dans le package com.sun.xml.txw2.output, elle est disponible dans jdk 1.7 et 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, Ssortingng encoding) throws IOException { super(writer, encoding); } // see http://www.w3.org/TR/xml/#syntax private static final Pattern XML_CHARS = Pattern.comstack("[<>&]"); 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(); } } } 

Nous substituons la méthode des caractères, en utilisant regex pour vérifier si des caractères spéciaux sont contenus. S’ils sont trouvés, nous mettons des balises CDATA autour d’eux. Dans ce cas, XMLWriter se charge d’append une balise CDATA.

Nous utiliserons le code suivant pour marshaling:

 public Ssortingng addCDATAToXML(TestingCDATA request) throws FormatException { try { JAXBContext jaxbContext = JAXBContext.newInstance(TestingCDATA.class); Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); SsortingngWriter sw = new SsortingngWriter(); CDATAContentHandler cDataContentHandler = new CDATAContentHandler(sw, "UTF-8"); jaxbMarshaller.marshal(request, cDataContentHandler); return sw.toSsortingng(); } catch (JAXBException | IOException e) { throw new FormatException("Unable to add CDATA for request", e); } } 

Cela permettrait de marshaler l’object et de retourner XML, si nous transmettons une demande à être marshalée comme indiqué ci-dessous.

 TestingCDATA request=new TestingCDATA(); request.xmlContent=""; System.out.println(addCDATAToXML(request)); // Would return the following Ssortingng Output-   ]]>