j'essaie de faire du marshaling avec JAXB.
ma sortie est comme
<?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>
mais j'ai besoin de sortie comme
<?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>
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 compiler mais je ne reçois pas la sortie exacte requise.
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);
}
}
}
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 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;
}
}
Classe d'adaptateur
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;
}
}
Vous pouvez faire ce qui suit:
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;
}
}
Racine
L'annotation @XmlJavaTypeAdapter
permet d'indiquer que la variable XmlAdapter
doit être utilisée.
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;
}
Démo
J'ai dû envelopper System.out
dans une OutputStreamWriter
pour obtenir l'effet souhaité. Notez également que la définition de CharacterEscapeHandler
signifie qu'il est responsable de toutes les opérations d'évacuation pour cette 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/Sortie
<?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>
Remarque: Je suis le EclipseLink JAXB (MOXy) lead et membre du groupe JAXB (JSR-222) .
Si vous utilisez MOXy en tant que fournisseur JAXB (JSR-222), vous pouvez utiliser l'extension @XmlCDATA
pour votre cas d'utilisation.
Racine
L'annotation @XmlCDATA
sert à 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 String name;
@XmlCDATA
private String surname;
@XmlCDATA
private String id;
}
jaxb.properties
Pour utiliser MOXy en tant que fournisseur JAXB, vous devez ajouter le fichier nommé jaxb.properties
avec 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(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
Ci-dessous se trouvent l'entrée et la sortie de l'exécution du code de démonstration.
<?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>
Pour plus d'informations
Désolé de creuser cette question et d’afficher une nouvelle réponse (mon représentant n’est pas encore assez haut pour faire un commentaire ...) . J'ai rencontré le même problème, j’ai essayé la réponse de Blaise Doughan, mais d'après mes tests, cela 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);
}
});
De mes tests, ce code supprime tous les échappements, peu importe si vous utilisez l'annotation @XmlJavaTypeAdapter(AdapterCDATA.class)
sur votre attribut ...
Pour résoudre ce problème, j'ai implémenté la CharacterEscapeHandler
suivante:
Classe publique CDataAwareUtfEncodedXmlCharacterEscapeHandler implémente CharacterEscapeHandler { caractère final statique privé [] cDataPrefix = "<! [CDATA [". toCharArray (); caractère final statique privé [] cDataSuffix = "]]>". toCharArray (); public final final CDataAwareUtfEncodedXmlCharacterEscapeHandler instance = new CDataAwareUtfEncodedXmlCharacterEscapeHandler (); private CDataAwareUtfEncodedXmlCharacterEscapeHandler () { } @Passer outre public void escape (char [] ch, int start, int length, boolean isAttVal, Writer out) jette IOException { booléen isCData = longueur> cDataPrefix.length + cDataSuffix.length; if (isCData) { pour (int i = 0, j = début; i <cDataPrefix.length; ++ i, ++ j) { if (cDataPrefix [i]! = ch [j]) { isCData = false; Pause; } } if (isCData) { pour (int i = cDataSuffix.length - 1, j = début + longueur - 1; 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 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 = "<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>
*/
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. Un moyen de résoudre ce problème consiste à envoyer le XML en tant qu’événements SAX2 à un gestionnaire, puis à écrire la logique dans le gestionnaire afin d’ajouter 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 String dans une classe générée à partir de XSD qui doit être marshalé et que le champ String contient des caractères spéciaux qui doivent être placés dans une balise CDATA.
@XmlRootElement
public class TestingCDATA{
public String xmlContent;
}
Nous commencerons par rechercher une classe appropriée dont la méthode peut être remplacée dans notre gestionnaire de contenu. Une de ces classes est XMLWriter présente 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, 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();
}
}
}
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’ajouter une balise CDATA.
Nous utiliserons le code suivant pour marshaling:
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);
}
}
Cela permettrait de marshaler l'objet et de renvoyer XML, si nous transmettons une requête à marshaler, comme indiqué ci-dessous.
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>