web-dev-qa-db-ger.com

JAXB Marshalling Mit CDATA unmarshalling

ich versuche mit JAXB Marshalling zu machen. 

meine Ausgabe ist wie

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <name>&lt;![CDATA[&lt;h1&gt;kshitij&lt;/h1&gt;]]&gt;</name>
    <surname>&lt;h1&gt;solanki&lt;/h1&gt;</surname>
    <id>&lt;h1&gt;1&lt;/h1&gt;</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;
    }
}
23
KSHiTiJ

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>
36
Blaise Doughan

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

11
Blaise Doughan

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.

3
Marc P.

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("&lt;", "<").replaceAll("&gt;", ">");
    }
    catch(JAXBException e){
        throw new RuntimeException(e);
    }
}
1
Bruno Marinho
    @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>&lt;p&gt;Jorge &amp; Mary&lt;/p&gt;</name>
</root>
     */
0
user1346730

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>
0
pkoli