ich versuche mit JAXB Marshalling zu machen.
meine Ausgabe ist wie
<?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>
aber ich brauche gerne 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>
Ich verwende dazu folgenden Code. und wenn ich den Code nicht kommentiere, erhalte ich eine Property-Binding-Ausnahme. Ohne das kann ich kompilieren, aber ich bekomme nicht die genaue Ausgabe.
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);
}
}
}
und meine Bohnenloks mögen
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;
}
}
Adapterklasse
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;
}
}
Sie könnten folgendes tun:
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;
}
}
Wurzel
Mit der Annotation @XmlJavaTypeAdapter
wird angegeben, dass XmlAdapter
verwendet werden soll.
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;
}
Demo
Ich musste System.out
in ein OutputStreamWriter
einwickeln, um den gewünschten Effekt zu erzielen. Beachten Sie außerdem, dass das Festlegen eines CharacterEscapeHandler
bedeutet, dass es für die gesamte Escape-Behandlung für dieses Marshaller
verantwortlich ist.
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/Ausgabe
<?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>
Bitte beachten Sie: Ich bin der EclipseLink JAXB (MOXy) Lead und Mitglied der Expertengruppe JAXB (JSR-222) .
Wenn Sie MOXy als JAXB-Provider (JSR-222) verwenden, können Sie die Erweiterung @XmlCDATA
für Ihren Anwendungsfall nutzen.
Wurzel
Die Annotation @XmlCDATA
gibt an, dass der Inhalt eines Felds/einer Eigenschaft in einem CDATA-Abschnitt eingeschlossen werden soll. Die Annotation @XmlCDATA
kann in Kombination mit @XmlElement
verwendet werden.
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
Um MOXy als JAXB-Provider zu verwenden, müssen Sie die Datei jaxb.properties
mit dem folgenden Eintrag hinzufügen.
javax.xml.bind.context.factory=org.Eclipse.persistence.jaxb.JAXBContextFactory
Demo
Nachfolgend finden Sie einige Demo-Codes, um zu beweisen, dass alles funktioniert.
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/Ausgabe
Nachfolgend finden Sie die Eingabe und Ausgabe des Demo-Codes.
<?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>
Für mehr Informationen
Tut mir leid, dass ich diese Frage herausgegraben und eine neue Antwort gepostet habe (mein Vertreter ist noch nicht hoch genug, um einen Kommentar abzugeben ...) ... Ich bin auf dieselbe Frage gestoßen und habe die Antwort von Blaise Doughan ausprobiert es deckt nicht alle Fälle ab, entweder mache ich irgendwo etwas falsch.
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);
}
});
Bei meinen Tests entfernt dieser Code alle Escapezeichen, unabhängig davon, ob Sie die @XmlJavaTypeAdapter(AdapterCDATA.class)
-Anmerkung für Ihr Attribut verwenden ...
Um dieses Problem zu beheben, habe ich folgende CharacterEscapeHandler
implementiert:
public class CDataAwareUtfEncodedXmlCharacterEscapeHandler implementiert den CharacterEscapeHandler { private static final char [] cDataPrefix = "<! [CDATA [". toCharArray (); private static final char [] cDataSuffix = "]]>". toCharArray (); public static final CDataAwareUtfEncodedXmlCharacterEscapeHandler-Instanz = new CDataAwareUtfEncodedXmlCharacterEscapeHandler (); private CDataAwareUtfEncodedXmlCharacterEscapeHandler () { } @Override public void escape (char [] ch, int start, int length, boolean isAttVal, Writer out) gibt IOException {.__ aus. 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; brechen; } } if (isCData) { für (int i = cDataSuffix.length - 1, j = Start + Länge - 1; i> = 0; --i, --j) { if (cDataSuffix [i]! = ch [j]) { isCData = false; brechen; } } } } if (isCData) { out.write (ch, start, length); } else { MinimumEscapeHandler.theInstance.escape (ch, start, length, isAttVal, out); } } }
Wenn Ihre Kodierung nicht UTF * ist, sollten Sie nicht MinimumEscapeHandler aufrufen, sondern NioEscapeHandler oder sogar DumbEscapeHandler.
com.Sun.internal funktioniert nicht mit play2, aber das funktioniert
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>
*/
Ich bin auf dieser Seite gelandet und habe versucht, ein ähnliches Problem zu lösen. Ich habe einen anderen Ansatz gefunden, um das Problem zu lösen. Eine Möglichkeit, dieses Problem zu lösen, besteht darin, XML als SAX2-Ereignisse an einen Handler zu senden und dann die Logik in den Handler zu schreiben, um die CDATA-Tags zum XML hinzuzufügen. Dieser Ansatz erfordert nicht, dass eine Anmerkung hinzugefügt wird. Nützlich in Szenarien, in denen Klassen, die gemarshallt werden sollen, aus XSDs generiert werden.
Angenommen, Sie haben ein String-Feld in einer aus XSD generierten Klasse, das gemarshallt werden soll, und das String-Feld enthält Sonderzeichen, die in ein CDATA-Tag eingefügt werden sollen.
@XmlRootElement
public class TestingCDATA{
public String xmlContent;
}
Wir beginnen mit der Suche nach einer geeigneten Klasse, deren Methode in unserem Content-Handler überschrieben werden kann. Eine solche Klasse ist XMLWriter im Paket com.Sun.xml.txw2.output. Es ist in jdk 1.7 und 1.8 verfügbar
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();
}
}
}
Wir überschreiben die Zeichenmethode und verwenden Regex, um zu überprüfen, ob Sonderzeichen enthalten sind. Wenn sie gefunden werden, setzen wir CDATA-Tags um sie herum. In diesem Fall sorgt XMLWriter für das Hinzufügen des CDATA-Tags.
Wir verwenden den folgenden Code für das Marshalling:
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);
}
}
Dies würde das Objekt marshallieren und XML zurückgeben, wenn wir die Anforderung zum Marshallen übergeben, wie unten beschrieben.
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>